From b738e349be490c24d3604c224f44fc54e16d3d7b Mon Sep 17 00:00:00 2001
From: Victor Chahuneau <vchahune@cs.cmu.edu>
Date: Sat, 23 Jun 2012 11:59:48 -0400
Subject: Support for sparse/dense vectors in the python extension

- SparseVector, DenseVector
- improved Lattice
- Lattice translation
- Hypergraph reweighting, pruning
---
 python/cdec/__init__.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'python/cdec/__init__.py')

diff --git a/python/cdec/__init__.py b/python/cdec/__init__.py
index c821f860..eda81194 100644
--- a/python/cdec/__init__.py
+++ b/python/cdec/__init__.py
@@ -1 +1 @@
-from _cdec import Decoder, Hypergraph, Lattice
+from _cdec import Decoder, Lattice
-- 
cgit v1.2.3


From dc9e428224d95adf63da6460a2031348de295ca1 Mon Sep 17 00:00:00 2001
From: Victor Chahuneau <vchahune@cs.cmu.edu>
Date: Sun, 1 Jul 2012 00:38:30 -0400
Subject: [python] MT evaluation

---
 python/cdec/__init__.py   |    1 +
 python/cdec/score.py      |    1 +
 python/setup.py           |    7 +-
 python/src/_cdec.cpp      | 6817 +++++++++++++++++++++++++++++++++++----------
 python/src/_cdec.pyx      |    4 +-
 python/src/hypergraph.pxi |   15 +-
 python/src/kbest.pxd      |    2 +
 python/src/mteval.pxd     |   47 +
 python/src/mteval.pxi     |  116 +
 python/src/utils.pxd      |   10 +-
 python/src/vectors.pxi    |   34 +-
 python/test.py            |    4 +-
 12 files changed, 5501 insertions(+), 1557 deletions(-)
 create mode 100644 python/cdec/score.py
 create mode 100644 python/src/mteval.pxd
 create mode 100644 python/src/mteval.pxi

(limited to 'python/cdec/__init__.py')

diff --git a/python/cdec/__init__.py b/python/cdec/__init__.py
index eda81194..0d7b8782 100644
--- a/python/cdec/__init__.py
+++ b/python/cdec/__init__.py
@@ -1 +1,2 @@
 from _cdec import Decoder, Lattice
+import score
diff --git a/python/cdec/score.py b/python/cdec/score.py
new file mode 100644
index 00000000..c107446f
--- /dev/null
+++ b/python/cdec/score.py
@@ -0,0 +1 @@
+from _cdec import BLEU, TER
diff --git a/python/setup.py b/python/setup.py
index 49a1ec8f..cc8b289d 100644
--- a/python/setup.py
+++ b/python/setup.py
@@ -3,8 +3,8 @@ from distutils.extension import Extension
 from Cython.Distutils import build_ext
 import os
 
-INC = ['..', 'src/', '../decoder', '../utils']
-LIB = ['../decoder', '../utils', '../mteval', '../klm/lm', '../klm/util']
+INC = ['..', 'src/', '../decoder', '../utils', '../mteval']
+LIB = ['../decoder', '../utils', '../mteval', '../training', '../klm/lm', '../klm/util']
 
 BOOST_ROOT = os.getenv('BOOST_ROOT')
 if BOOST_ROOT:
@@ -18,7 +18,8 @@ ext_modules = [
         include_dirs=INC,
         library_dirs=LIB,
         libraries=['boost_program_options-mt', 'z',
-                   'cdec', 'utils', 'mteval', 'klm', 'klm_util'])
+                   'cdec', 'utils', 'mteval', 'training', 'klm', 'klm_util'],
+        extra_compile_args=['-DHAVE_CONFIG_H']),
 ]
 
 setup(
diff --git a/python/src/_cdec.cpp b/python/src/_cdec.cpp
index 0b9b9911..7d45e27f 100644
--- a/python/src/_cdec.cpp
+++ b/python/src/_cdec.cpp
@@ -1,4 +1,4 @@
-/* Generated by Cython 0.16 on Sat Jun 23 11:57:21 2012 */
+/* Generated by Cython 0.16 on Sun Jul  1 00:36:19 2012 */
 
 #define PY_SSIZE_T_CLEAN
 #include "Python.h"
@@ -279,11 +279,12 @@
 #include "utils/wordid.h"
 #include "utils/small_vector.h"
 #include "utils/sparse_vector.h"
-#include "utils/tdict.cc"
+#include "utils/tdict.h"
 #include "utils/verbose.h"
 #include "utils/fdict.h"
 #include "utils/filelib.h"
 #include "utils/sampler.h"
+#include <boost/shared_ptr.hpp>
 #include "decoder/lattice.h"
 #include "decoder/hg.h"
 #include "decoder/viterbi.h"
@@ -295,6 +296,8 @@
 #include "decoder/decoder.h"
 #include "observer.h"
 #include "decoder/kbest.h"
+#include "mteval/ns.h"
+#include "training/candidate_set.h"
 #ifdef _OPENMP
 #include <omp.h>
 #endif /* _OPENMP */
@@ -381,37 +384,66 @@ static const char *__pyx_f[] = {
   "vectors.pxi",
   "hypergraph.pxi",
   "lattice.pxi",
+  "mteval.pxi",
 };
 
 /*--- Type declarations ---*/
-struct __pyx_obj_5_cdec___pyx_scope_struct_4_sample;
+struct __pyx_obj_5_cdec_Scorer;
+struct __pyx_obj_5_cdec_SufficientStats;
 struct __pyx_obj_5_cdec___pyx_scope_struct_1___iter__;
+struct __pyx_obj_5_cdec___pyx_scope_struct_4_kbest_features;
 struct __pyx_obj_5_cdec___pyx_scope_struct_3_kbest_tree;
 struct __pyx_obj_5_cdec_Decoder;
+struct __pyx_obj_5_cdec___pyx_scope_struct_8_candidate_set;
+struct __pyx_obj_5_cdec_SegmentEvaluator;
 struct __pyx_obj_5_cdec_SparseVector;
 struct __pyx_obj_5_cdec_Hypergraph;
 struct __pyx_obj_5_cdec_Lattice;
-struct __pyx_obj_5_cdec___pyx_scope_struct_5___iter__;
 struct __pyx_obj_5_cdec___pyx_scope_struct____iter__;
 struct __pyx_obj_5_cdec___pyx_scope_struct_2_kbest;
+struct __pyx_obj_5_cdec_Candidate;
+struct __pyx_obj_5_cdec___pyx_scope_struct_5_sample;
 struct __pyx_obj_5_cdec_DenseVector;
+struct __pyx_obj_5_cdec___pyx_scope_struct_6___iter__;
+struct __pyx_obj_5_cdec___pyx_scope_struct_7___iter__;
+struct __pyx_opt_args_5_cdec_as_str;
 
-/* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":56
- *         del derivations
+/* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":3
+ * cimport mteval
+ * 
+ * cdef char* as_str(sentence, error_msg='Cannot convert type %s to str'):             # <<<<<<<<<<<<<<
+ *     cdef bytes ret
+ *     if isinstance(sentence, unicode):
+ */
+struct __pyx_opt_args_5_cdec_as_str {
+  int __pyx_n;
+  PyObject *error_msg;
+};
+
+/* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":87
+ *         del cs
+ * 
+ * cdef class Scorer:             # <<<<<<<<<<<<<<
+ *     cdef string* name
  * 
- *     def sample(self, unsigned n):             # <<<<<<<<<<<<<<
- *         cdef vector[hypergraph.Hypothesis]* hypos = new vector[hypergraph.Hypothesis]()
- *         if self.rng == NULL:
  */
-struct __pyx_obj_5_cdec___pyx_scope_struct_4_sample {
+struct __pyx_obj_5_cdec_Scorer {
   PyObject_HEAD
-  std::vector<HypergraphSampler::Hypothesis> *__pyx_v_hypos;
-  unsigned int __pyx_v_k;
-  unsigned int __pyx_v_n;
-  struct __pyx_obj_5_cdec_Hypergraph *__pyx_v_self;
-  PyObject *__pyx_v_sentence;
-  size_t __pyx_t_0;
-  unsigned int __pyx_t_1;
+  std::string *name;
+};
+
+
+/* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":27
+ *             return fmap
+ * 
+ * cdef class SufficientStats:             # <<<<<<<<<<<<<<
+ *     cdef mteval.SufficientStats* stats
+ *     cdef mteval.EvaluationMetric* metric
+ */
+struct __pyx_obj_5_cdec_SufficientStats {
+  PyObject_HEAD
+  SufficientStats *stats;
+  EvaluationMetric *metric;
 };
 
 
@@ -433,6 +465,26 @@ struct __pyx_obj_5_cdec___pyx_scope_struct_1___iter__ {
 };
 
 
+/* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":56
+ *         del derivations
+ * 
+ *     def kbest_features(self, size):             # <<<<<<<<<<<<<<
+ *         cdef kb.KBestDerivations[FastSparseVector[weight_t], kb.FeatureVectorTraversal]* derivations = new kb.KBestDerivations[FastSparseVector[weight_t], kb.FeatureVectorTraversal](self.hg[0], size)
+ *         cdef kb.KBestDerivations[FastSparseVector[weight_t], kb.FeatureVectorTraversal].Derivation* derivation
+ */
+struct __pyx_obj_5_cdec___pyx_scope_struct_4_kbest_features {
+  PyObject_HEAD
+  KBest::KBestDerivations<FastSparseVector<weight_t>,FeatureVectorTraversal>::Derivation *__pyx_v_derivation;
+  KBest::KBestDerivations<FastSparseVector<weight_t>,FeatureVectorTraversal> *__pyx_v_derivations;
+  struct __pyx_obj_5_cdec_SparseVector *__pyx_v_fmap;
+  unsigned int __pyx_v_k;
+  struct __pyx_obj_5_cdec_Hypergraph *__pyx_v_self;
+  PyObject *__pyx_v_size;
+  unsigned int __pyx_t_0;
+  long __pyx_t_1;
+};
+
+
 /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":44
  *         del derivations
  * 
@@ -454,7 +506,7 @@ struct __pyx_obj_5_cdec___pyx_scope_struct_3_kbest_tree {
 
 
 /* "_cdec.pyx":15
- *     pass
+ * class ParseFailed(Exception): pass
  * 
  * cdef class Decoder:             # <<<<<<<<<<<<<<
  *     cdef decoder.Decoder* dec
@@ -467,6 +519,40 @@ struct __pyx_obj_5_cdec_Decoder {
 };
 
 
+/* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":75
+ *         return sf
+ * 
+ *     def candidate_set(self, Hypergraph hypergraph, unsigned k):             # <<<<<<<<<<<<<<
+ *         cdef mteval.CandidateSet* cs = new mteval.CandidateSet()
+ *         cs.AddKBestCandidates(hypergraph.hg[0], k, self.scorer.get())
+ */
+struct __pyx_obj_5_cdec___pyx_scope_struct_8_candidate_set {
+  PyObject_HEAD
+  struct __pyx_obj_5_cdec_Candidate *__pyx_v_candidate;
+  training::CandidateSet *__pyx_v_cs;
+  struct __pyx_obj_5_cdec_Hypergraph *__pyx_v_hypergraph;
+  unsigned int __pyx_v_i;
+  unsigned int __pyx_v_k;
+  struct __pyx_obj_5_cdec_SegmentEvaluator *__pyx_v_self;
+  unsigned int __pyx_t_0;
+  unsigned int __pyx_t_1;
+};
+
+
+/* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":59
+ *         return result
+ * 
+ * cdef class SegmentEvaluator:             # <<<<<<<<<<<<<<
+ *     cdef shared_ptr[mteval.SegmentEvaluator]* scorer
+ *     cdef mteval.EvaluationMetric* metric
+ */
+struct __pyx_obj_5_cdec_SegmentEvaluator {
+  PyObject_HEAD
+  boost::shared_ptr<SegmentEvaluator> *scorer;
+  EvaluationMetric *metric;
+};
+
+
 /* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":32
  *         return sparse
  * 
@@ -507,22 +593,6 @@ struct __pyx_obj_5_cdec_Lattice {
 };
 
 
-/* "/Users/vchahun/Sandbox/cdec/python/src/lattice.pxi":50
- *         return hypergraph.AsPLF(self.lattice[0], True).c_str()
- * 
- *     def __iter__(self):             # <<<<<<<<<<<<<<
- *         cdef unsigned i
- *         for i in range(len(self)):
- */
-struct __pyx_obj_5_cdec___pyx_scope_struct_5___iter__ {
-  PyObject_HEAD
-  unsigned int __pyx_v_i;
-  struct __pyx_obj_5_cdec_Lattice *__pyx_v_self;
-  Py_ssize_t __pyx_t_0;
-  unsigned int __pyx_t_1;
-};
-
-
 /* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":18
  *         self.vector[0][fid] = value
  * 
@@ -559,6 +629,39 @@ struct __pyx_obj_5_cdec___pyx_scope_struct_2_kbest {
 };
 
 
+/* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":13
+ *     return ret
+ * 
+ * cdef class Candidate:             # <<<<<<<<<<<<<<
+ *     cdef mteval.Candidate* candidate
+ *     cdef public float score
+ */
+struct __pyx_obj_5_cdec_Candidate {
+  PyObject_HEAD
+  const training::Candidate *candidate;
+  float score;
+};
+
+
+/* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":69
+ *         del derivations
+ * 
+ *     def sample(self, unsigned n):             # <<<<<<<<<<<<<<
+ *         cdef vector[hypergraph.Hypothesis]* hypos = new vector[hypergraph.Hypothesis]()
+ *         if self.rng == NULL:
+ */
+struct __pyx_obj_5_cdec___pyx_scope_struct_5_sample {
+  PyObject_HEAD
+  std::vector<HypergraphSampler::Hypothesis> *__pyx_v_hypos;
+  unsigned int __pyx_v_k;
+  unsigned int __pyx_v_n;
+  struct __pyx_obj_5_cdec_Hypergraph *__pyx_v_self;
+  PyObject *__pyx_v_sentence;
+  size_t __pyx_t_0;
+  unsigned int __pyx_t_1;
+};
+
+
 /* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":3
  * from cython.operator cimport preincrement as pinc
  * 
@@ -571,6 +674,39 @@ struct __pyx_obj_5_cdec_DenseVector {
   std::vector<weight_t> *vector;
 };
 
+
+/* "/Users/vchahun/Sandbox/cdec/python/src/lattice.pxi":50
+ *         return hypergraph.AsPLF(self.lattice[0], True).c_str()
+ * 
+ *     def __iter__(self):             # <<<<<<<<<<<<<<
+ *         cdef unsigned i
+ *         for i in range(len(self)):
+ */
+struct __pyx_obj_5_cdec___pyx_scope_struct_6___iter__ {
+  PyObject_HEAD
+  unsigned int __pyx_v_i;
+  struct __pyx_obj_5_cdec_Lattice *__pyx_v_self;
+  Py_ssize_t __pyx_t_0;
+  unsigned int __pyx_t_1;
+};
+
+
+/* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":45
+ *         return self.stats.size()
+ * 
+ *     def __iter__(self):             # <<<<<<<<<<<<<<
+ *         for i in range(len(self)):
+ *             yield self.stats[0][i]
+ */
+struct __pyx_obj_5_cdec___pyx_scope_struct_7___iter__ {
+  PyObject_HEAD
+  PyObject *__pyx_v_i;
+  struct __pyx_obj_5_cdec_SufficientStats *__pyx_v_self;
+  Py_ssize_t __pyx_t_0;
+  PyObject *__pyx_t_1;
+  PyObject *(*__pyx_t_2)(PyObject *);
+};
+
 #ifndef CYTHON_REFNANNY
   #define CYTHON_REFNANNY 0
 #endif
@@ -635,6 +771,8 @@ static void __Pyx_Raise(PyObject *type, PyObject *value, PyObject *tb, PyObject
 static int __Pyx_ArgTypeTest(PyObject *obj, PyTypeObject *type, int none_allowed,
     const char *name, int exact); /*proto*/
 
+static CYTHON_INLINE int __Pyx_TypeTest(PyObject *obj, PyTypeObject *type); /*proto*/
+
 static void __Pyx_RaiseDoubleKeywordsError(const char* func_name, PyObject* kw_name); /*proto*/
 
 static int __Pyx_ParseOptionalKeywords(PyObject *kwds, PyObject **argnames[], \
@@ -736,8 +874,6 @@ static double __Pyx__PyObject_AsDouble(PyObject* obj); /* proto */
 
 static int __Pyx_GetException(PyObject **type, PyObject **value, PyObject **tb); /*proto*/
 
-static CYTHON_INLINE int __Pyx_TypeTest(PyObject *obj, PyTypeObject *type); /*proto*/
-
 static CYTHON_INLINE void __Pyx_ExceptionSave(PyObject **type, PyObject **value, PyObject **tb); /*proto*/
 static void __Pyx_ExceptionReset(PyObject *type, PyObject *value, PyObject *tb); /*proto*/
 
@@ -801,6 +937,9 @@ static __pyx_GeneratorObject *__Pyx_Generator_New(__pyx_generator_body_t body,
                                                   PyObject *closure);
 static int __pyx_Generator_init(void);
 
+static void __Pyx_WriteUnraisable(const char *name, int clineno,
+                                  int lineno, const char *filename); /*proto*/
+
 static int __Pyx_check_binary_version(void);
 
 typedef struct {
@@ -841,18 +980,28 @@ static int __Pyx_InitStrings(__Pyx_StringTabEntry *t); /*proto*/
 
 /* Module declarations from 'kbest' */
 
+/* Module declarations from 'mteval' */
+
 /* Module declarations from '_cdec' */
 static PyTypeObject *__pyx_ptype_5_cdec_DenseVector = 0;
 static PyTypeObject *__pyx_ptype_5_cdec_SparseVector = 0;
 static PyTypeObject *__pyx_ptype_5_cdec_Hypergraph = 0;
 static PyTypeObject *__pyx_ptype_5_cdec_Lattice = 0;
+static PyTypeObject *__pyx_ptype_5_cdec_Candidate = 0;
+static PyTypeObject *__pyx_ptype_5_cdec_SufficientStats = 0;
+static PyTypeObject *__pyx_ptype_5_cdec_SegmentEvaluator = 0;
+static PyTypeObject *__pyx_ptype_5_cdec_Scorer = 0;
 static PyTypeObject *__pyx_ptype_5_cdec_Decoder = 0;
 static PyTypeObject *__pyx_ptype_5_cdec___pyx_scope_struct____iter__ = 0;
 static PyTypeObject *__pyx_ptype_5_cdec___pyx_scope_struct_1___iter__ = 0;
 static PyTypeObject *__pyx_ptype_5_cdec___pyx_scope_struct_2_kbest = 0;
 static PyTypeObject *__pyx_ptype_5_cdec___pyx_scope_struct_3_kbest_tree = 0;
-static PyTypeObject *__pyx_ptype_5_cdec___pyx_scope_struct_4_sample = 0;
-static PyTypeObject *__pyx_ptype_5_cdec___pyx_scope_struct_5___iter__ = 0;
+static PyTypeObject *__pyx_ptype_5_cdec___pyx_scope_struct_4_kbest_features = 0;
+static PyTypeObject *__pyx_ptype_5_cdec___pyx_scope_struct_5_sample = 0;
+static PyTypeObject *__pyx_ptype_5_cdec___pyx_scope_struct_6___iter__ = 0;
+static PyTypeObject *__pyx_ptype_5_cdec___pyx_scope_struct_7___iter__ = 0;
+static PyTypeObject *__pyx_ptype_5_cdec___pyx_scope_struct_8_candidate_set = 0;
+static char *__pyx_f_5_cdec_as_str(PyObject *, struct __pyx_opt_args_5_cdec_as_str *__pyx_optional_args); /*proto*/
 #define __Pyx_MODULE_NAME "_cdec"
 int __pyx_module_is_main__cdec = 0;
 
@@ -860,11 +1009,10 @@ int __pyx_module_is_main__cdec = 0;
 static PyObject *__pyx_builtin_Exception;
 static PyObject *__pyx_builtin_KeyError;
 static PyObject *__pyx_builtin_range;
-static PyObject *__pyx_builtin_ValueError;
+static PyObject *__pyx_builtin_TypeError;
 static PyObject *__pyx_builtin_NotImplemented;
 static PyObject *__pyx_builtin_eval;
 static PyObject *__pyx_builtin_enumerate;
-static PyObject *__pyx_builtin_TypeError;
 static PyObject *__pyx_builtin_IndexError;
 static PyObject *__pyx_builtin_open;
 static PyObject *__pyx_pf_5_cdec_11DenseVector___getitem__(struct __pyx_obj_5_cdec_DenseVector *__pyx_v_self, char *__pyx_v_fname); /* proto */
@@ -877,7 +1025,7 @@ static int __pyx_pf_5_cdec_12SparseVector_2__setitem__(struct __pyx_obj_5_cdec_S
 static PyObject *__pyx_pf_5_cdec_12SparseVector_4__iter__(struct __pyx_obj_5_cdec_SparseVector *__pyx_v_self); /* proto */
 static PyObject *__pyx_pf_5_cdec_12SparseVector_7dot(struct __pyx_obj_5_cdec_SparseVector *__pyx_v_self, PyObject *__pyx_v_other); /* proto */
 static PyObject *__pyx_pf_5_cdec_12SparseVector_9todense(struct __pyx_obj_5_cdec_SparseVector *__pyx_v_self); /* proto */
-static PyObject *__pyx_pf_5_cdec_12SparseVector_11__richcmp__(struct __pyx_obj_5_cdec_SparseVector *__pyx_v_self, struct __pyx_obj_5_cdec_SparseVector *__pyx_v_other, int __pyx_v_op); /* proto */
+static PyObject *__pyx_pf_5_cdec_12SparseVector_11__richcmp__(struct __pyx_obj_5_cdec_SparseVector *__pyx_v_x, struct __pyx_obj_5_cdec_SparseVector *__pyx_v_y, int __pyx_v_op); /* proto */
 static Py_ssize_t __pyx_pf_5_cdec_12SparseVector_13__len__(struct __pyx_obj_5_cdec_SparseVector *__pyx_v_self); /* proto */
 static int __pyx_pf_5_cdec_12SparseVector_15__contains__(struct __pyx_obj_5_cdec_SparseVector *__pyx_v_self, char *__pyx_v_fname); /* proto */
 static PyObject *__pyx_pf_5_cdec_12SparseVector_17__iadd__(struct __pyx_obj_5_cdec_SparseVector *__pyx_v_self, struct __pyx_obj_5_cdec_SparseVector *__pyx_v_other); /* proto */
@@ -886,8 +1034,12 @@ static PyObject *__pyx_pf_5_cdec_12SparseVector_21__imul__(struct __pyx_obj_5_cd
 #if PY_MAJOR_VERSION < 3
 static PyObject *__pyx_pf_5_cdec_12SparseVector_23__idiv__(struct __pyx_obj_5_cdec_SparseVector *__pyx_v_self, float __pyx_v_scalar); /* proto */
 #endif
-static PyObject *__pyx_pf_5_cdec_12SparseVector_25__add__(struct __pyx_obj_5_cdec_SparseVector *__pyx_v_self, struct __pyx_obj_5_cdec_SparseVector *__pyx_v_other); /* proto */
-static PyObject *__pyx_pf_5_cdec_12SparseVector_27__sub__(struct __pyx_obj_5_cdec_SparseVector *__pyx_v_self, struct __pyx_obj_5_cdec_SparseVector *__pyx_v_other); /* proto */
+static PyObject *__pyx_pf_5_cdec_12SparseVector_25__add__(struct __pyx_obj_5_cdec_SparseVector *__pyx_v_x, struct __pyx_obj_5_cdec_SparseVector *__pyx_v_y); /* proto */
+static PyObject *__pyx_pf_5_cdec_12SparseVector_27__sub__(struct __pyx_obj_5_cdec_SparseVector *__pyx_v_x, struct __pyx_obj_5_cdec_SparseVector *__pyx_v_y); /* proto */
+static PyObject *__pyx_pf_5_cdec_12SparseVector_29__mul__(PyObject *__pyx_v_x, PyObject *__pyx_v_y); /* proto */
+#if PY_MAJOR_VERSION < 3
+static PyObject *__pyx_pf_5_cdec_12SparseVector_31__div__(PyObject *__pyx_v_x, PyObject *__pyx_v_y); /* proto */
+#endif
 static void __pyx_pf_5_cdec_10Hypergraph___dealloc__(struct __pyx_obj_5_cdec_Hypergraph *__pyx_v_self); /* proto */
 static PyObject *__pyx_pf_5_cdec_10Hypergraph_2viterbi(struct __pyx_obj_5_cdec_Hypergraph *__pyx_v_self); /* proto */
 static PyObject *__pyx_pf_5_cdec_10Hypergraph_4viterbi_tree(struct __pyx_obj_5_cdec_Hypergraph *__pyx_v_self); /* proto */
@@ -895,11 +1047,12 @@ static PyObject *__pyx_pf_5_cdec_10Hypergraph_6viterbi_source_tree(struct __pyx_
 static PyObject *__pyx_pf_5_cdec_10Hypergraph_8viterbi_features(struct __pyx_obj_5_cdec_Hypergraph *__pyx_v_self); /* proto */
 static PyObject *__pyx_pf_5_cdec_10Hypergraph_10kbest(struct __pyx_obj_5_cdec_Hypergraph *__pyx_v_self, PyObject *__pyx_v_size); /* proto */
 static PyObject *__pyx_pf_5_cdec_10Hypergraph_13kbest_tree(struct __pyx_obj_5_cdec_Hypergraph *__pyx_v_self, PyObject *__pyx_v_size); /* proto */
-static PyObject *__pyx_pf_5_cdec_10Hypergraph_16sample(struct __pyx_obj_5_cdec_Hypergraph *__pyx_v_self, unsigned int __pyx_v_n); /* proto */
-static PyObject *__pyx_pf_5_cdec_10Hypergraph_19intersect(struct __pyx_obj_5_cdec_Hypergraph *__pyx_v_self, struct __pyx_obj_5_cdec_Lattice *__pyx_v_lat); /* proto */
-static PyObject *__pyx_pf_5_cdec_10Hypergraph_21prune(struct __pyx_obj_5_cdec_Hypergraph *__pyx_v_self, PyObject *__pyx_v_beam_alpha, PyObject *__pyx_v_density, PyObject *__pyx_v_kwargs); /* proto */
-static PyObject *__pyx_pf_5_cdec_10Hypergraph_23lattice(struct __pyx_obj_5_cdec_Hypergraph *__pyx_v_self); /* proto */
-static PyObject *__pyx_pf_5_cdec_10Hypergraph_25reweight(struct __pyx_obj_5_cdec_Hypergraph *__pyx_v_self, PyObject *__pyx_v_weights); /* proto */
+static PyObject *__pyx_pf_5_cdec_10Hypergraph_16kbest_features(struct __pyx_obj_5_cdec_Hypergraph *__pyx_v_self, PyObject *__pyx_v_size); /* proto */
+static PyObject *__pyx_pf_5_cdec_10Hypergraph_19sample(struct __pyx_obj_5_cdec_Hypergraph *__pyx_v_self, unsigned int __pyx_v_n); /* proto */
+static PyObject *__pyx_pf_5_cdec_10Hypergraph_22intersect(struct __pyx_obj_5_cdec_Hypergraph *__pyx_v_self, struct __pyx_obj_5_cdec_Lattice *__pyx_v_lat); /* proto */
+static PyObject *__pyx_pf_5_cdec_10Hypergraph_24prune(struct __pyx_obj_5_cdec_Hypergraph *__pyx_v_self, PyObject *__pyx_v_beam_alpha, PyObject *__pyx_v_density, PyObject *__pyx_v_kwargs); /* proto */
+static PyObject *__pyx_pf_5_cdec_10Hypergraph_26lattice(struct __pyx_obj_5_cdec_Hypergraph *__pyx_v_self); /* proto */
+static PyObject *__pyx_pf_5_cdec_10Hypergraph_28reweight(struct __pyx_obj_5_cdec_Hypergraph *__pyx_v_self, PyObject *__pyx_v_weights); /* proto */
 static int __pyx_pf_5_cdec_7Lattice___init__(struct __pyx_obj_5_cdec_Lattice *__pyx_v_self, PyObject *__pyx_v_inp); /* proto */
 static PyObject *__pyx_pf_5_cdec_7Lattice_2__getitem__(struct __pyx_obj_5_cdec_Lattice *__pyx_v_self, int __pyx_v_index); /* proto */
 static int __pyx_pf_5_cdec_7Lattice_4__setitem__(struct __pyx_obj_5_cdec_Lattice *__pyx_v_self, int __pyx_v_index, PyObject *__pyx_v_arcs); /* proto */
@@ -907,6 +1060,23 @@ static Py_ssize_t __pyx_pf_5_cdec_7Lattice_6__len__(struct __pyx_obj_5_cdec_Latt
 static PyObject *__pyx_pf_5_cdec_7Lattice_8__str__(struct __pyx_obj_5_cdec_Lattice *__pyx_v_self); /* proto */
 static PyObject *__pyx_pf_5_cdec_7Lattice_10__iter__(struct __pyx_obj_5_cdec_Lattice *__pyx_v_self); /* proto */
 static void __pyx_pf_5_cdec_7Lattice_13__dealloc__(CYTHON_UNUSED struct __pyx_obj_5_cdec_Lattice *__pyx_v_self); /* proto */
+static PyObject *__pyx_pf_5_cdec_9Candidate_5words___get__(struct __pyx_obj_5_cdec_Candidate *__pyx_v_self); /* proto */
+static PyObject *__pyx_pf_5_cdec_9Candidate_4fmap___get__(struct __pyx_obj_5_cdec_Candidate *__pyx_v_self); /* proto */
+static PyObject *__pyx_pf_5_cdec_9Candidate_5score___get__(struct __pyx_obj_5_cdec_Candidate *__pyx_v_self); /* proto */
+static int __pyx_pf_5_cdec_9Candidate_5score_2__set__(struct __pyx_obj_5_cdec_Candidate *__pyx_v_self, PyObject *__pyx_v_value); /* proto */
+static void __pyx_pf_5_cdec_15SufficientStats___dealloc__(CYTHON_UNUSED struct __pyx_obj_5_cdec_SufficientStats *__pyx_v_self); /* proto */
+static PyObject *__pyx_pf_5_cdec_15SufficientStats_5score___get__(struct __pyx_obj_5_cdec_SufficientStats *__pyx_v_self); /* proto */
+static PyObject *__pyx_pf_5_cdec_15SufficientStats_6detail___get__(struct __pyx_obj_5_cdec_SufficientStats *__pyx_v_self); /* proto */
+static Py_ssize_t __pyx_pf_5_cdec_15SufficientStats_2__len__(struct __pyx_obj_5_cdec_SufficientStats *__pyx_v_self); /* proto */
+static PyObject *__pyx_pf_5_cdec_15SufficientStats_4__iter__(struct __pyx_obj_5_cdec_SufficientStats *__pyx_v_self); /* proto */
+static PyObject *__pyx_pf_5_cdec_15SufficientStats_7__iadd__(struct __pyx_obj_5_cdec_SufficientStats *__pyx_v_self, struct __pyx_obj_5_cdec_SufficientStats *__pyx_v_other); /* proto */
+static PyObject *__pyx_pf_5_cdec_15SufficientStats_9__add__(struct __pyx_obj_5_cdec_SufficientStats *__pyx_v_x, struct __pyx_obj_5_cdec_SufficientStats *__pyx_v_y); /* proto */
+static void __pyx_pf_5_cdec_16SegmentEvaluator___dealloc__(CYTHON_UNUSED struct __pyx_obj_5_cdec_SegmentEvaluator *__pyx_v_self); /* proto */
+static PyObject *__pyx_pf_5_cdec_16SegmentEvaluator_2evaluate(struct __pyx_obj_5_cdec_SegmentEvaluator *__pyx_v_self, PyObject *__pyx_v_sentence); /* proto */
+static PyObject *__pyx_pf_5_cdec_16SegmentEvaluator_4candidate_set(struct __pyx_obj_5_cdec_SegmentEvaluator *__pyx_v_self, struct __pyx_obj_5_cdec_Hypergraph *__pyx_v_hypergraph, unsigned int __pyx_v_k); /* proto */
+static int __pyx_pf_5_cdec_6Scorer___cinit__(struct __pyx_obj_5_cdec_Scorer *__pyx_v_self, char *__pyx_v_name); /* proto */
+static PyObject *__pyx_pf_5_cdec_6Scorer_2__call__(struct __pyx_obj_5_cdec_Scorer *__pyx_v_self, PyObject *__pyx_v_refs); /* proto */
+static PyObject *__pyx_pf_5_cdec_6Scorer_4__str__(struct __pyx_obj_5_cdec_Scorer *__pyx_v_self); /* proto */
 static int __pyx_pf_5_cdec_7Decoder___cinit__(struct __pyx_obj_5_cdec_Decoder *__pyx_v_self, char *__pyx_v_config); /* proto */
 static void __pyx_pf_5_cdec_7Decoder_2__dealloc__(CYTHON_UNUSED struct __pyx_obj_5_cdec_Decoder *__pyx_v_self); /* proto */
 static PyObject *__pyx_pf_5_cdec_7Decoder_4read_weights(struct __pyx_obj_5_cdec_Decoder *__pyx_v_self, PyObject *__pyx_v_cfg); /* proto */
@@ -920,12 +1090,18 @@ static char __pyx_k_10[] = "csplit_preserve_full_word";
 static char __pyx_k_11[] = "cannot reweight hypergraph with %s";
 static char __pyx_k_13[] = "Cannot create lattice from %s";
 static char __pyx_k_14[] = "lattice index out of range";
-static char __pyx_k_21[] = "Cannot translate input type %s";
+static char __pyx_k_19[] = "Cannot convert type %s to str";
+static char __pyx_k_23[] = "Cannot translate input type %s";
+static char __pyx_k__k[] = "k";
+static char __pyx_k__TER[] = "TER";
 static char __pyx_k__dot[] = "dot";
 static char __pyx_k__inp[] = "inp";
 static char __pyx_k__plf[] = "plf";
+static char __pyx_k__BLEU[] = "BLEU";
 static char __pyx_k__eval[] = "eval";
+static char __pyx_k__name[] = "name";
 static char __pyx_k__open[] = "open";
+static char __pyx_k__refs[] = "refs";
 static char __pyx_k__self[] = "self";
 static char __pyx_k__utf8[] = "utf8";
 static char __pyx_k___cdec[] = "_cdec";
@@ -937,18 +1113,20 @@ static char __pyx_k__decode[] = "decode";
 static char __pyx_k__encode[] = "encode";
 static char __pyx_k__density[] = "density";
 static char __pyx_k__grammar[] = "grammar";
+static char __pyx_k__IBM_BLEU[] = "IBM_BLEU";
 static char __pyx_k__KeyError[] = "KeyError";
 static char __pyx_k____exit__[] = "__exit__";
 static char __pyx_k____main__[] = "__main__";
 static char __pyx_k____test__[] = "__test__";
+static char __pyx_k__encoding[] = "encoding";
 static char __pyx_k__sentence[] = "sentence";
 static char __pyx_k__Exception[] = "Exception";
 static char __pyx_k__TypeError[] = "TypeError";
 static char __pyx_k____enter__[] = "__enter__";
 static char __pyx_k__enumerate[] = "enumerate";
 static char __pyx_k__IndexError[] = "IndexError";
-static char __pyx_k__ValueError[] = "ValueError";
 static char __pyx_k__beam_alpha[] = "beam_alpha";
+static char __pyx_k__hypergraph[] = "hypergraph";
 static char __pyx_k__ParseFailed[] = "ParseFailed";
 static char __pyx_k__NotImplemented[] = "NotImplemented";
 static PyObject *__pyx_kp_s_1;
@@ -956,15 +1134,18 @@ static PyObject *__pyx_n_s_10;
 static PyObject *__pyx_kp_s_11;
 static PyObject *__pyx_kp_s_13;
 static PyObject *__pyx_kp_s_14;
+static PyObject *__pyx_kp_s_19;
 static PyObject *__pyx_kp_s_2;
-static PyObject *__pyx_kp_s_21;
+static PyObject *__pyx_kp_s_23;
+static PyObject *__pyx_n_s__BLEU;
 static PyObject *__pyx_n_s__Exception;
+static PyObject *__pyx_n_s__IBM_BLEU;
 static PyObject *__pyx_n_s__IndexError;
 static PyObject *__pyx_n_s__KeyError;
 static PyObject *__pyx_n_s__NotImplemented;
 static PyObject *__pyx_n_s__ParseFailed;
+static PyObject *__pyx_n_s__TER;
 static PyObject *__pyx_n_s__TypeError;
-static PyObject *__pyx_n_s__ValueError;
 static PyObject *__pyx_n_s____enter__;
 static PyObject *__pyx_n_s____exit__;
 static PyObject *__pyx_n_s____main__;
@@ -976,13 +1157,18 @@ static PyObject *__pyx_n_s__decode;
 static PyObject *__pyx_n_s__density;
 static PyObject *__pyx_n_s__dot;
 static PyObject *__pyx_n_s__encode;
+static PyObject *__pyx_n_s__encoding;
 static PyObject *__pyx_n_s__enumerate;
 static PyObject *__pyx_n_s__eval;
 static PyObject *__pyx_n_s__grammar;
+static PyObject *__pyx_n_s__hypergraph;
 static PyObject *__pyx_n_s__inp;
+static PyObject *__pyx_n_s__k;
+static PyObject *__pyx_n_s__name;
 static PyObject *__pyx_n_s__open;
 static PyObject *__pyx_n_s__plf;
 static PyObject *__pyx_n_s__range;
+static PyObject *__pyx_n_s__refs;
 static PyObject *__pyx_n_s__self;
 static PyObject *__pyx_n_s__sentence;
 static PyObject *__pyx_n_s__split;
@@ -1002,8 +1188,11 @@ static PyObject *__pyx_k_tuple_15;
 static PyObject *__pyx_k_tuple_16;
 static PyObject *__pyx_k_tuple_17;
 static PyObject *__pyx_k_tuple_18;
-static PyObject *__pyx_k_tuple_19;
 static PyObject *__pyx_k_tuple_20;
+static PyObject *__pyx_k_tuple_21;
+static PyObject *__pyx_k_tuple_22;
+static PyObject *__pyx_k_tuple_24;
+static PyObject *__pyx_k_tuple_25;
 
 /* Python wrapper */
 static PyObject *__pyx_pw_5_cdec_11DenseVector_1__getitem__(PyObject *__pyx_v_self, PyObject *__pyx_arg_fname); /*proto*/
@@ -1857,7 +2046,7 @@ static PyObject *__pyx_pf_5_cdec_12SparseVector_7dot(struct __pyx_obj_5_cdec_Spa
  *             return self.vector.dot((<DenseVector> other).vector[0])
  *         elif isinstance(other, SparseVector):             # <<<<<<<<<<<<<<
  *             return self.vector.dot((<SparseVector> other).vector[0])
- *         raise ValueError('cannot take the dot product of %s and SparseVector' % type(other))
+ *         raise TypeError('cannot take the dot product of %s and SparseVector' % type(other))
  */
   __pyx_t_1 = ((PyObject *)((PyObject*)__pyx_ptype_5_cdec_SparseVector));
   __Pyx_INCREF(__pyx_t_1);
@@ -1869,7 +2058,7 @@ static PyObject *__pyx_pf_5_cdec_12SparseVector_7dot(struct __pyx_obj_5_cdec_Spa
  *             return self.vector.dot((<DenseVector> other).vector[0])
  *         elif isinstance(other, SparseVector):
  *             return self.vector.dot((<SparseVector> other).vector[0])             # <<<<<<<<<<<<<<
- *         raise ValueError('cannot take the dot product of %s and SparseVector' % type(other))
+ *         raise TypeError('cannot take the dot product of %s and SparseVector' % type(other))
  * 
  */
     __Pyx_XDECREF(__pyx_r);
@@ -1885,7 +2074,7 @@ static PyObject *__pyx_pf_5_cdec_12SparseVector_7dot(struct __pyx_obj_5_cdec_Spa
   /* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":56
  *         elif isinstance(other, SparseVector):
  *             return self.vector.dot((<SparseVector> other).vector[0])
- *         raise ValueError('cannot take the dot product of %s and SparseVector' % type(other))             # <<<<<<<<<<<<<<
+ *         raise TypeError('cannot take the dot product of %s and SparseVector' % type(other))             # <<<<<<<<<<<<<<
  * 
  *     def todense(self):
  */
@@ -1896,7 +2085,7 @@ static PyObject *__pyx_pf_5_cdec_12SparseVector_7dot(struct __pyx_obj_5_cdec_Spa
   PyTuple_SET_ITEM(__pyx_t_3, 0, ((PyObject *)__pyx_t_1));
   __Pyx_GIVEREF(((PyObject *)__pyx_t_1));
   __pyx_t_1 = 0;
-  __pyx_t_1 = PyObject_Call(__pyx_builtin_ValueError, ((PyObject *)__pyx_t_3), NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 56; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_1 = PyObject_Call(__pyx_builtin_TypeError, ((PyObject *)__pyx_t_3), NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 56; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __Pyx_GOTREF(__pyx_t_1);
   __Pyx_DECREF(((PyObject *)__pyx_t_3)); __pyx_t_3 = 0;
   __Pyx_Raise(__pyx_t_1, 0, 0, 0);
@@ -1928,7 +2117,7 @@ static PyObject *__pyx_pw_5_cdec_12SparseVector_10todense(PyObject *__pyx_v_self
 }
 
 /* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":58
- *         raise ValueError('cannot take the dot product of %s and SparseVector' % type(other))
+ *         raise TypeError('cannot take the dot product of %s and SparseVector' % type(other))
  * 
  *     def todense(self):             # <<<<<<<<<<<<<<
  *         cdef DenseVector dense = DenseVector()
@@ -1980,7 +2169,7 @@ static PyObject *__pyx_pf_5_cdec_12SparseVector_9todense(struct __pyx_obj_5_cdec
  *         self.vector.init_vector(dense.vector)
  *         return dense             # <<<<<<<<<<<<<<
  * 
- *     def __richcmp__(SparseVector self, SparseVector other, int op):
+ *     def __richcmp__(SparseVector x, SparseVector y, int op):
  */
   __Pyx_XDECREF(__pyx_r);
   __Pyx_INCREF(((PyObject *)__pyx_v_dense));
@@ -2001,14 +2190,14 @@ static PyObject *__pyx_pf_5_cdec_12SparseVector_9todense(struct __pyx_obj_5_cdec
 }
 
 /* Python wrapper */
-static PyObject *__pyx_pw_5_cdec_12SparseVector_12__richcmp__(PyObject *__pyx_v_self, PyObject *__pyx_v_other, int __pyx_v_op); /*proto*/
-static PyObject *__pyx_pw_5_cdec_12SparseVector_12__richcmp__(PyObject *__pyx_v_self, PyObject *__pyx_v_other, int __pyx_v_op) {
+static PyObject *__pyx_pw_5_cdec_12SparseVector_12__richcmp__(PyObject *__pyx_v_x, PyObject *__pyx_v_y, int __pyx_v_op); /*proto*/
+static PyObject *__pyx_pw_5_cdec_12SparseVector_12__richcmp__(PyObject *__pyx_v_x, PyObject *__pyx_v_y, int __pyx_v_op) {
   PyObject *__pyx_r = 0;
   __Pyx_RefNannyDeclarations
   __Pyx_RefNannySetupContext("__richcmp__ (wrapper)", 0);
-  if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_self), __pyx_ptype_5_cdec_SparseVector, 1, "self", 0))) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 64; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_other), __pyx_ptype_5_cdec_SparseVector, 1, "other", 0))) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 64; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __pyx_r = __pyx_pf_5_cdec_12SparseVector_11__richcmp__(((struct __pyx_obj_5_cdec_SparseVector *)__pyx_v_self), ((struct __pyx_obj_5_cdec_SparseVector *)__pyx_v_other), ((int)__pyx_v_op));
+  if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_x), __pyx_ptype_5_cdec_SparseVector, 1, "x", 0))) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 64; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_y), __pyx_ptype_5_cdec_SparseVector, 1, "y", 0))) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 64; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_r = __pyx_pf_5_cdec_12SparseVector_11__richcmp__(((struct __pyx_obj_5_cdec_SparseVector *)__pyx_v_x), ((struct __pyx_obj_5_cdec_SparseVector *)__pyx_v_y), ((int)__pyx_v_op));
   goto __pyx_L0;
   __pyx_L1_error:;
   __pyx_r = NULL;
@@ -2020,12 +2209,12 @@ static PyObject *__pyx_pw_5_cdec_12SparseVector_12__richcmp__(PyObject *__pyx_v_
 /* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":64
  *         return dense
  * 
- *     def __richcmp__(SparseVector self, SparseVector other, int op):             # <<<<<<<<<<<<<<
+ *     def __richcmp__(SparseVector x, SparseVector y, int op):             # <<<<<<<<<<<<<<
  *         if op == 2: # ==
- *             return self.vector[0] == other.vector[0]
+ *             return x.vector[0] == y.vector[0]
  */
 
-static PyObject *__pyx_pf_5_cdec_12SparseVector_11__richcmp__(struct __pyx_obj_5_cdec_SparseVector *__pyx_v_self, struct __pyx_obj_5_cdec_SparseVector *__pyx_v_other, int __pyx_v_op) {
+static PyObject *__pyx_pf_5_cdec_12SparseVector_11__richcmp__(struct __pyx_obj_5_cdec_SparseVector *__pyx_v_x, struct __pyx_obj_5_cdec_SparseVector *__pyx_v_y, int __pyx_v_op) {
   PyObject *__pyx_r = NULL;
   __Pyx_RefNannyDeclarations
   PyObject *__pyx_t_1 = NULL;
@@ -2037,31 +2226,31 @@ static PyObject *__pyx_pf_5_cdec_12SparseVector_11__richcmp__(struct __pyx_obj_5
 
   /* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":67
  *         if op == 2: # ==
- *             return self.vector[0] == other.vector[0]
+ *             return x.vector[0] == y.vector[0]
  *         elif op == 3: # !=             # <<<<<<<<<<<<<<
- *             return not (self == other)
+ *             return not (x == y)
  *         raise NotImplemented('comparison not implemented for SparseVector')
  */
   switch (__pyx_v_op) {
 
     /* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":65
  * 
- *     def __richcmp__(SparseVector self, SparseVector other, int op):
+ *     def __richcmp__(SparseVector x, SparseVector y, int op):
  *         if op == 2: # ==             # <<<<<<<<<<<<<<
- *             return self.vector[0] == other.vector[0]
+ *             return x.vector[0] == y.vector[0]
  *         elif op == 3: # !=
  */
     case 2:
 
     /* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":66
- *     def __richcmp__(SparseVector self, SparseVector other, int op):
+ *     def __richcmp__(SparseVector x, SparseVector y, int op):
  *         if op == 2: # ==
- *             return self.vector[0] == other.vector[0]             # <<<<<<<<<<<<<<
+ *             return x.vector[0] == y.vector[0]             # <<<<<<<<<<<<<<
  *         elif op == 3: # !=
- *             return not (self == other)
+ *             return not (x == y)
  */
     __Pyx_XDECREF(__pyx_r);
-    __pyx_t_1 = __Pyx_PyBool_FromLong(((__pyx_v_self->vector[0]) == (__pyx_v_other->vector[0]))); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 66; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_t_1 = __Pyx_PyBool_FromLong(((__pyx_v_x->vector[0]) == (__pyx_v_y->vector[0]))); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 66; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
     __Pyx_GOTREF(__pyx_t_1);
     __pyx_r = __pyx_t_1;
     __pyx_t_1 = 0;
@@ -2070,22 +2259,22 @@ static PyObject *__pyx_pf_5_cdec_12SparseVector_11__richcmp__(struct __pyx_obj_5
 
     /* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":67
  *         if op == 2: # ==
- *             return self.vector[0] == other.vector[0]
+ *             return x.vector[0] == y.vector[0]
  *         elif op == 3: # !=             # <<<<<<<<<<<<<<
- *             return not (self == other)
+ *             return not (x == y)
  *         raise NotImplemented('comparison not implemented for SparseVector')
  */
     case 3:
 
     /* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":68
- *             return self.vector[0] == other.vector[0]
+ *             return x.vector[0] == y.vector[0]
  *         elif op == 3: # !=
- *             return not (self == other)             # <<<<<<<<<<<<<<
+ *             return not (x == y)             # <<<<<<<<<<<<<<
  *         raise NotImplemented('comparison not implemented for SparseVector')
  * 
  */
     __Pyx_XDECREF(__pyx_r);
-    __pyx_t_1 = PyObject_RichCompare(((PyObject *)__pyx_v_self), ((PyObject *)__pyx_v_other), Py_EQ); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 68; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_t_1 = PyObject_RichCompare(((PyObject *)__pyx_v_x), ((PyObject *)__pyx_v_y), Py_EQ); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 68; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
     __Pyx_GOTREF(__pyx_t_1);
     __pyx_t_2 = __Pyx_PyObject_IsTrue(__pyx_t_1); if (unlikely(__pyx_t_2 < 0)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 68; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
     __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
@@ -2099,7 +2288,7 @@ static PyObject *__pyx_pf_5_cdec_12SparseVector_11__richcmp__(struct __pyx_obj_5
 
   /* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":69
  *         elif op == 3: # !=
- *             return not (self == other)
+ *             return not (x == y)
  *         raise NotImplemented('comparison not implemented for SparseVector')             # <<<<<<<<<<<<<<
  * 
  *     def __len__(self):
@@ -2439,7 +2628,7 @@ static PyObject *__pyx_pf_5_cdec_12SparseVector_23__idiv__(struct __pyx_obj_5_cd
  *         self.vector[0] /= scalar
  *         return self             # <<<<<<<<<<<<<<
  * 
- *     def __add__(SparseVector self, SparseVector other):
+ *     def __add__(SparseVector x, SparseVector y):
  */
   __Pyx_XDECREF(__pyx_r);
   __Pyx_INCREF(((PyObject *)__pyx_v_self));
@@ -2455,14 +2644,14 @@ static PyObject *__pyx_pf_5_cdec_12SparseVector_23__idiv__(struct __pyx_obj_5_cd
 #endif /*!(#if PY_MAJOR_VERSION < 3)*/
 
 /* Python wrapper */
-static PyObject *__pyx_pw_5_cdec_12SparseVector_26__add__(PyObject *__pyx_v_self, PyObject *__pyx_v_other); /*proto*/
-static PyObject *__pyx_pw_5_cdec_12SparseVector_26__add__(PyObject *__pyx_v_self, PyObject *__pyx_v_other) {
+static PyObject *__pyx_pw_5_cdec_12SparseVector_26__add__(PyObject *__pyx_v_x, PyObject *__pyx_v_y); /*proto*/
+static PyObject *__pyx_pw_5_cdec_12SparseVector_26__add__(PyObject *__pyx_v_x, PyObject *__pyx_v_y) {
   PyObject *__pyx_r = 0;
   __Pyx_RefNannyDeclarations
   __Pyx_RefNannySetupContext("__add__ (wrapper)", 0);
-  if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_self), __pyx_ptype_5_cdec_SparseVector, 1, "self", 0))) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 93; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_other), __pyx_ptype_5_cdec_SparseVector, 1, "other", 0))) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 93; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __pyx_r = __pyx_pf_5_cdec_12SparseVector_25__add__(((struct __pyx_obj_5_cdec_SparseVector *)__pyx_v_self), ((struct __pyx_obj_5_cdec_SparseVector *)__pyx_v_other));
+  if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_x), __pyx_ptype_5_cdec_SparseVector, 1, "x", 0))) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 93; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_y), __pyx_ptype_5_cdec_SparseVector, 1, "y", 0))) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 93; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_r = __pyx_pf_5_cdec_12SparseVector_25__add__(((struct __pyx_obj_5_cdec_SparseVector *)__pyx_v_x), ((struct __pyx_obj_5_cdec_SparseVector *)__pyx_v_y));
   goto __pyx_L0;
   __pyx_L1_error:;
   __pyx_r = NULL;
@@ -2474,12 +2663,12 @@ static PyObject *__pyx_pw_5_cdec_12SparseVector_26__add__(PyObject *__pyx_v_self
 /* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":93
  *         return self
  * 
- *     def __add__(SparseVector self, SparseVector other):             # <<<<<<<<<<<<<<
+ *     def __add__(SparseVector x, SparseVector y):             # <<<<<<<<<<<<<<
  *         cdef SparseVector result = SparseVector()
- *         result.vector = new FastSparseVector[weight_t](self.vector[0] + other.vector[0])
+ *         result.vector = new FastSparseVector[weight_t](x.vector[0] + y.vector[0])
  */
 
-static PyObject *__pyx_pf_5_cdec_12SparseVector_25__add__(struct __pyx_obj_5_cdec_SparseVector *__pyx_v_self, struct __pyx_obj_5_cdec_SparseVector *__pyx_v_other) {
+static PyObject *__pyx_pf_5_cdec_12SparseVector_25__add__(struct __pyx_obj_5_cdec_SparseVector *__pyx_v_x, struct __pyx_obj_5_cdec_SparseVector *__pyx_v_y) {
   struct __pyx_obj_5_cdec_SparseVector *__pyx_v_result = 0;
   PyObject *__pyx_r = NULL;
   __Pyx_RefNannyDeclarations
@@ -2491,9 +2680,9 @@ static PyObject *__pyx_pf_5_cdec_12SparseVector_25__add__(struct __pyx_obj_5_cde
 
   /* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":94
  * 
- *     def __add__(SparseVector self, SparseVector other):
+ *     def __add__(SparseVector x, SparseVector y):
  *         cdef SparseVector result = SparseVector()             # <<<<<<<<<<<<<<
- *         result.vector = new FastSparseVector[weight_t](self.vector[0] + other.vector[0])
+ *         result.vector = new FastSparseVector[weight_t](x.vector[0] + y.vector[0])
  *         return result
  */
   __pyx_t_1 = PyObject_Call(((PyObject *)((PyObject*)__pyx_ptype_5_cdec_SparseVector)), ((PyObject *)__pyx_empty_tuple), NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 94; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
@@ -2502,20 +2691,20 @@ static PyObject *__pyx_pf_5_cdec_12SparseVector_25__add__(struct __pyx_obj_5_cde
   __pyx_t_1 = 0;
 
   /* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":95
- *     def __add__(SparseVector self, SparseVector other):
+ *     def __add__(SparseVector x, SparseVector y):
  *         cdef SparseVector result = SparseVector()
- *         result.vector = new FastSparseVector[weight_t](self.vector[0] + other.vector[0])             # <<<<<<<<<<<<<<
+ *         result.vector = new FastSparseVector[weight_t](x.vector[0] + y.vector[0])             # <<<<<<<<<<<<<<
  *         return result
  * 
  */
-  __pyx_v_result->vector = new FastSparseVector<weight_t>(((__pyx_v_self->vector[0]) + (__pyx_v_other->vector[0])));
+  __pyx_v_result->vector = new FastSparseVector<weight_t>(((__pyx_v_x->vector[0]) + (__pyx_v_y->vector[0])));
 
   /* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":96
  *         cdef SparseVector result = SparseVector()
- *         result.vector = new FastSparseVector[weight_t](self.vector[0] + other.vector[0])
+ *         result.vector = new FastSparseVector[weight_t](x.vector[0] + y.vector[0])
  *         return result             # <<<<<<<<<<<<<<
  * 
- *     def __sub__(SparseVector self, SparseVector other):
+ *     def __sub__(SparseVector x, SparseVector y):
  */
   __Pyx_XDECREF(__pyx_r);
   __Pyx_INCREF(((PyObject *)__pyx_v_result));
@@ -2536,14 +2725,14 @@ static PyObject *__pyx_pf_5_cdec_12SparseVector_25__add__(struct __pyx_obj_5_cde
 }
 
 /* Python wrapper */
-static PyObject *__pyx_pw_5_cdec_12SparseVector_28__sub__(PyObject *__pyx_v_self, PyObject *__pyx_v_other); /*proto*/
-static PyObject *__pyx_pw_5_cdec_12SparseVector_28__sub__(PyObject *__pyx_v_self, PyObject *__pyx_v_other) {
+static PyObject *__pyx_pw_5_cdec_12SparseVector_28__sub__(PyObject *__pyx_v_x, PyObject *__pyx_v_y); /*proto*/
+static PyObject *__pyx_pw_5_cdec_12SparseVector_28__sub__(PyObject *__pyx_v_x, PyObject *__pyx_v_y) {
   PyObject *__pyx_r = 0;
   __Pyx_RefNannyDeclarations
   __Pyx_RefNannySetupContext("__sub__ (wrapper)", 0);
-  if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_self), __pyx_ptype_5_cdec_SparseVector, 1, "self", 0))) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 98; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_other), __pyx_ptype_5_cdec_SparseVector, 1, "other", 0))) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 98; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __pyx_r = __pyx_pf_5_cdec_12SparseVector_27__sub__(((struct __pyx_obj_5_cdec_SparseVector *)__pyx_v_self), ((struct __pyx_obj_5_cdec_SparseVector *)__pyx_v_other));
+  if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_x), __pyx_ptype_5_cdec_SparseVector, 1, "x", 0))) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 98; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_y), __pyx_ptype_5_cdec_SparseVector, 1, "y", 0))) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 98; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_r = __pyx_pf_5_cdec_12SparseVector_27__sub__(((struct __pyx_obj_5_cdec_SparseVector *)__pyx_v_x), ((struct __pyx_obj_5_cdec_SparseVector *)__pyx_v_y));
   goto __pyx_L0;
   __pyx_L1_error:;
   __pyx_r = NULL;
@@ -2555,12 +2744,12 @@ static PyObject *__pyx_pw_5_cdec_12SparseVector_28__sub__(PyObject *__pyx_v_self
 /* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":98
  *         return result
  * 
- *     def __sub__(SparseVector self, SparseVector other):             # <<<<<<<<<<<<<<
+ *     def __sub__(SparseVector x, SparseVector y):             # <<<<<<<<<<<<<<
  *         cdef SparseVector result = SparseVector()
- *         result.vector = new FastSparseVector[weight_t](self.vector[0] - other.vector[0])
+ *         result.vector = new FastSparseVector[weight_t](x.vector[0] - y.vector[0])
  */
 
-static PyObject *__pyx_pf_5_cdec_12SparseVector_27__sub__(struct __pyx_obj_5_cdec_SparseVector *__pyx_v_self, struct __pyx_obj_5_cdec_SparseVector *__pyx_v_other) {
+static PyObject *__pyx_pf_5_cdec_12SparseVector_27__sub__(struct __pyx_obj_5_cdec_SparseVector *__pyx_v_x, struct __pyx_obj_5_cdec_SparseVector *__pyx_v_y) {
   struct __pyx_obj_5_cdec_SparseVector *__pyx_v_result = 0;
   PyObject *__pyx_r = NULL;
   __Pyx_RefNannyDeclarations
@@ -2572,9 +2761,9 @@ static PyObject *__pyx_pf_5_cdec_12SparseVector_27__sub__(struct __pyx_obj_5_cde
 
   /* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":99
  * 
- *     def __sub__(SparseVector self, SparseVector other):
+ *     def __sub__(SparseVector x, SparseVector y):
  *         cdef SparseVector result = SparseVector()             # <<<<<<<<<<<<<<
- *         result.vector = new FastSparseVector[weight_t](self.vector[0] - other.vector[0])
+ *         result.vector = new FastSparseVector[weight_t](x.vector[0] - y.vector[0])
  *         return result
  */
   __pyx_t_1 = PyObject_Call(((PyObject *)((PyObject*)__pyx_ptype_5_cdec_SparseVector)), ((PyObject *)__pyx_empty_tuple), NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 99; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
@@ -2583,17 +2772,20 @@ static PyObject *__pyx_pf_5_cdec_12SparseVector_27__sub__(struct __pyx_obj_5_cde
   __pyx_t_1 = 0;
 
   /* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":100
- *     def __sub__(SparseVector self, SparseVector other):
+ *     def __sub__(SparseVector x, SparseVector y):
  *         cdef SparseVector result = SparseVector()
- *         result.vector = new FastSparseVector[weight_t](self.vector[0] - other.vector[0])             # <<<<<<<<<<<<<<
+ *         result.vector = new FastSparseVector[weight_t](x.vector[0] - y.vector[0])             # <<<<<<<<<<<<<<
  *         return result
+ * 
  */
-  __pyx_v_result->vector = new FastSparseVector<weight_t>(((__pyx_v_self->vector[0]) - (__pyx_v_other->vector[0])));
+  __pyx_v_result->vector = new FastSparseVector<weight_t>(((__pyx_v_x->vector[0]) - (__pyx_v_y->vector[0])));
 
   /* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":101
  *         cdef SparseVector result = SparseVector()
- *         result.vector = new FastSparseVector[weight_t](self.vector[0] - other.vector[0])
+ *         result.vector = new FastSparseVector[weight_t](x.vector[0] - y.vector[0])
  *         return result             # <<<<<<<<<<<<<<
+ * 
+ *     def __mul__(x, y):
  */
   __Pyx_XDECREF(__pyx_r);
   __Pyx_INCREF(((PyObject *)__pyx_v_result));
@@ -2614,105 +2806,346 @@ static PyObject *__pyx_pf_5_cdec_12SparseVector_27__sub__(struct __pyx_obj_5_cde
 }
 
 /* Python wrapper */
-static void __pyx_pw_5_cdec_10Hypergraph_1__dealloc__(PyObject *__pyx_v_self); /*proto*/
-static void __pyx_pw_5_cdec_10Hypergraph_1__dealloc__(PyObject *__pyx_v_self) {
+static PyObject *__pyx_pw_5_cdec_12SparseVector_30__mul__(PyObject *__pyx_v_x, PyObject *__pyx_v_y); /*proto*/
+static PyObject *__pyx_pw_5_cdec_12SparseVector_30__mul__(PyObject *__pyx_v_x, PyObject *__pyx_v_y) {
+  PyObject *__pyx_r = 0;
   __Pyx_RefNannyDeclarations
-  __Pyx_RefNannySetupContext("__dealloc__ (wrapper)", 0);
-  __pyx_pf_5_cdec_10Hypergraph___dealloc__(((struct __pyx_obj_5_cdec_Hypergraph *)__pyx_v_self));
+  __Pyx_RefNannySetupContext("__mul__ (wrapper)", 0);
+  __pyx_r = __pyx_pf_5_cdec_12SparseVector_29__mul__(((PyObject *)__pyx_v_x), ((PyObject *)__pyx_v_y));
   __Pyx_RefNannyFinishContext();
+  return __pyx_r;
 }
 
-/* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":8
- *     cdef MT19937* rng
+/* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":103
+ *         return result
  * 
- *     def __dealloc__(self):             # <<<<<<<<<<<<<<
- *         del self.hg
- *         if self.rng != NULL:
+ *     def __mul__(x, y):             # <<<<<<<<<<<<<<
+ *         cdef SparseVector vector
+ *         cdef float scalar
  */
 
-static void __pyx_pf_5_cdec_10Hypergraph___dealloc__(struct __pyx_obj_5_cdec_Hypergraph *__pyx_v_self) {
+static PyObject *__pyx_pf_5_cdec_12SparseVector_29__mul__(PyObject *__pyx_v_x, PyObject *__pyx_v_y) {
+  struct __pyx_obj_5_cdec_SparseVector *__pyx_v_vector = 0;
+  float __pyx_v_scalar;
+  struct __pyx_obj_5_cdec_SparseVector *__pyx_v_result = 0;
+  PyObject *__pyx_r = NULL;
   __Pyx_RefNannyDeclarations
-  int __pyx_t_1;
-  __Pyx_RefNannySetupContext("__dealloc__", 0);
+  PyObject *__pyx_t_1 = NULL;
+  int __pyx_t_2;
+  float __pyx_t_3;
+  int __pyx_lineno = 0;
+  const char *__pyx_filename = NULL;
+  int __pyx_clineno = 0;
+  __Pyx_RefNannySetupContext("__mul__", 0);
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":9
- * 
- *     def __dealloc__(self):
- *         del self.hg             # <<<<<<<<<<<<<<
- *         if self.rng != NULL:
- *             del self.rng
+  /* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":106
+ *         cdef SparseVector vector
+ *         cdef float scalar
+ *         if isinstance(x, SparseVector): vector, scalar = x, y             # <<<<<<<<<<<<<<
+ *         else: vector, scalar = y, x
+ *         cdef SparseVector result = SparseVector()
  */
-  delete __pyx_v_self->hg;
+  __pyx_t_1 = ((PyObject *)((PyObject*)__pyx_ptype_5_cdec_SparseVector));
+  __Pyx_INCREF(__pyx_t_1);
+  __pyx_t_2 = __Pyx_TypeCheck(__pyx_v_x, __pyx_t_1); 
+  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+  if (__pyx_t_2) {
+    if (!(likely(((__pyx_v_x) == Py_None) || likely(__Pyx_TypeTest(__pyx_v_x, __pyx_ptype_5_cdec_SparseVector))))) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 106; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_t_1 = __pyx_v_x;
+    __Pyx_INCREF(__pyx_t_1);
+    __pyx_t_3 = __pyx_PyFloat_AsFloat(__pyx_v_y); if (unlikely((__pyx_t_3 == (float)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 106; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_v_vector = ((struct __pyx_obj_5_cdec_SparseVector *)__pyx_t_1);
+    __pyx_t_1 = 0;
+    __pyx_v_scalar = __pyx_t_3;
+    goto __pyx_L3;
+  }
+  /*else*/ {
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":10
- *     def __dealloc__(self):
- *         del self.hg
- *         if self.rng != NULL:             # <<<<<<<<<<<<<<
- *             del self.rng
+    /* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":107
+ *         cdef float scalar
+ *         if isinstance(x, SparseVector): vector, scalar = x, y
+ *         else: vector, scalar = y, x             # <<<<<<<<<<<<<<
+ *         cdef SparseVector result = SparseVector()
+ *         result.vector = new FastSparseVector[weight_t](vector.vector[0] * scalar)
+ */
+    if (!(likely(((__pyx_v_y) == Py_None) || likely(__Pyx_TypeTest(__pyx_v_y, __pyx_ptype_5_cdec_SparseVector))))) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 107; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_t_1 = __pyx_v_y;
+    __Pyx_INCREF(__pyx_t_1);
+    __pyx_t_3 = __pyx_PyFloat_AsFloat(__pyx_v_x); if (unlikely((__pyx_t_3 == (float)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 107; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_v_vector = ((struct __pyx_obj_5_cdec_SparseVector *)__pyx_t_1);
+    __pyx_t_1 = 0;
+    __pyx_v_scalar = __pyx_t_3;
+  }
+  __pyx_L3:;
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":108
+ *         if isinstance(x, SparseVector): vector, scalar = x, y
+ *         else: vector, scalar = y, x
+ *         cdef SparseVector result = SparseVector()             # <<<<<<<<<<<<<<
+ *         result.vector = new FastSparseVector[weight_t](vector.vector[0] * scalar)
+ *         return result
+ */
+  __pyx_t_1 = PyObject_Call(((PyObject *)((PyObject*)__pyx_ptype_5_cdec_SparseVector)), ((PyObject *)__pyx_empty_tuple), NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 108; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_1);
+  __pyx_v_result = ((struct __pyx_obj_5_cdec_SparseVector *)__pyx_t_1);
+  __pyx_t_1 = 0;
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":109
+ *         else: vector, scalar = y, x
+ *         cdef SparseVector result = SparseVector()
+ *         result.vector = new FastSparseVector[weight_t](vector.vector[0] * scalar)             # <<<<<<<<<<<<<<
+ *         return result
  * 
  */
-  __pyx_t_1 = (__pyx_v_self->rng != NULL);
-  if (__pyx_t_1) {
+  __pyx_v_result->vector = new FastSparseVector<weight_t>(((__pyx_v_vector->vector[0]) * __pyx_v_scalar));
 
-    /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":11
- *         del self.hg
- *         if self.rng != NULL:
- *             del self.rng             # <<<<<<<<<<<<<<
+  /* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":110
+ *         cdef SparseVector result = SparseVector()
+ *         result.vector = new FastSparseVector[weight_t](vector.vector[0] * scalar)
+ *         return result             # <<<<<<<<<<<<<<
  * 
- *     def viterbi(self):
+ *     def __div__(x, y):
  */
-    delete __pyx_v_self->rng;
-    goto __pyx_L3;
-  }
-  __pyx_L3:;
+  __Pyx_XDECREF(__pyx_r);
+  __Pyx_INCREF(((PyObject *)__pyx_v_result));
+  __pyx_r = ((PyObject *)__pyx_v_result);
+  goto __pyx_L0;
 
+  __pyx_r = Py_None; __Pyx_INCREF(Py_None);
+  goto __pyx_L0;
+  __pyx_L1_error:;
+  __Pyx_XDECREF(__pyx_t_1);
+  __Pyx_AddTraceback("_cdec.SparseVector.__mul__", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __pyx_r = NULL;
+  __pyx_L0:;
+  __Pyx_XDECREF((PyObject *)__pyx_v_vector);
+  __Pyx_XDECREF((PyObject *)__pyx_v_result);
+  __Pyx_XGIVEREF(__pyx_r);
   __Pyx_RefNannyFinishContext();
+  return __pyx_r;
 }
 
 /* Python wrapper */
-static PyObject *__pyx_pw_5_cdec_10Hypergraph_3viterbi(PyObject *__pyx_v_self, CYTHON_UNUSED PyObject *unused); /*proto*/
-static PyObject *__pyx_pw_5_cdec_10Hypergraph_3viterbi(PyObject *__pyx_v_self, CYTHON_UNUSED PyObject *unused) {
+#if PY_MAJOR_VERSION < 3
+static PyObject *__pyx_pw_5_cdec_12SparseVector_32__div__(PyObject *__pyx_v_x, PyObject *__pyx_v_y); /*proto*/
+static PyObject *__pyx_pw_5_cdec_12SparseVector_32__div__(PyObject *__pyx_v_x, PyObject *__pyx_v_y) {
   PyObject *__pyx_r = 0;
   __Pyx_RefNannyDeclarations
-  __Pyx_RefNannySetupContext("viterbi (wrapper)", 0);
-  __pyx_r = __pyx_pf_5_cdec_10Hypergraph_2viterbi(((struct __pyx_obj_5_cdec_Hypergraph *)__pyx_v_self));
+  __Pyx_RefNannySetupContext("__div__ (wrapper)", 0);
+  __pyx_r = __pyx_pf_5_cdec_12SparseVector_31__div__(((PyObject *)__pyx_v_x), ((PyObject *)__pyx_v_y));
   __Pyx_RefNannyFinishContext();
   return __pyx_r;
 }
+#endif /*!(#if PY_MAJOR_VERSION < 3)*/
 
-/* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":13
- *             del self.rng
+/* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":112
+ *         return result
  * 
- *     def viterbi(self):             # <<<<<<<<<<<<<<
- *         cdef vector[WordID] trans
- *         hypergraph.ViterbiESentence(self.hg[0], &trans)
+ *     def __div__(x, y):             # <<<<<<<<<<<<<<
+ *         cdef SparseVector vector
+ *         cdef float scalar
  */
 
-static PyObject *__pyx_pf_5_cdec_10Hypergraph_2viterbi(struct __pyx_obj_5_cdec_Hypergraph *__pyx_v_self) {
-  std::vector<WordID> __pyx_v_trans;
-  PyObject *__pyx_v_sentence = 0;
+#if PY_MAJOR_VERSION < 3
+static PyObject *__pyx_pf_5_cdec_12SparseVector_31__div__(PyObject *__pyx_v_x, PyObject *__pyx_v_y) {
+  struct __pyx_obj_5_cdec_SparseVector *__pyx_v_vector = 0;
+  float __pyx_v_scalar;
+  struct __pyx_obj_5_cdec_SparseVector *__pyx_v_result = 0;
   PyObject *__pyx_r = NULL;
   __Pyx_RefNannyDeclarations
   PyObject *__pyx_t_1 = NULL;
-  PyObject *__pyx_t_2 = NULL;
+  int __pyx_t_2;
+  float __pyx_t_3;
   int __pyx_lineno = 0;
   const char *__pyx_filename = NULL;
   int __pyx_clineno = 0;
-  __Pyx_RefNannySetupContext("viterbi", 0);
+  __Pyx_RefNannySetupContext("__div__", 0);
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":15
- *     def viterbi(self):
- *         cdef vector[WordID] trans
- *         hypergraph.ViterbiESentence(self.hg[0], &trans)             # <<<<<<<<<<<<<<
- *         cdef str sentence = GetString(trans).c_str()
- *         return sentence.decode('utf8')
+  /* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":115
+ *         cdef SparseVector vector
+ *         cdef float scalar
+ *         if isinstance(x, SparseVector): vector, scalar = x, y             # <<<<<<<<<<<<<<
+ *         else: vector, scalar = y, x
+ *         cdef SparseVector result = SparseVector()
  */
-  ViterbiESentence((__pyx_v_self->hg[0]), (&__pyx_v_trans));
+  __pyx_t_1 = ((PyObject *)((PyObject*)__pyx_ptype_5_cdec_SparseVector));
+  __Pyx_INCREF(__pyx_t_1);
+  __pyx_t_2 = __Pyx_TypeCheck(__pyx_v_x, __pyx_t_1); 
+  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+  if (__pyx_t_2) {
+    if (!(likely(((__pyx_v_x) == Py_None) || likely(__Pyx_TypeTest(__pyx_v_x, __pyx_ptype_5_cdec_SparseVector))))) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 115; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_t_1 = __pyx_v_x;
+    __Pyx_INCREF(__pyx_t_1);
+    __pyx_t_3 = __pyx_PyFloat_AsFloat(__pyx_v_y); if (unlikely((__pyx_t_3 == (float)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 115; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_v_vector = ((struct __pyx_obj_5_cdec_SparseVector *)__pyx_t_1);
+    __pyx_t_1 = 0;
+    __pyx_v_scalar = __pyx_t_3;
+    goto __pyx_L3;
+  }
+  /*else*/ {
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":16
- *         cdef vector[WordID] trans
- *         hypergraph.ViterbiESentence(self.hg[0], &trans)
- *         cdef str sentence = GetString(trans).c_str()             # <<<<<<<<<<<<<<
+    /* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":116
+ *         cdef float scalar
+ *         if isinstance(x, SparseVector): vector, scalar = x, y
+ *         else: vector, scalar = y, x             # <<<<<<<<<<<<<<
+ *         cdef SparseVector result = SparseVector()
+ *         result.vector = new FastSparseVector[weight_t](vector.vector[0] / scalar)
+ */
+    if (!(likely(((__pyx_v_y) == Py_None) || likely(__Pyx_TypeTest(__pyx_v_y, __pyx_ptype_5_cdec_SparseVector))))) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 116; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_t_1 = __pyx_v_y;
+    __Pyx_INCREF(__pyx_t_1);
+    __pyx_t_3 = __pyx_PyFloat_AsFloat(__pyx_v_x); if (unlikely((__pyx_t_3 == (float)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 116; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_v_vector = ((struct __pyx_obj_5_cdec_SparseVector *)__pyx_t_1);
+    __pyx_t_1 = 0;
+    __pyx_v_scalar = __pyx_t_3;
+  }
+  __pyx_L3:;
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":117
+ *         if isinstance(x, SparseVector): vector, scalar = x, y
+ *         else: vector, scalar = y, x
+ *         cdef SparseVector result = SparseVector()             # <<<<<<<<<<<<<<
+ *         result.vector = new FastSparseVector[weight_t](vector.vector[0] / scalar)
+ *         return result
+ */
+  __pyx_t_1 = PyObject_Call(((PyObject *)((PyObject*)__pyx_ptype_5_cdec_SparseVector)), ((PyObject *)__pyx_empty_tuple), NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 117; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_1);
+  __pyx_v_result = ((struct __pyx_obj_5_cdec_SparseVector *)__pyx_t_1);
+  __pyx_t_1 = 0;
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":118
+ *         else: vector, scalar = y, x
+ *         cdef SparseVector result = SparseVector()
+ *         result.vector = new FastSparseVector[weight_t](vector.vector[0] / scalar)             # <<<<<<<<<<<<<<
+ *         return result
+ */
+  __pyx_v_result->vector = new FastSparseVector<weight_t>(((__pyx_v_vector->vector[0]) / __pyx_v_scalar));
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":119
+ *         cdef SparseVector result = SparseVector()
+ *         result.vector = new FastSparseVector[weight_t](vector.vector[0] / scalar)
+ *         return result             # <<<<<<<<<<<<<<
+ */
+  __Pyx_XDECREF(__pyx_r);
+  __Pyx_INCREF(((PyObject *)__pyx_v_result));
+  __pyx_r = ((PyObject *)__pyx_v_result);
+  goto __pyx_L0;
+
+  __pyx_r = Py_None; __Pyx_INCREF(Py_None);
+  goto __pyx_L0;
+  __pyx_L1_error:;
+  __Pyx_XDECREF(__pyx_t_1);
+  __Pyx_AddTraceback("_cdec.SparseVector.__div__", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __pyx_r = NULL;
+  __pyx_L0:;
+  __Pyx_XDECREF((PyObject *)__pyx_v_vector);
+  __Pyx_XDECREF((PyObject *)__pyx_v_result);
+  __Pyx_XGIVEREF(__pyx_r);
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+#endif /*!(#if PY_MAJOR_VERSION < 3)*/
+
+/* Python wrapper */
+static void __pyx_pw_5_cdec_10Hypergraph_1__dealloc__(PyObject *__pyx_v_self); /*proto*/
+static void __pyx_pw_5_cdec_10Hypergraph_1__dealloc__(PyObject *__pyx_v_self) {
+  __Pyx_RefNannyDeclarations
+  __Pyx_RefNannySetupContext("__dealloc__ (wrapper)", 0);
+  __pyx_pf_5_cdec_10Hypergraph___dealloc__(((struct __pyx_obj_5_cdec_Hypergraph *)__pyx_v_self));
+  __Pyx_RefNannyFinishContext();
+}
+
+/* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":8
+ *     cdef MT19937* rng
+ * 
+ *     def __dealloc__(self):             # <<<<<<<<<<<<<<
+ *         del self.hg
+ *         if self.rng != NULL:
+ */
+
+static void __pyx_pf_5_cdec_10Hypergraph___dealloc__(struct __pyx_obj_5_cdec_Hypergraph *__pyx_v_self) {
+  __Pyx_RefNannyDeclarations
+  int __pyx_t_1;
+  __Pyx_RefNannySetupContext("__dealloc__", 0);
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":9
+ * 
+ *     def __dealloc__(self):
+ *         del self.hg             # <<<<<<<<<<<<<<
+ *         if self.rng != NULL:
+ *             del self.rng
+ */
+  delete __pyx_v_self->hg;
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":10
+ *     def __dealloc__(self):
+ *         del self.hg
+ *         if self.rng != NULL:             # <<<<<<<<<<<<<<
+ *             del self.rng
+ * 
+ */
+  __pyx_t_1 = (__pyx_v_self->rng != NULL);
+  if (__pyx_t_1) {
+
+    /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":11
+ *         del self.hg
+ *         if self.rng != NULL:
+ *             del self.rng             # <<<<<<<<<<<<<<
+ * 
+ *     def viterbi(self):
+ */
+    delete __pyx_v_self->rng;
+    goto __pyx_L3;
+  }
+  __pyx_L3:;
+
+  __Pyx_RefNannyFinishContext();
+}
+
+/* Python wrapper */
+static PyObject *__pyx_pw_5_cdec_10Hypergraph_3viterbi(PyObject *__pyx_v_self, CYTHON_UNUSED PyObject *unused); /*proto*/
+static PyObject *__pyx_pw_5_cdec_10Hypergraph_3viterbi(PyObject *__pyx_v_self, CYTHON_UNUSED PyObject *unused) {
+  PyObject *__pyx_r = 0;
+  __Pyx_RefNannyDeclarations
+  __Pyx_RefNannySetupContext("viterbi (wrapper)", 0);
+  __pyx_r = __pyx_pf_5_cdec_10Hypergraph_2viterbi(((struct __pyx_obj_5_cdec_Hypergraph *)__pyx_v_self));
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+/* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":13
+ *             del self.rng
+ * 
+ *     def viterbi(self):             # <<<<<<<<<<<<<<
+ *         cdef vector[WordID] trans
+ *         hypergraph.ViterbiESentence(self.hg[0], &trans)
+ */
+
+static PyObject *__pyx_pf_5_cdec_10Hypergraph_2viterbi(struct __pyx_obj_5_cdec_Hypergraph *__pyx_v_self) {
+  std::vector<WordID> __pyx_v_trans;
+  PyObject *__pyx_v_sentence = 0;
+  PyObject *__pyx_r = NULL;
+  __Pyx_RefNannyDeclarations
+  PyObject *__pyx_t_1 = NULL;
+  PyObject *__pyx_t_2 = NULL;
+  int __pyx_lineno = 0;
+  const char *__pyx_filename = NULL;
+  int __pyx_clineno = 0;
+  __Pyx_RefNannySetupContext("viterbi", 0);
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":15
+ *     def viterbi(self):
+ *         cdef vector[WordID] trans
+ *         hypergraph.ViterbiESentence(self.hg[0], &trans)             # <<<<<<<<<<<<<<
+ *         cdef str sentence = GetString(trans).c_str()
+ *         return sentence.decode('utf8')
+ */
+  ViterbiESentence((__pyx_v_self->hg[0]), (&__pyx_v_trans));
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":16
+ *         cdef vector[WordID] trans
+ *         hypergraph.ViterbiESentence(self.hg[0], &trans)
+ *         cdef str sentence = GetString(trans).c_str()             # <<<<<<<<<<<<<<
  *         return sentence.decode('utf8')
  * 
  */
@@ -3338,7 +3771,7 @@ static PyObject *__pyx_gb_5_cdec_10Hypergraph_15generator3(__pyx_GeneratorObject
  *             yield tree.decode('utf8')
  *         del derivations             # <<<<<<<<<<<<<<
  * 
- *     def sample(self, unsigned n):
+ *     def kbest_features(self, size):
  */
   delete __pyx_cur_scope->__pyx_v_derivations;
   PyErr_SetNone(PyExc_StopIteration);
@@ -3356,22 +3789,12 @@ static PyObject *__pyx_gb_5_cdec_10Hypergraph_15generator3(__pyx_GeneratorObject
 static PyObject *__pyx_gb_5_cdec_10Hypergraph_18generator4(__pyx_GeneratorObject *__pyx_generator, PyObject *__pyx_sent_value); /* proto */
 
 /* Python wrapper */
-static PyObject *__pyx_pw_5_cdec_10Hypergraph_17sample(PyObject *__pyx_v_self, PyObject *__pyx_arg_n); /*proto*/
-static PyObject *__pyx_pw_5_cdec_10Hypergraph_17sample(PyObject *__pyx_v_self, PyObject *__pyx_arg_n) {
-  unsigned int __pyx_v_n;
+static PyObject *__pyx_pw_5_cdec_10Hypergraph_17kbest_features(PyObject *__pyx_v_self, PyObject *__pyx_v_size); /*proto*/
+static PyObject *__pyx_pw_5_cdec_10Hypergraph_17kbest_features(PyObject *__pyx_v_self, PyObject *__pyx_v_size) {
   PyObject *__pyx_r = 0;
   __Pyx_RefNannyDeclarations
-  __Pyx_RefNannySetupContext("sample (wrapper)", 0);
-  assert(__pyx_arg_n); {
-    __pyx_v_n = __Pyx_PyInt_AsUnsignedInt(__pyx_arg_n); if (unlikely((__pyx_v_n == (unsigned int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 56; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
-  }
-  goto __pyx_L4_argument_unpacking_done;
-  __pyx_L3_error:;
-  __Pyx_AddTraceback("_cdec.Hypergraph.sample", __pyx_clineno, __pyx_lineno, __pyx_filename);
-  __Pyx_RefNannyFinishContext();
-  return NULL;
-  __pyx_L4_argument_unpacking_done:;
-  __pyx_r = __pyx_pf_5_cdec_10Hypergraph_16sample(((struct __pyx_obj_5_cdec_Hypergraph *)__pyx_v_self), ((unsigned int)__pyx_v_n));
+  __Pyx_RefNannySetupContext("kbest_features (wrapper)", 0);
+  __pyx_r = __pyx_pf_5_cdec_10Hypergraph_16kbest_features(((struct __pyx_obj_5_cdec_Hypergraph *)__pyx_v_self), ((PyObject *)__pyx_v_size));
   __Pyx_RefNannyFinishContext();
   return __pyx_r;
 }
@@ -3379,20 +3802,20 @@ static PyObject *__pyx_pw_5_cdec_10Hypergraph_17sample(PyObject *__pyx_v_self, P
 /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":56
  *         del derivations
  * 
- *     def sample(self, unsigned n):             # <<<<<<<<<<<<<<
- *         cdef vector[hypergraph.Hypothesis]* hypos = new vector[hypergraph.Hypothesis]()
- *         if self.rng == NULL:
+ *     def kbest_features(self, size):             # <<<<<<<<<<<<<<
+ *         cdef kb.KBestDerivations[FastSparseVector[weight_t], kb.FeatureVectorTraversal]* derivations = new kb.KBestDerivations[FastSparseVector[weight_t], kb.FeatureVectorTraversal](self.hg[0], size)
+ *         cdef kb.KBestDerivations[FastSparseVector[weight_t], kb.FeatureVectorTraversal].Derivation* derivation
  */
 
-static PyObject *__pyx_pf_5_cdec_10Hypergraph_16sample(struct __pyx_obj_5_cdec_Hypergraph *__pyx_v_self, unsigned int __pyx_v_n) {
-  struct __pyx_obj_5_cdec___pyx_scope_struct_4_sample *__pyx_cur_scope;
+static PyObject *__pyx_pf_5_cdec_10Hypergraph_16kbest_features(struct __pyx_obj_5_cdec_Hypergraph *__pyx_v_self, PyObject *__pyx_v_size) {
+  struct __pyx_obj_5_cdec___pyx_scope_struct_4_kbest_features *__pyx_cur_scope;
   PyObject *__pyx_r = NULL;
   __Pyx_RefNannyDeclarations
   int __pyx_lineno = 0;
   const char *__pyx_filename = NULL;
   int __pyx_clineno = 0;
-  __Pyx_RefNannySetupContext("sample", 0);
-  __pyx_cur_scope = (struct __pyx_obj_5_cdec___pyx_scope_struct_4_sample *)__pyx_ptype_5_cdec___pyx_scope_struct_4_sample->tp_new(__pyx_ptype_5_cdec___pyx_scope_struct_4_sample, __pyx_empty_tuple, NULL);
+  __Pyx_RefNannySetupContext("kbest_features", 0);
+  __pyx_cur_scope = (struct __pyx_obj_5_cdec___pyx_scope_struct_4_kbest_features *)__pyx_ptype_5_cdec___pyx_scope_struct_4_kbest_features->tp_new(__pyx_ptype_5_cdec___pyx_scope_struct_4_kbest_features, __pyx_empty_tuple, NULL);
   if (unlikely(!__pyx_cur_scope)) {
     __Pyx_RefNannyFinishContext();
     return NULL;
@@ -3401,7 +3824,9 @@ static PyObject *__pyx_pf_5_cdec_10Hypergraph_16sample(struct __pyx_obj_5_cdec_H
   __pyx_cur_scope->__pyx_v_self = __pyx_v_self;
   __Pyx_INCREF((PyObject *)__pyx_cur_scope->__pyx_v_self);
   __Pyx_GIVEREF((PyObject *)__pyx_cur_scope->__pyx_v_self);
-  __pyx_cur_scope->__pyx_v_n = __pyx_v_n;
+  __pyx_cur_scope->__pyx_v_size = __pyx_v_size;
+  __Pyx_INCREF(__pyx_cur_scope->__pyx_v_size);
+  __Pyx_GIVEREF(__pyx_cur_scope->__pyx_v_size);
   {
     __pyx_GeneratorObject *gen = __Pyx_Generator_New((__pyx_generator_body_t) __pyx_gb_5_cdec_10Hypergraph_18generator4, (PyObject *) __pyx_cur_scope); if (unlikely(!gen)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 56; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
     __Pyx_DECREF(__pyx_cur_scope);
@@ -3412,7 +3837,7 @@ static PyObject *__pyx_pf_5_cdec_10Hypergraph_16sample(struct __pyx_obj_5_cdec_H
   __pyx_r = Py_None; __Pyx_INCREF(Py_None);
   goto __pyx_L0;
   __pyx_L1_error:;
-  __Pyx_AddTraceback("_cdec.Hypergraph.sample", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __Pyx_AddTraceback("_cdec.Hypergraph.kbest_features", __pyx_clineno, __pyx_lineno, __pyx_filename);
   __pyx_r = NULL;
   __pyx_L0:;
   __Pyx_DECREF(((PyObject *)__pyx_cur_scope));
@@ -3423,13 +3848,12 @@ static PyObject *__pyx_pf_5_cdec_10Hypergraph_16sample(struct __pyx_obj_5_cdec_H
 
 static PyObject *__pyx_gb_5_cdec_10Hypergraph_18generator4(__pyx_GeneratorObject *__pyx_generator, PyObject *__pyx_sent_value) /* generator body */
 {
-  struct __pyx_obj_5_cdec___pyx_scope_struct_4_sample *__pyx_cur_scope = ((struct __pyx_obj_5_cdec___pyx_scope_struct_4_sample *)__pyx_generator->closure);
+  struct __pyx_obj_5_cdec___pyx_scope_struct_4_kbest_features *__pyx_cur_scope = ((struct __pyx_obj_5_cdec___pyx_scope_struct_4_kbest_features *)__pyx_generator->closure);
   PyObject *__pyx_r = NULL;
-  int __pyx_t_1;
-  size_t __pyx_t_2;
-  unsigned int __pyx_t_3;
+  unsigned int __pyx_t_1;
+  long __pyx_t_2;
+  int __pyx_t_3;
   PyObject *__pyx_t_4 = NULL;
-  PyObject *__pyx_t_5 = NULL;
   __Pyx_RefNannyDeclarations
   __Pyx_RefNannySetupContext("None", 0);
   switch (__pyx_generator->resume_label) {
@@ -3444,99 +3868,298 @@ static PyObject *__pyx_gb_5_cdec_10Hypergraph_18generator4(__pyx_GeneratorObject
 
   /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":57
  * 
- *     def sample(self, unsigned n):
- *         cdef vector[hypergraph.Hypothesis]* hypos = new vector[hypergraph.Hypothesis]()             # <<<<<<<<<<<<<<
- *         if self.rng == NULL:
- *             self.rng = new MT19937()
- */
-  __pyx_cur_scope->__pyx_v_hypos = new std::vector<HypergraphSampler::Hypothesis>();
-
-  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":58
- *     def sample(self, unsigned n):
- *         cdef vector[hypergraph.Hypothesis]* hypos = new vector[hypergraph.Hypothesis]()
- *         if self.rng == NULL:             # <<<<<<<<<<<<<<
- *             self.rng = new MT19937()
- *         hypergraph.sample_hypotheses(self.hg[0], n, self.rng, hypos)
+ *     def kbest_features(self, size):
+ *         cdef kb.KBestDerivations[FastSparseVector[weight_t], kb.FeatureVectorTraversal]* derivations = new kb.KBestDerivations[FastSparseVector[weight_t], kb.FeatureVectorTraversal](self.hg[0], size)             # <<<<<<<<<<<<<<
+ *         cdef kb.KBestDerivations[FastSparseVector[weight_t], kb.FeatureVectorTraversal].Derivation* derivation
+ *         cdef SparseVector fmap
  */
-  __pyx_t_1 = (__pyx_cur_scope->__pyx_v_self->rng == NULL);
-  if (__pyx_t_1) {
+  __pyx_t_1 = __Pyx_PyInt_AsUnsignedInt(__pyx_cur_scope->__pyx_v_size); if (unlikely((__pyx_t_1 == (unsigned int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 57; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_cur_scope->__pyx_v_derivations = new KBest::KBestDerivations<FastSparseVector<weight_t>,FeatureVectorTraversal>((__pyx_cur_scope->__pyx_v_self->hg[0]), __pyx_t_1);
 
-    /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":59
- *         cdef vector[hypergraph.Hypothesis]* hypos = new vector[hypergraph.Hypothesis]()
- *         if self.rng == NULL:
- *             self.rng = new MT19937()             # <<<<<<<<<<<<<<
- *         hypergraph.sample_hypotheses(self.hg[0], n, self.rng, hypos)
- *         cdef str sentence
+  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":61
+ *         cdef SparseVector fmap
+ *         cdef unsigned k
+ *         for k in range(size):             # <<<<<<<<<<<<<<
+ *             derivation = derivations.LazyKthBest(self.hg.nodes_.size() - 1, k)
+ *             if not derivation: break
  */
-    __pyx_cur_scope->__pyx_v_self->rng = new MT19937();
-    goto __pyx_L4;
-  }
-  __pyx_L4:;
+  __pyx_t_2 = __Pyx_PyInt_AsLong(__pyx_cur_scope->__pyx_v_size); if (unlikely((__pyx_t_2 == (long)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 61; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  for (__pyx_t_1 = 0; __pyx_t_1 < __pyx_t_2; __pyx_t_1+=1) {
+    __pyx_cur_scope->__pyx_v_k = __pyx_t_1;
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":60
- *         if self.rng == NULL:
- *             self.rng = new MT19937()
- *         hypergraph.sample_hypotheses(self.hg[0], n, self.rng, hypos)             # <<<<<<<<<<<<<<
- *         cdef str sentence
+    /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":62
  *         cdef unsigned k
+ *         for k in range(size):
+ *             derivation = derivations.LazyKthBest(self.hg.nodes_.size() - 1, k)             # <<<<<<<<<<<<<<
+ *             if not derivation: break
+ *             fmap = SparseVector()
  */
-  HypergraphSampler::sample_hypotheses((__pyx_cur_scope->__pyx_v_self->hg[0]), __pyx_cur_scope->__pyx_v_n, __pyx_cur_scope->__pyx_v_self->rng, __pyx_cur_scope->__pyx_v_hypos);
+    __pyx_cur_scope->__pyx_v_derivation = __pyx_cur_scope->__pyx_v_derivations->LazyKthBest((__pyx_cur_scope->__pyx_v_self->hg->nodes_.size() - 1), __pyx_cur_scope->__pyx_v_k);
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":63
- *         cdef str sentence
- *         cdef unsigned k
- *         for k in range(hypos.size()):             # <<<<<<<<<<<<<<
- *             sentence = GetString(hypos[0][k].words).c_str()
- *             yield sentence.decode('utf8')
+    /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":63
+ *         for k in range(size):
+ *             derivation = derivations.LazyKthBest(self.hg.nodes_.size() - 1, k)
+ *             if not derivation: break             # <<<<<<<<<<<<<<
+ *             fmap = SparseVector()
+ *             fmap.vector = new FastSparseVector[weight_t](derivation._yield)
  */
-  __pyx_t_2 = __pyx_cur_scope->__pyx_v_hypos->size();
-  for (__pyx_t_3 = 0; __pyx_t_3 < __pyx_t_2; __pyx_t_3+=1) {
-    __pyx_cur_scope->__pyx_v_k = __pyx_t_3;
+    __pyx_t_3 = (!(__pyx_cur_scope->__pyx_v_derivation != 0));
+    if (__pyx_t_3) {
+      goto __pyx_L5_break;
+      goto __pyx_L6;
+    }
+    __pyx_L6:;
 
     /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":64
- *         cdef unsigned k
- *         for k in range(hypos.size()):
- *             sentence = GetString(hypos[0][k].words).c_str()             # <<<<<<<<<<<<<<
- *             yield sentence.decode('utf8')
- *         del hypos
+ *             derivation = derivations.LazyKthBest(self.hg.nodes_.size() - 1, k)
+ *             if not derivation: break
+ *             fmap = SparseVector()             # <<<<<<<<<<<<<<
+ *             fmap.vector = new FastSparseVector[weight_t](derivation._yield)
+ *             yield fmap
  */
-    __pyx_t_4 = PyBytes_FromString(TD::GetString(((__pyx_cur_scope->__pyx_v_hypos[0])[__pyx_cur_scope->__pyx_v_k]).words).c_str()); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 64; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-    __Pyx_GOTREF(((PyObject *)__pyx_t_4));
-    if (!(likely(PyString_CheckExact(((PyObject *)__pyx_t_4)))||(PyErr_Format(PyExc_TypeError, "Expected str, got %.200s", Py_TYPE(((PyObject *)__pyx_t_4))->tp_name), 0))) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 64; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-    __Pyx_XGOTREF(((PyObject *)__pyx_cur_scope->__pyx_v_sentence));
-    __Pyx_XDECREF(((PyObject *)__pyx_cur_scope->__pyx_v_sentence));
-    __Pyx_GIVEREF(((PyObject *)__pyx_t_4));
-    __pyx_cur_scope->__pyx_v_sentence = ((PyObject*)__pyx_t_4);
+    __pyx_t_4 = PyObject_Call(((PyObject *)((PyObject*)__pyx_ptype_5_cdec_SparseVector)), ((PyObject *)__pyx_empty_tuple), NULL); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 64; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_4);
+    __Pyx_XGOTREF(((PyObject *)__pyx_cur_scope->__pyx_v_fmap));
+    __Pyx_XDECREF(((PyObject *)__pyx_cur_scope->__pyx_v_fmap));
+    __Pyx_GIVEREF(__pyx_t_4);
+    __pyx_cur_scope->__pyx_v_fmap = ((struct __pyx_obj_5_cdec_SparseVector *)__pyx_t_4);
     __pyx_t_4 = 0;
 
     /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":65
- *         for k in range(hypos.size()):
- *             sentence = GetString(hypos[0][k].words).c_str()
- *             yield sentence.decode('utf8')             # <<<<<<<<<<<<<<
- *         del hypos
+ *             if not derivation: break
+ *             fmap = SparseVector()
+ *             fmap.vector = new FastSparseVector[weight_t](derivation._yield)             # <<<<<<<<<<<<<<
+ *             yield fmap
+ *         del derivations
+ */
+    __pyx_cur_scope->__pyx_v_fmap->vector = new FastSparseVector<weight_t>(__pyx_cur_scope->__pyx_v_derivation->yield);
+
+    /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":66
+ *             fmap = SparseVector()
+ *             fmap.vector = new FastSparseVector[weight_t](derivation._yield)
+ *             yield fmap             # <<<<<<<<<<<<<<
+ *         del derivations
  * 
  */
-    __pyx_t_4 = PyObject_GetAttr(((PyObject *)__pyx_cur_scope->__pyx_v_sentence), __pyx_n_s__decode); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 65; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-    __Pyx_GOTREF(__pyx_t_4);
-    __pyx_t_5 = PyObject_Call(__pyx_t_4, ((PyObject *)__pyx_k_tuple_9), NULL); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 65; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-    __Pyx_GOTREF(__pyx_t_5);
-    __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
-    __pyx_r = __pyx_t_5;
-    __pyx_t_5 = 0;
-    __pyx_cur_scope->__pyx_t_0 = __pyx_t_2;
-    __pyx_cur_scope->__pyx_t_1 = __pyx_t_3;
+    __Pyx_INCREF(((PyObject *)__pyx_cur_scope->__pyx_v_fmap));
+    __pyx_r = ((PyObject *)__pyx_cur_scope->__pyx_v_fmap);
+    __pyx_cur_scope->__pyx_t_0 = __pyx_t_1;
+    __pyx_cur_scope->__pyx_t_1 = __pyx_t_2;
     __Pyx_XGIVEREF(__pyx_r);
     __Pyx_RefNannyFinishContext();
     /* return from generator, yielding value */
     __pyx_generator->resume_label = 1;
     return __pyx_r;
     __pyx_L7_resume_from_yield:;
-    __pyx_t_2 = __pyx_cur_scope->__pyx_t_0;
-    __pyx_t_3 = __pyx_cur_scope->__pyx_t_1;
-    if (unlikely(!__pyx_sent_value)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 65; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  }
+    __pyx_t_1 = __pyx_cur_scope->__pyx_t_0;
+    __pyx_t_2 = __pyx_cur_scope->__pyx_t_1;
+    if (unlikely(!__pyx_sent_value)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 66; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  }
+  __pyx_L5_break:;
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":67
+ *             fmap.vector = new FastSparseVector[weight_t](derivation._yield)
+ *             yield fmap
+ *         del derivations             # <<<<<<<<<<<<<<
+ * 
+ *     def sample(self, unsigned n):
+ */
+  delete __pyx_cur_scope->__pyx_v_derivations;
+  PyErr_SetNone(PyExc_StopIteration);
+  goto __pyx_L0;
+  __pyx_L1_error:;
+  __Pyx_XDECREF(__pyx_t_4);
+  __Pyx_AddTraceback("kbest_features", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __pyx_L0:;
+  __Pyx_XDECREF(__pyx_r);
+  __pyx_generator->resume_label = -1;
+  __Pyx_RefNannyFinishContext();
+  return NULL;
+}
+static PyObject *__pyx_gb_5_cdec_10Hypergraph_21generator5(__pyx_GeneratorObject *__pyx_generator, PyObject *__pyx_sent_value); /* proto */
+
+/* Python wrapper */
+static PyObject *__pyx_pw_5_cdec_10Hypergraph_20sample(PyObject *__pyx_v_self, PyObject *__pyx_arg_n); /*proto*/
+static PyObject *__pyx_pw_5_cdec_10Hypergraph_20sample(PyObject *__pyx_v_self, PyObject *__pyx_arg_n) {
+  unsigned int __pyx_v_n;
+  PyObject *__pyx_r = 0;
+  __Pyx_RefNannyDeclarations
+  __Pyx_RefNannySetupContext("sample (wrapper)", 0);
+  assert(__pyx_arg_n); {
+    __pyx_v_n = __Pyx_PyInt_AsUnsignedInt(__pyx_arg_n); if (unlikely((__pyx_v_n == (unsigned int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 69; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+  }
+  goto __pyx_L4_argument_unpacking_done;
+  __pyx_L3_error:;
+  __Pyx_AddTraceback("_cdec.Hypergraph.sample", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __Pyx_RefNannyFinishContext();
+  return NULL;
+  __pyx_L4_argument_unpacking_done:;
+  __pyx_r = __pyx_pf_5_cdec_10Hypergraph_19sample(((struct __pyx_obj_5_cdec_Hypergraph *)__pyx_v_self), ((unsigned int)__pyx_v_n));
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+/* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":69
+ *         del derivations
+ * 
+ *     def sample(self, unsigned n):             # <<<<<<<<<<<<<<
+ *         cdef vector[hypergraph.Hypothesis]* hypos = new vector[hypergraph.Hypothesis]()
+ *         if self.rng == NULL:
+ */
+
+static PyObject *__pyx_pf_5_cdec_10Hypergraph_19sample(struct __pyx_obj_5_cdec_Hypergraph *__pyx_v_self, unsigned int __pyx_v_n) {
+  struct __pyx_obj_5_cdec___pyx_scope_struct_5_sample *__pyx_cur_scope;
+  PyObject *__pyx_r = NULL;
+  __Pyx_RefNannyDeclarations
+  int __pyx_lineno = 0;
+  const char *__pyx_filename = NULL;
+  int __pyx_clineno = 0;
+  __Pyx_RefNannySetupContext("sample", 0);
+  __pyx_cur_scope = (struct __pyx_obj_5_cdec___pyx_scope_struct_5_sample *)__pyx_ptype_5_cdec___pyx_scope_struct_5_sample->tp_new(__pyx_ptype_5_cdec___pyx_scope_struct_5_sample, __pyx_empty_tuple, NULL);
+  if (unlikely(!__pyx_cur_scope)) {
+    __Pyx_RefNannyFinishContext();
+    return NULL;
+  }
+  __Pyx_GOTREF(__pyx_cur_scope);
+  __pyx_cur_scope->__pyx_v_self = __pyx_v_self;
+  __Pyx_INCREF((PyObject *)__pyx_cur_scope->__pyx_v_self);
+  __Pyx_GIVEREF((PyObject *)__pyx_cur_scope->__pyx_v_self);
+  __pyx_cur_scope->__pyx_v_n = __pyx_v_n;
+  {
+    __pyx_GeneratorObject *gen = __Pyx_Generator_New((__pyx_generator_body_t) __pyx_gb_5_cdec_10Hypergraph_21generator5, (PyObject *) __pyx_cur_scope); if (unlikely(!gen)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 69; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_DECREF(__pyx_cur_scope);
+    __Pyx_RefNannyFinishContext();
+    return (PyObject *) gen;
+  }
+
+  __pyx_r = Py_None; __Pyx_INCREF(Py_None);
+  goto __pyx_L0;
+  __pyx_L1_error:;
+  __Pyx_AddTraceback("_cdec.Hypergraph.sample", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __pyx_r = NULL;
+  __pyx_L0:;
+  __Pyx_DECREF(((PyObject *)__pyx_cur_scope));
+  __Pyx_XGIVEREF(__pyx_r);
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+static PyObject *__pyx_gb_5_cdec_10Hypergraph_21generator5(__pyx_GeneratorObject *__pyx_generator, PyObject *__pyx_sent_value) /* generator body */
+{
+  struct __pyx_obj_5_cdec___pyx_scope_struct_5_sample *__pyx_cur_scope = ((struct __pyx_obj_5_cdec___pyx_scope_struct_5_sample *)__pyx_generator->closure);
+  PyObject *__pyx_r = NULL;
+  int __pyx_t_1;
+  size_t __pyx_t_2;
+  unsigned int __pyx_t_3;
+  PyObject *__pyx_t_4 = NULL;
+  PyObject *__pyx_t_5 = NULL;
+  __Pyx_RefNannyDeclarations
+  __Pyx_RefNannySetupContext("None", 0);
+  switch (__pyx_generator->resume_label) {
+    case 0: goto __pyx_L3_first_run;
+    case 1: goto __pyx_L7_resume_from_yield;
+    default: /* CPython raises the right error here */
+    __Pyx_RefNannyFinishContext();
+    return NULL;
+  }
+  __pyx_L3_first_run:;
+  if (unlikely(!__pyx_sent_value)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 69; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":70
+ * 
+ *     def sample(self, unsigned n):
+ *         cdef vector[hypergraph.Hypothesis]* hypos = new vector[hypergraph.Hypothesis]()             # <<<<<<<<<<<<<<
+ *         if self.rng == NULL:
+ *             self.rng = new MT19937()
+ */
+  __pyx_cur_scope->__pyx_v_hypos = new std::vector<HypergraphSampler::Hypothesis>();
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":71
+ *     def sample(self, unsigned n):
+ *         cdef vector[hypergraph.Hypothesis]* hypos = new vector[hypergraph.Hypothesis]()
+ *         if self.rng == NULL:             # <<<<<<<<<<<<<<
+ *             self.rng = new MT19937()
+ *         hypergraph.sample_hypotheses(self.hg[0], n, self.rng, hypos)
+ */
+  __pyx_t_1 = (__pyx_cur_scope->__pyx_v_self->rng == NULL);
+  if (__pyx_t_1) {
+
+    /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":72
+ *         cdef vector[hypergraph.Hypothesis]* hypos = new vector[hypergraph.Hypothesis]()
+ *         if self.rng == NULL:
+ *             self.rng = new MT19937()             # <<<<<<<<<<<<<<
+ *         hypergraph.sample_hypotheses(self.hg[0], n, self.rng, hypos)
+ *         cdef str sentence
+ */
+    __pyx_cur_scope->__pyx_v_self->rng = new MT19937();
+    goto __pyx_L4;
+  }
+  __pyx_L4:;
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":73
+ *         if self.rng == NULL:
+ *             self.rng = new MT19937()
+ *         hypergraph.sample_hypotheses(self.hg[0], n, self.rng, hypos)             # <<<<<<<<<<<<<<
+ *         cdef str sentence
+ *         cdef unsigned k
+ */
+  HypergraphSampler::sample_hypotheses((__pyx_cur_scope->__pyx_v_self->hg[0]), __pyx_cur_scope->__pyx_v_n, __pyx_cur_scope->__pyx_v_self->rng, __pyx_cur_scope->__pyx_v_hypos);
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":76
+ *         cdef str sentence
+ *         cdef unsigned k
+ *         for k in range(hypos.size()):             # <<<<<<<<<<<<<<
+ *             sentence = GetString(hypos[0][k].words).c_str()
+ *             yield sentence.decode('utf8')
+ */
+  __pyx_t_2 = __pyx_cur_scope->__pyx_v_hypos->size();
+  for (__pyx_t_3 = 0; __pyx_t_3 < __pyx_t_2; __pyx_t_3+=1) {
+    __pyx_cur_scope->__pyx_v_k = __pyx_t_3;
+
+    /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":77
+ *         cdef unsigned k
+ *         for k in range(hypos.size()):
+ *             sentence = GetString(hypos[0][k].words).c_str()             # <<<<<<<<<<<<<<
+ *             yield sentence.decode('utf8')
+ *         del hypos
+ */
+    __pyx_t_4 = PyBytes_FromString(TD::GetString(((__pyx_cur_scope->__pyx_v_hypos[0])[__pyx_cur_scope->__pyx_v_k]).words).c_str()); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 77; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(((PyObject *)__pyx_t_4));
+    if (!(likely(PyString_CheckExact(((PyObject *)__pyx_t_4)))||(PyErr_Format(PyExc_TypeError, "Expected str, got %.200s", Py_TYPE(((PyObject *)__pyx_t_4))->tp_name), 0))) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 77; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_XGOTREF(((PyObject *)__pyx_cur_scope->__pyx_v_sentence));
+    __Pyx_XDECREF(((PyObject *)__pyx_cur_scope->__pyx_v_sentence));
+    __Pyx_GIVEREF(((PyObject *)__pyx_t_4));
+    __pyx_cur_scope->__pyx_v_sentence = ((PyObject*)__pyx_t_4);
+    __pyx_t_4 = 0;
+
+    /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":78
+ *         for k in range(hypos.size()):
+ *             sentence = GetString(hypos[0][k].words).c_str()
+ *             yield sentence.decode('utf8')             # <<<<<<<<<<<<<<
+ *         del hypos
+ * 
+ */
+    __pyx_t_4 = PyObject_GetAttr(((PyObject *)__pyx_cur_scope->__pyx_v_sentence), __pyx_n_s__decode); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 78; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_4);
+    __pyx_t_5 = PyObject_Call(__pyx_t_4, ((PyObject *)__pyx_k_tuple_9), NULL); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 78; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_5);
+    __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
+    __pyx_r = __pyx_t_5;
+    __pyx_t_5 = 0;
+    __pyx_cur_scope->__pyx_t_0 = __pyx_t_2;
+    __pyx_cur_scope->__pyx_t_1 = __pyx_t_3;
+    __Pyx_XGIVEREF(__pyx_r);
+    __Pyx_RefNannyFinishContext();
+    /* return from generator, yielding value */
+    __pyx_generator->resume_label = 1;
+    return __pyx_r;
+    __pyx_L7_resume_from_yield:;
+    __pyx_t_2 = __pyx_cur_scope->__pyx_t_0;
+    __pyx_t_3 = __pyx_cur_scope->__pyx_t_1;
+    if (unlikely(!__pyx_sent_value)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 78; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  }
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":66
+  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":79
  *             sentence = GetString(hypos[0][k].words).c_str()
  *             yield sentence.decode('utf8')
  *         del hypos             # <<<<<<<<<<<<<<
@@ -3558,13 +4181,13 @@ static PyObject *__pyx_gb_5_cdec_10Hypergraph_18generator4(__pyx_GeneratorObject
 }
 
 /* Python wrapper */
-static PyObject *__pyx_pw_5_cdec_10Hypergraph_20intersect(PyObject *__pyx_v_self, PyObject *__pyx_v_lat); /*proto*/
-static PyObject *__pyx_pw_5_cdec_10Hypergraph_20intersect(PyObject *__pyx_v_self, PyObject *__pyx_v_lat) {
+static PyObject *__pyx_pw_5_cdec_10Hypergraph_23intersect(PyObject *__pyx_v_self, PyObject *__pyx_v_lat); /*proto*/
+static PyObject *__pyx_pw_5_cdec_10Hypergraph_23intersect(PyObject *__pyx_v_self, PyObject *__pyx_v_lat) {
   PyObject *__pyx_r = 0;
   __Pyx_RefNannyDeclarations
   __Pyx_RefNannySetupContext("intersect (wrapper)", 0);
-  if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_lat), __pyx_ptype_5_cdec_Lattice, 1, "lat", 0))) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 70; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __pyx_r = __pyx_pf_5_cdec_10Hypergraph_19intersect(((struct __pyx_obj_5_cdec_Hypergraph *)__pyx_v_self), ((struct __pyx_obj_5_cdec_Lattice *)__pyx_v_lat));
+  if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_lat), __pyx_ptype_5_cdec_Lattice, 1, "lat", 0))) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 83; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_r = __pyx_pf_5_cdec_10Hypergraph_22intersect(((struct __pyx_obj_5_cdec_Hypergraph *)__pyx_v_self), ((struct __pyx_obj_5_cdec_Lattice *)__pyx_v_lat));
   goto __pyx_L0;
   __pyx_L1_error:;
   __pyx_r = NULL;
@@ -3573,7 +4196,7 @@ static PyObject *__pyx_pw_5_cdec_10Hypergraph_20intersect(PyObject *__pyx_v_self
   return __pyx_r;
 }
 
-/* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":70
+/* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":83
  *     # TODO richer k-best/sample output (feature vectors, trees?)
  * 
  *     def intersect(self, Lattice lat):             # <<<<<<<<<<<<<<
@@ -3581,7 +4204,7 @@ static PyObject *__pyx_pw_5_cdec_10Hypergraph_20intersect(PyObject *__pyx_v_self
  * 
  */
 
-static PyObject *__pyx_pf_5_cdec_10Hypergraph_19intersect(struct __pyx_obj_5_cdec_Hypergraph *__pyx_v_self, struct __pyx_obj_5_cdec_Lattice *__pyx_v_lat) {
+static PyObject *__pyx_pf_5_cdec_10Hypergraph_22intersect(struct __pyx_obj_5_cdec_Hypergraph *__pyx_v_self, struct __pyx_obj_5_cdec_Lattice *__pyx_v_lat) {
   PyObject *__pyx_r = NULL;
   __Pyx_RefNannyDeclarations
   PyObject *__pyx_t_1 = NULL;
@@ -3590,7 +4213,7 @@ static PyObject *__pyx_pf_5_cdec_10Hypergraph_19intersect(struct __pyx_obj_5_cde
   int __pyx_clineno = 0;
   __Pyx_RefNannySetupContext("intersect", 0);
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":71
+  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":84
  * 
  *     def intersect(self, Lattice lat):
  *         return hypergraph.Intersect(lat.lattice[0], self.hg)             # <<<<<<<<<<<<<<
@@ -3598,7 +4221,7 @@ static PyObject *__pyx_pf_5_cdec_10Hypergraph_19intersect(struct __pyx_obj_5_cde
  *     def prune(self, beam_alpha=0, density=0, **kwargs):
  */
   __Pyx_XDECREF(__pyx_r);
-  __pyx_t_1 = __Pyx_PyBool_FromLong(HG::Intersect((__pyx_v_lat->lattice[0]), __pyx_v_self->hg)); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 71; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_1 = __Pyx_PyBool_FromLong(HG::Intersect((__pyx_v_lat->lattice[0]), __pyx_v_self->hg)); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 84; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __Pyx_GOTREF(__pyx_t_1);
   __pyx_r = __pyx_t_1;
   __pyx_t_1 = 0;
@@ -3617,8 +4240,8 @@ static PyObject *__pyx_pf_5_cdec_10Hypergraph_19intersect(struct __pyx_obj_5_cde
 }
 
 /* Python wrapper */
-static PyObject *__pyx_pw_5_cdec_10Hypergraph_22prune(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/
-static PyObject *__pyx_pw_5_cdec_10Hypergraph_22prune(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) {
+static PyObject *__pyx_pw_5_cdec_10Hypergraph_25prune(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/
+static PyObject *__pyx_pw_5_cdec_10Hypergraph_25prune(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) {
   PyObject *__pyx_v_beam_alpha = 0;
   PyObject *__pyx_v_density = 0;
   PyObject *__pyx_v_kwargs = 0;
@@ -3655,7 +4278,7 @@ static PyObject *__pyx_pw_5_cdec_10Hypergraph_22prune(PyObject *__pyx_v_self, Py
         }
       }
       if (unlikely(kw_args > 0)) {
-        if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, __pyx_v_kwargs, values, pos_args, "prune") < 0)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 73; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+        if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, __pyx_v_kwargs, values, pos_args, "prune") < 0)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 86; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
       }
     } else {
       switch (PyTuple_GET_SIZE(__pyx_args)) {
@@ -3670,20 +4293,20 @@ static PyObject *__pyx_pw_5_cdec_10Hypergraph_22prune(PyObject *__pyx_v_self, Py
   }
   goto __pyx_L4_argument_unpacking_done;
   __pyx_L5_argtuple_error:;
-  __Pyx_RaiseArgtupleInvalid("prune", 0, 0, 2, PyTuple_GET_SIZE(__pyx_args)); {__pyx_filename = __pyx_f[2]; __pyx_lineno = 73; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+  __Pyx_RaiseArgtupleInvalid("prune", 0, 0, 2, PyTuple_GET_SIZE(__pyx_args)); {__pyx_filename = __pyx_f[2]; __pyx_lineno = 86; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
   __pyx_L3_error:;
   __Pyx_DECREF(__pyx_v_kwargs); __pyx_v_kwargs = 0;
   __Pyx_AddTraceback("_cdec.Hypergraph.prune", __pyx_clineno, __pyx_lineno, __pyx_filename);
   __Pyx_RefNannyFinishContext();
   return NULL;
   __pyx_L4_argument_unpacking_done:;
-  __pyx_r = __pyx_pf_5_cdec_10Hypergraph_21prune(((struct __pyx_obj_5_cdec_Hypergraph *)__pyx_v_self), __pyx_v_beam_alpha, __pyx_v_density, __pyx_v_kwargs);
+  __pyx_r = __pyx_pf_5_cdec_10Hypergraph_24prune(((struct __pyx_obj_5_cdec_Hypergraph *)__pyx_v_self), __pyx_v_beam_alpha, __pyx_v_density, __pyx_v_kwargs);
   __Pyx_XDECREF(__pyx_v_kwargs);
   __Pyx_RefNannyFinishContext();
   return __pyx_r;
 }
 
-/* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":73
+/* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":86
  *         return hypergraph.Intersect(lat.lattice[0], self.hg)
  * 
  *     def prune(self, beam_alpha=0, density=0, **kwargs):             # <<<<<<<<<<<<<<
@@ -3691,7 +4314,7 @@ static PyObject *__pyx_pw_5_cdec_10Hypergraph_22prune(PyObject *__pyx_v_self, Py
  *         if 'csplit_preserve_full_word' in kwargs:
  */
 
-static PyObject *__pyx_pf_5_cdec_10Hypergraph_21prune(struct __pyx_obj_5_cdec_Hypergraph *__pyx_v_self, PyObject *__pyx_v_beam_alpha, PyObject *__pyx_v_density, PyObject *__pyx_v_kwargs) {
+static PyObject *__pyx_pf_5_cdec_10Hypergraph_24prune(struct __pyx_obj_5_cdec_Hypergraph *__pyx_v_self, PyObject *__pyx_v_beam_alpha, PyObject *__pyx_v_density, PyObject *__pyx_v_kwargs) {
   std::vector<bool> *__pyx_v_preserve_mask;
   PyObject *__pyx_r = NULL;
   __Pyx_RefNannyDeclarations
@@ -3703,7 +4326,7 @@ static PyObject *__pyx_pf_5_cdec_10Hypergraph_21prune(struct __pyx_obj_5_cdec_Hy
   int __pyx_clineno = 0;
   __Pyx_RefNannySetupContext("prune", 0);
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":74
+  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":87
  * 
  *     def prune(self, beam_alpha=0, density=0, **kwargs):
  *         cdef hypergraph.EdgeMask* preserve_mask = NULL             # <<<<<<<<<<<<<<
@@ -3712,17 +4335,17 @@ static PyObject *__pyx_pf_5_cdec_10Hypergraph_21prune(struct __pyx_obj_5_cdec_Hy
  */
   __pyx_v_preserve_mask = NULL;
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":75
+  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":88
  *     def prune(self, beam_alpha=0, density=0, **kwargs):
  *         cdef hypergraph.EdgeMask* preserve_mask = NULL
  *         if 'csplit_preserve_full_word' in kwargs:             # <<<<<<<<<<<<<<
  *              preserve_mask = new hypergraph.EdgeMask(self.hg.edges_.size())
  *              preserve_mask[0][hypergraph.GetFullWordEdgeIndex(self.hg[0])] = True
  */
-  __pyx_t_1 = ((PyDict_Contains(((PyObject *)__pyx_v_kwargs), ((PyObject *)__pyx_n_s_10)))); if (unlikely(__pyx_t_1 < 0)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 75; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_1 = ((PyDict_Contains(((PyObject *)__pyx_v_kwargs), ((PyObject *)__pyx_n_s_10)))); if (unlikely(__pyx_t_1 < 0)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 88; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   if (__pyx_t_1) {
 
-    /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":76
+    /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":89
  *         cdef hypergraph.EdgeMask* preserve_mask = NULL
  *         if 'csplit_preserve_full_word' in kwargs:
  *              preserve_mask = new hypergraph.EdgeMask(self.hg.edges_.size())             # <<<<<<<<<<<<<<
@@ -3731,7 +4354,7 @@ static PyObject *__pyx_pf_5_cdec_10Hypergraph_21prune(struct __pyx_obj_5_cdec_Hy
  */
     __pyx_v_preserve_mask = new std::vector<bool>(__pyx_v_self->hg->edges_.size());
 
-    /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":77
+    /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":90
  *         if 'csplit_preserve_full_word' in kwargs:
  *              preserve_mask = new hypergraph.EdgeMask(self.hg.edges_.size())
  *              preserve_mask[0][hypergraph.GetFullWordEdgeIndex(self.hg[0])] = True             # <<<<<<<<<<<<<<
@@ -3743,15 +4366,15 @@ static PyObject *__pyx_pf_5_cdec_10Hypergraph_21prune(struct __pyx_obj_5_cdec_Hy
   }
   __pyx_L3:;
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":78
+  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":91
  *              preserve_mask = new hypergraph.EdgeMask(self.hg.edges_.size())
  *              preserve_mask[0][hypergraph.GetFullWordEdgeIndex(self.hg[0])] = True
  *         self.hg.PruneInsideOutside(beam_alpha, density, preserve_mask, False, 1, False)             # <<<<<<<<<<<<<<
  * 
  *     def lattice(self): # TODO direct hg -> lattice conversion in cdec
  */
-  __pyx_t_2 = __pyx_PyFloat_AsDouble(__pyx_v_beam_alpha); if (unlikely((__pyx_t_2 == (double)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 78; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __pyx_t_3 = __pyx_PyFloat_AsDouble(__pyx_v_density); if (unlikely((__pyx_t_3 == (double)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 78; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_2 = __pyx_PyFloat_AsDouble(__pyx_v_beam_alpha); if (unlikely((__pyx_t_2 == (double)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 91; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_3 = __pyx_PyFloat_AsDouble(__pyx_v_density); if (unlikely((__pyx_t_3 == (double)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 91; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __pyx_v_self->hg->PruneInsideOutside(__pyx_t_2, __pyx_t_3, __pyx_v_preserve_mask, 0, 1.0, 0);
 
   __pyx_r = Py_None; __Pyx_INCREF(Py_None);
@@ -3766,17 +4389,17 @@ static PyObject *__pyx_pf_5_cdec_10Hypergraph_21prune(struct __pyx_obj_5_cdec_Hy
 }
 
 /* Python wrapper */
-static PyObject *__pyx_pw_5_cdec_10Hypergraph_24lattice(PyObject *__pyx_v_self, CYTHON_UNUSED PyObject *unused); /*proto*/
-static PyObject *__pyx_pw_5_cdec_10Hypergraph_24lattice(PyObject *__pyx_v_self, CYTHON_UNUSED PyObject *unused) {
+static PyObject *__pyx_pw_5_cdec_10Hypergraph_27lattice(PyObject *__pyx_v_self, CYTHON_UNUSED PyObject *unused); /*proto*/
+static PyObject *__pyx_pw_5_cdec_10Hypergraph_27lattice(PyObject *__pyx_v_self, CYTHON_UNUSED PyObject *unused) {
   PyObject *__pyx_r = 0;
   __Pyx_RefNannyDeclarations
   __Pyx_RefNannySetupContext("lattice (wrapper)", 0);
-  __pyx_r = __pyx_pf_5_cdec_10Hypergraph_23lattice(((struct __pyx_obj_5_cdec_Hypergraph *)__pyx_v_self));
+  __pyx_r = __pyx_pf_5_cdec_10Hypergraph_26lattice(((struct __pyx_obj_5_cdec_Hypergraph *)__pyx_v_self));
   __Pyx_RefNannyFinishContext();
   return __pyx_r;
 }
 
-/* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":80
+/* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":93
  *         self.hg.PruneInsideOutside(beam_alpha, density, preserve_mask, False, 1, False)
  * 
  *     def lattice(self): # TODO direct hg -> lattice conversion in cdec             # <<<<<<<<<<<<<<
@@ -3784,7 +4407,7 @@ static PyObject *__pyx_pw_5_cdec_10Hypergraph_24lattice(PyObject *__pyx_v_self,
  *         return Lattice(eval(plf))
  */
 
-static PyObject *__pyx_pf_5_cdec_10Hypergraph_23lattice(struct __pyx_obj_5_cdec_Hypergraph *__pyx_v_self) {
+static PyObject *__pyx_pf_5_cdec_10Hypergraph_26lattice(struct __pyx_obj_5_cdec_Hypergraph *__pyx_v_self) {
   PyObject *__pyx_v_plf = 0;
   PyObject *__pyx_r = NULL;
   __Pyx_RefNannyDeclarations
@@ -3796,20 +4419,20 @@ static PyObject *__pyx_pf_5_cdec_10Hypergraph_23lattice(struct __pyx_obj_5_cdec_
   int __pyx_clineno = 0;
   __Pyx_RefNannySetupContext("lattice", 0);
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":81
+  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":94
  * 
  *     def lattice(self): # TODO direct hg -> lattice conversion in cdec
  *         cdef str plf = hypergraph.AsPLF(self.hg[0], True).c_str()             # <<<<<<<<<<<<<<
  *         return Lattice(eval(plf))
  * 
  */
-  __pyx_t_1 = PyBytes_FromString(HypergraphIO::AsPLF((__pyx_v_self->hg[0]), 1).c_str()); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 81; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_1 = PyBytes_FromString(HypergraphIO::AsPLF((__pyx_v_self->hg[0]), 1).c_str()); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 94; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __Pyx_GOTREF(((PyObject *)__pyx_t_1));
-  if (!(likely(PyString_CheckExact(((PyObject *)__pyx_t_1)))||(PyErr_Format(PyExc_TypeError, "Expected str, got %.200s", Py_TYPE(((PyObject *)__pyx_t_1))->tp_name), 0))) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 81; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (!(likely(PyString_CheckExact(((PyObject *)__pyx_t_1)))||(PyErr_Format(PyExc_TypeError, "Expected str, got %.200s", Py_TYPE(((PyObject *)__pyx_t_1))->tp_name), 0))) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 94; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __pyx_v_plf = ((PyObject*)__pyx_t_1);
   __pyx_t_1 = 0;
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":82
+  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":95
  *     def lattice(self): # TODO direct hg -> lattice conversion in cdec
  *         cdef str plf = hypergraph.AsPLF(self.hg[0], True).c_str()
  *         return Lattice(eval(plf))             # <<<<<<<<<<<<<<
@@ -3817,17 +4440,17 @@ static PyObject *__pyx_pf_5_cdec_10Hypergraph_23lattice(struct __pyx_obj_5_cdec_
  *     def reweight(self, weights):
  */
   __Pyx_XDECREF(__pyx_r);
-  __pyx_t_1 = __Pyx_Globals(); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 82; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_1 = __Pyx_Globals(); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 95; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __Pyx_GOTREF(__pyx_t_1);
-  __pyx_t_2 = PyDict_New(); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 82; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_2 = PyDict_New(); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 95; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __Pyx_GOTREF(((PyObject *)__pyx_t_2));
   if (((PyObject *)__pyx_v_plf)) {
-    if (PyDict_SetItem(__pyx_t_2, ((PyObject *)__pyx_n_s__plf), ((PyObject *)__pyx_v_plf)) < 0) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 82; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    if (PyDict_SetItem(__pyx_t_2, ((PyObject *)__pyx_n_s__plf), ((PyObject *)__pyx_v_plf)) < 0) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 95; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   }
   if (((PyObject *)__pyx_v_self)) {
-    if (PyDict_SetItem(__pyx_t_2, ((PyObject *)__pyx_n_s__self), ((PyObject *)__pyx_v_self)) < 0) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 82; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    if (PyDict_SetItem(__pyx_t_2, ((PyObject *)__pyx_n_s__self), ((PyObject *)__pyx_v_self)) < 0) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 95; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   }
-  __pyx_t_3 = PyTuple_New(3); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 82; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_3 = PyTuple_New(3); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 95; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __Pyx_GOTREF(__pyx_t_3);
   __Pyx_INCREF(((PyObject *)__pyx_v_plf));
   PyTuple_SET_ITEM(__pyx_t_3, 0, ((PyObject *)__pyx_v_plf));
@@ -3838,15 +4461,15 @@ static PyObject *__pyx_pf_5_cdec_10Hypergraph_23lattice(struct __pyx_obj_5_cdec_
   __Pyx_GIVEREF(((PyObject *)__pyx_t_2));
   __pyx_t_1 = 0;
   __pyx_t_2 = 0;
-  __pyx_t_2 = PyObject_Call(__pyx_builtin_eval, ((PyObject *)__pyx_t_3), NULL); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 82; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_2 = PyObject_Call(__pyx_builtin_eval, ((PyObject *)__pyx_t_3), NULL); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 95; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __Pyx_GOTREF(__pyx_t_2);
   __Pyx_DECREF(((PyObject *)__pyx_t_3)); __pyx_t_3 = 0;
-  __pyx_t_3 = PyTuple_New(1); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 82; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_3 = PyTuple_New(1); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 95; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __Pyx_GOTREF(__pyx_t_3);
   PyTuple_SET_ITEM(__pyx_t_3, 0, __pyx_t_2);
   __Pyx_GIVEREF(__pyx_t_2);
   __pyx_t_2 = 0;
-  __pyx_t_2 = PyObject_Call(((PyObject *)((PyObject*)__pyx_ptype_5_cdec_Lattice)), ((PyObject *)__pyx_t_3), NULL); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 82; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_2 = PyObject_Call(((PyObject *)((PyObject*)__pyx_ptype_5_cdec_Lattice)), ((PyObject *)__pyx_t_3), NULL); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 95; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __Pyx_GOTREF(__pyx_t_2);
   __Pyx_DECREF(((PyObject *)__pyx_t_3)); __pyx_t_3 = 0;
   __pyx_r = __pyx_t_2;
@@ -3869,17 +4492,17 @@ static PyObject *__pyx_pf_5_cdec_10Hypergraph_23lattice(struct __pyx_obj_5_cdec_
 }
 
 /* Python wrapper */
-static PyObject *__pyx_pw_5_cdec_10Hypergraph_26reweight(PyObject *__pyx_v_self, PyObject *__pyx_v_weights); /*proto*/
-static PyObject *__pyx_pw_5_cdec_10Hypergraph_26reweight(PyObject *__pyx_v_self, PyObject *__pyx_v_weights) {
+static PyObject *__pyx_pw_5_cdec_10Hypergraph_29reweight(PyObject *__pyx_v_self, PyObject *__pyx_v_weights); /*proto*/
+static PyObject *__pyx_pw_5_cdec_10Hypergraph_29reweight(PyObject *__pyx_v_self, PyObject *__pyx_v_weights) {
   PyObject *__pyx_r = 0;
   __Pyx_RefNannyDeclarations
   __Pyx_RefNannySetupContext("reweight (wrapper)", 0);
-  __pyx_r = __pyx_pf_5_cdec_10Hypergraph_25reweight(((struct __pyx_obj_5_cdec_Hypergraph *)__pyx_v_self), ((PyObject *)__pyx_v_weights));
+  __pyx_r = __pyx_pf_5_cdec_10Hypergraph_28reweight(((struct __pyx_obj_5_cdec_Hypergraph *)__pyx_v_self), ((PyObject *)__pyx_v_weights));
   __Pyx_RefNannyFinishContext();
   return __pyx_r;
 }
 
-/* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":84
+/* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":97
  *         return Lattice(eval(plf))
  * 
  *     def reweight(self, weights):             # <<<<<<<<<<<<<<
@@ -3887,7 +4510,7 @@ static PyObject *__pyx_pw_5_cdec_10Hypergraph_26reweight(PyObject *__pyx_v_self,
  *             self.hg.Reweight((<SparseVector> weights).vector[0])
  */
 
-static PyObject *__pyx_pf_5_cdec_10Hypergraph_25reweight(struct __pyx_obj_5_cdec_Hypergraph *__pyx_v_self, PyObject *__pyx_v_weights) {
+static PyObject *__pyx_pf_5_cdec_10Hypergraph_28reweight(struct __pyx_obj_5_cdec_Hypergraph *__pyx_v_self, PyObject *__pyx_v_weights) {
   PyObject *__pyx_r = NULL;
   __Pyx_RefNannyDeclarations
   PyObject *__pyx_t_1 = NULL;
@@ -3898,7 +4521,7 @@ static PyObject *__pyx_pf_5_cdec_10Hypergraph_25reweight(struct __pyx_obj_5_cdec
   int __pyx_clineno = 0;
   __Pyx_RefNannySetupContext("reweight", 0);
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":85
+  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":98
  * 
  *     def reweight(self, weights):
  *         if isinstance(weights, SparseVector):             # <<<<<<<<<<<<<<
@@ -3911,7 +4534,7 @@ static PyObject *__pyx_pf_5_cdec_10Hypergraph_25reweight(struct __pyx_obj_5_cdec
   __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
   if (__pyx_t_2) {
 
-    /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":86
+    /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":99
  *     def reweight(self, weights):
  *         if isinstance(weights, SparseVector):
  *             self.hg.Reweight((<SparseVector> weights).vector[0])             # <<<<<<<<<<<<<<
@@ -3922,7 +4545,7 @@ static PyObject *__pyx_pf_5_cdec_10Hypergraph_25reweight(struct __pyx_obj_5_cdec
     goto __pyx_L3;
   }
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":87
+  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":100
  *         if isinstance(weights, SparseVector):
  *             self.hg.Reweight((<SparseVector> weights).vector[0])
  *         elif isinstance(weights, DenseVector):             # <<<<<<<<<<<<<<
@@ -3935,38 +4558,38 @@ static PyObject *__pyx_pf_5_cdec_10Hypergraph_25reweight(struct __pyx_obj_5_cdec
   __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
   if (__pyx_t_2) {
 
-    /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":88
+    /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":101
  *             self.hg.Reweight((<SparseVector> weights).vector[0])
  *         elif isinstance(weights, DenseVector):
  *             self.hg.Reweight((<DenseVector> weights).vector[0])             # <<<<<<<<<<<<<<
  *         else:
- *             raise ValueError('cannot reweight hypergraph with %s' % type(weights))
+ *             raise TypeError('cannot reweight hypergraph with %s' % type(weights))
  */
     __pyx_v_self->hg->Reweight((((struct __pyx_obj_5_cdec_DenseVector *)__pyx_v_weights)->vector[0]));
     goto __pyx_L3;
   }
   /*else*/ {
 
-    /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":90
+    /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":103
  *             self.hg.Reweight((<DenseVector> weights).vector[0])
  *         else:
- *             raise ValueError('cannot reweight hypergraph with %s' % type(weights))             # <<<<<<<<<<<<<<
+ *             raise TypeError('cannot reweight hypergraph with %s' % type(weights))             # <<<<<<<<<<<<<<
  * 
  *     # TODO get feature expectations, get partition function ("inside" score)
  */
-    __pyx_t_1 = PyNumber_Remainder(((PyObject *)__pyx_kp_s_11), ((PyObject *)Py_TYPE(__pyx_v_weights))); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 90; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_t_1 = PyNumber_Remainder(((PyObject *)__pyx_kp_s_11), ((PyObject *)Py_TYPE(__pyx_v_weights))); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 103; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
     __Pyx_GOTREF(((PyObject *)__pyx_t_1));
-    __pyx_t_3 = PyTuple_New(1); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 90; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_t_3 = PyTuple_New(1); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 103; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
     __Pyx_GOTREF(__pyx_t_3);
     PyTuple_SET_ITEM(__pyx_t_3, 0, ((PyObject *)__pyx_t_1));
     __Pyx_GIVEREF(((PyObject *)__pyx_t_1));
     __pyx_t_1 = 0;
-    __pyx_t_1 = PyObject_Call(__pyx_builtin_ValueError, ((PyObject *)__pyx_t_3), NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 90; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_t_1 = PyObject_Call(__pyx_builtin_TypeError, ((PyObject *)__pyx_t_3), NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 103; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
     __Pyx_GOTREF(__pyx_t_1);
     __Pyx_DECREF(((PyObject *)__pyx_t_3)); __pyx_t_3 = 0;
     __Pyx_Raise(__pyx_t_1, 0, 0, 0);
     __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
-    {__pyx_filename = __pyx_f[2]; __pyx_lineno = 90; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    {__pyx_filename = __pyx_f[2]; __pyx_lineno = 103; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   }
   __pyx_L3:;
 
@@ -4787,7 +5410,7 @@ static PyObject *__pyx_pf_5_cdec_7Lattice_8__str__(struct __pyx_obj_5_cdec_Latti
   __Pyx_RefNannyFinishContext();
   return __pyx_r;
 }
-static PyObject *__pyx_gb_5_cdec_7Lattice_12generator5(__pyx_GeneratorObject *__pyx_generator, PyObject *__pyx_sent_value); /* proto */
+static PyObject *__pyx_gb_5_cdec_7Lattice_12generator6(__pyx_GeneratorObject *__pyx_generator, PyObject *__pyx_sent_value); /* proto */
 
 /* Python wrapper */
 static PyObject *__pyx_pw_5_cdec_7Lattice_11__iter__(PyObject *__pyx_v_self); /*proto*/
@@ -4809,14 +5432,14 @@ static PyObject *__pyx_pw_5_cdec_7Lattice_11__iter__(PyObject *__pyx_v_self) {
  */
 
 static PyObject *__pyx_pf_5_cdec_7Lattice_10__iter__(struct __pyx_obj_5_cdec_Lattice *__pyx_v_self) {
-  struct __pyx_obj_5_cdec___pyx_scope_struct_5___iter__ *__pyx_cur_scope;
+  struct __pyx_obj_5_cdec___pyx_scope_struct_6___iter__ *__pyx_cur_scope;
   PyObject *__pyx_r = NULL;
   __Pyx_RefNannyDeclarations
   int __pyx_lineno = 0;
   const char *__pyx_filename = NULL;
   int __pyx_clineno = 0;
   __Pyx_RefNannySetupContext("__iter__", 0);
-  __pyx_cur_scope = (struct __pyx_obj_5_cdec___pyx_scope_struct_5___iter__ *)__pyx_ptype_5_cdec___pyx_scope_struct_5___iter__->tp_new(__pyx_ptype_5_cdec___pyx_scope_struct_5___iter__, __pyx_empty_tuple, NULL);
+  __pyx_cur_scope = (struct __pyx_obj_5_cdec___pyx_scope_struct_6___iter__ *)__pyx_ptype_5_cdec___pyx_scope_struct_6___iter__->tp_new(__pyx_ptype_5_cdec___pyx_scope_struct_6___iter__, __pyx_empty_tuple, NULL);
   if (unlikely(!__pyx_cur_scope)) {
     __Pyx_RefNannyFinishContext();
     return NULL;
@@ -4826,7 +5449,7 @@ static PyObject *__pyx_pf_5_cdec_7Lattice_10__iter__(struct __pyx_obj_5_cdec_Lat
   __Pyx_INCREF((PyObject *)__pyx_cur_scope->__pyx_v_self);
   __Pyx_GIVEREF((PyObject *)__pyx_cur_scope->__pyx_v_self);
   {
-    __pyx_GeneratorObject *gen = __Pyx_Generator_New((__pyx_generator_body_t) __pyx_gb_5_cdec_7Lattice_12generator5, (PyObject *) __pyx_cur_scope); if (unlikely(!gen)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 50; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_GeneratorObject *gen = __Pyx_Generator_New((__pyx_generator_body_t) __pyx_gb_5_cdec_7Lattice_12generator6, (PyObject *) __pyx_cur_scope); if (unlikely(!gen)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 50; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
     __Pyx_DECREF(__pyx_cur_scope);
     __Pyx_RefNannyFinishContext();
     return (PyObject *) gen;
@@ -4844,9 +5467,9 @@ static PyObject *__pyx_pf_5_cdec_7Lattice_10__iter__(struct __pyx_obj_5_cdec_Lat
   return __pyx_r;
 }
 
-static PyObject *__pyx_gb_5_cdec_7Lattice_12generator5(__pyx_GeneratorObject *__pyx_generator, PyObject *__pyx_sent_value) /* generator body */
+static PyObject *__pyx_gb_5_cdec_7Lattice_12generator6(__pyx_GeneratorObject *__pyx_generator, PyObject *__pyx_sent_value) /* generator body */
 {
-  struct __pyx_obj_5_cdec___pyx_scope_struct_5___iter__ *__pyx_cur_scope = ((struct __pyx_obj_5_cdec___pyx_scope_struct_5___iter__ *)__pyx_generator->closure);
+  struct __pyx_obj_5_cdec___pyx_scope_struct_6___iter__ *__pyx_cur_scope = ((struct __pyx_obj_5_cdec___pyx_scope_struct_6___iter__ *)__pyx_generator->closure);
   PyObject *__pyx_r = NULL;
   Py_ssize_t __pyx_t_1;
   unsigned int __pyx_t_2;
@@ -4939,839 +5562,496 @@ static void __pyx_pf_5_cdec_7Lattice_13__dealloc__(CYTHON_UNUSED struct __pyx_ob
   __Pyx_RefNannyFinishContext();
 }
 
-/* Python wrapper */
-static int __pyx_pw_5_cdec_7Decoder_1__cinit__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/
-static int __pyx_pw_5_cdec_7Decoder_1__cinit__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) {
-  char *__pyx_v_config;
-  static PyObject **__pyx_pyargnames[] = {&__pyx_n_s__config,0};
-  int __pyx_r;
-  __Pyx_RefNannyDeclarations
-  __Pyx_RefNannySetupContext("__cinit__ (wrapper)", 0);
-  {
-    PyObject* values[1] = {0};
-    if (unlikely(__pyx_kwds)) {
-      Py_ssize_t kw_args;
-      const Py_ssize_t pos_args = PyTuple_GET_SIZE(__pyx_args);
-      switch (pos_args) {
-        case  1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0);
-        case  0: break;
-        default: goto __pyx_L5_argtuple_error;
-      }
-      kw_args = PyDict_Size(__pyx_kwds);
-      switch (pos_args) {
-        case  0:
-        values[0] = PyDict_GetItem(__pyx_kwds, __pyx_n_s__config);
-        if (likely(values[0])) kw_args--;
-        else goto __pyx_L5_argtuple_error;
-      }
-      if (unlikely(kw_args > 0)) {
-        if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "__cinit__") < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 19; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
-      }
-    } else if (PyTuple_GET_SIZE(__pyx_args) != 1) {
-      goto __pyx_L5_argtuple_error;
-    } else {
-      values[0] = PyTuple_GET_ITEM(__pyx_args, 0);
-    }
-    __pyx_v_config = PyBytes_AsString(values[0]); if (unlikely((!__pyx_v_config) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 19; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
-  }
-  goto __pyx_L4_argument_unpacking_done;
-  __pyx_L5_argtuple_error:;
-  __Pyx_RaiseArgtupleInvalid("__cinit__", 1, 1, 1, PyTuple_GET_SIZE(__pyx_args)); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 19; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
-  __pyx_L3_error:;
-  __Pyx_AddTraceback("_cdec.Decoder.__cinit__", __pyx_clineno, __pyx_lineno, __pyx_filename);
-  __Pyx_RefNannyFinishContext();
-  return -1;
-  __pyx_L4_argument_unpacking_done:;
-  __pyx_r = __pyx_pf_5_cdec_7Decoder___cinit__(((struct __pyx_obj_5_cdec_Decoder *)__pyx_v_self), __pyx_v_config);
-  __Pyx_RefNannyFinishContext();
-  return __pyx_r;
-}
-
-/* "_cdec.pyx":19
- *     cdef public DenseVector weights
+/* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":3
+ * cimport mteval
  * 
- *     def __cinit__(self, char* config):             # <<<<<<<<<<<<<<
- *         decoder.register_feature_functions()
- *         cdef istringstream* config_stream = new istringstream(config)
+ * cdef char* as_str(sentence, error_msg='Cannot convert type %s to str'):             # <<<<<<<<<<<<<<
+ *     cdef bytes ret
+ *     if isinstance(sentence, unicode):
  */
 
-static int __pyx_pf_5_cdec_7Decoder___cinit__(struct __pyx_obj_5_cdec_Decoder *__pyx_v_self, char *__pyx_v_config) {
-  std::istringstream *__pyx_v_config_stream;
-  int __pyx_r;
+static char *__pyx_f_5_cdec_as_str(PyObject *__pyx_v_sentence, struct __pyx_opt_args_5_cdec_as_str *__pyx_optional_args) {
+  PyObject *__pyx_v_error_msg = ((PyObject *)__pyx_kp_s_19);
+  PyObject *__pyx_v_ret = 0;
+  char *__pyx_r;
   __Pyx_RefNannyDeclarations
   PyObject *__pyx_t_1 = NULL;
+  int __pyx_t_2;
+  PyObject *__pyx_t_3 = NULL;
+  char *__pyx_t_4;
   int __pyx_lineno = 0;
   const char *__pyx_filename = NULL;
   int __pyx_clineno = 0;
-  __Pyx_RefNannySetupContext("__cinit__", 0);
+  __Pyx_RefNannySetupContext("as_str", 0);
+  if (__pyx_optional_args) {
+    if (__pyx_optional_args->__pyx_n > 0) {
+      __pyx_v_error_msg = __pyx_optional_args->error_msg;
+    }
+  }
 
-  /* "_cdec.pyx":20
- * 
- *     def __cinit__(self, char* config):
- *         decoder.register_feature_functions()             # <<<<<<<<<<<<<<
- *         cdef istringstream* config_stream = new istringstream(config)
- *         self.dec = new decoder.Decoder(config_stream)
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":5
+ * cdef char* as_str(sentence, error_msg='Cannot convert type %s to str'):
+ *     cdef bytes ret
+ *     if isinstance(sentence, unicode):             # <<<<<<<<<<<<<<
+ *         ret = sentence.encode('utf8')
+ *     elif isinstance(sentence, str):
  */
-  register_feature_functions();
-
-  /* "_cdec.pyx":21
- *     def __cinit__(self, char* config):
- *         decoder.register_feature_functions()
- *         cdef istringstream* config_stream = new istringstream(config)             # <<<<<<<<<<<<<<
- *         self.dec = new decoder.Decoder(config_stream)
- *         del config_stream
+  __pyx_t_1 = ((PyObject *)((PyObject*)(&PyUnicode_Type)));
+  __Pyx_INCREF(__pyx_t_1);
+  __pyx_t_2 = __Pyx_TypeCheck(__pyx_v_sentence, __pyx_t_1); 
+  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+  if (__pyx_t_2) {
+
+    /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":6
+ *     cdef bytes ret
+ *     if isinstance(sentence, unicode):
+ *         ret = sentence.encode('utf8')             # <<<<<<<<<<<<<<
+ *     elif isinstance(sentence, str):
+ *         ret = sentence
  */
-  __pyx_v_config_stream = new std::istringstream(__pyx_v_config);
+    __pyx_t_1 = PyObject_GetAttr(__pyx_v_sentence, __pyx_n_s__encode); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 6; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_1);
+    __pyx_t_3 = PyObject_Call(__pyx_t_1, ((PyObject *)__pyx_k_tuple_20), NULL); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 6; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_3);
+    __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+    if (!(likely(PyBytes_CheckExact(__pyx_t_3))||((__pyx_t_3) == Py_None)||(PyErr_Format(PyExc_TypeError, "Expected bytes, got %.200s", Py_TYPE(__pyx_t_3)->tp_name), 0))) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 6; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_v_ret = ((PyObject*)__pyx_t_3);
+    __pyx_t_3 = 0;
+    goto __pyx_L3;
+  }
 
-  /* "_cdec.pyx":22
- *         decoder.register_feature_functions()
- *         cdef istringstream* config_stream = new istringstream(config)
- *         self.dec = new decoder.Decoder(config_stream)             # <<<<<<<<<<<<<<
- *         del config_stream
- *         self.weights = DenseVector()
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":7
+ *     if isinstance(sentence, unicode):
+ *         ret = sentence.encode('utf8')
+ *     elif isinstance(sentence, str):             # <<<<<<<<<<<<<<
+ *         ret = sentence
+ *     else:
  */
-  __pyx_v_self->dec = new Decoder(__pyx_v_config_stream);
+  __pyx_t_3 = ((PyObject *)((PyObject*)(&PyString_Type)));
+  __Pyx_INCREF(__pyx_t_3);
+  __pyx_t_2 = __Pyx_TypeCheck(__pyx_v_sentence, __pyx_t_3); 
+  __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
+  if (__pyx_t_2) {
 
-  /* "_cdec.pyx":23
- *         cdef istringstream* config_stream = new istringstream(config)
- *         self.dec = new decoder.Decoder(config_stream)
- *         del config_stream             # <<<<<<<<<<<<<<
- *         self.weights = DenseVector()
- *         self.weights.vector = &self.dec.CurrentWeightVector()
+    /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":8
+ *         ret = sentence.encode('utf8')
+ *     elif isinstance(sentence, str):
+ *         ret = sentence             # <<<<<<<<<<<<<<
+ *     else:
+ *         raise TypeError(error_msg % type(sentence))
  */
-  delete __pyx_v_config_stream;
+    if (!(likely(PyBytes_CheckExact(__pyx_v_sentence))||((__pyx_v_sentence) == Py_None)||(PyErr_Format(PyExc_TypeError, "Expected bytes, got %.200s", Py_TYPE(__pyx_v_sentence)->tp_name), 0))) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 8; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_INCREF(__pyx_v_sentence);
+    __pyx_v_ret = ((PyObject*)__pyx_v_sentence);
+    goto __pyx_L3;
+  }
+  /*else*/ {
 
-  /* "_cdec.pyx":24
- *         self.dec = new decoder.Decoder(config_stream)
- *         del config_stream
- *         self.weights = DenseVector()             # <<<<<<<<<<<<<<
- *         self.weights.vector = &self.dec.CurrentWeightVector()
+    /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":10
+ *         ret = sentence
+ *     else:
+ *         raise TypeError(error_msg % type(sentence))             # <<<<<<<<<<<<<<
+ *     return ret
  * 
  */
-  __pyx_t_1 = PyObject_Call(((PyObject *)((PyObject*)__pyx_ptype_5_cdec_DenseVector)), ((PyObject *)__pyx_empty_tuple), NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 24; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __Pyx_GOTREF(__pyx_t_1);
-  __Pyx_GIVEREF(__pyx_t_1);
-  __Pyx_GOTREF(__pyx_v_self->weights);
-  __Pyx_DECREF(((PyObject *)__pyx_v_self->weights));
-  __pyx_v_self->weights = ((struct __pyx_obj_5_cdec_DenseVector *)__pyx_t_1);
-  __pyx_t_1 = 0;
+    __pyx_t_3 = PyNumber_Remainder(__pyx_v_error_msg, ((PyObject *)Py_TYPE(__pyx_v_sentence))); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 10; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_3);
+    __pyx_t_1 = PyTuple_New(1); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 10; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_1);
+    PyTuple_SET_ITEM(__pyx_t_1, 0, __pyx_t_3);
+    __Pyx_GIVEREF(__pyx_t_3);
+    __pyx_t_3 = 0;
+    __pyx_t_3 = PyObject_Call(__pyx_builtin_TypeError, ((PyObject *)__pyx_t_1), NULL); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 10; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_3);
+    __Pyx_DECREF(((PyObject *)__pyx_t_1)); __pyx_t_1 = 0;
+    __Pyx_Raise(__pyx_t_3, 0, 0, 0);
+    __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
+    {__pyx_filename = __pyx_f[4]; __pyx_lineno = 10; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  }
+  __pyx_L3:;
 
-  /* "_cdec.pyx":25
- *         del config_stream
- *         self.weights = DenseVector()
- *         self.weights.vector = &self.dec.CurrentWeightVector()             # <<<<<<<<<<<<<<
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":11
+ *     else:
+ *         raise TypeError(error_msg % type(sentence))
+ *     return ret             # <<<<<<<<<<<<<<
  * 
- *     def __dealloc__(self):
+ * cdef class Candidate:
  */
-  __pyx_v_self->weights->vector = (&__pyx_v_self->dec->CurrentWeightVector());
+  __pyx_t_4 = PyBytes_AsString(((PyObject *)__pyx_v_ret)); if (unlikely((!__pyx_t_4) && PyErr_Occurred())) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 11; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_r = __pyx_t_4;
+  goto __pyx_L0;
 
   __pyx_r = 0;
   goto __pyx_L0;
   __pyx_L1_error:;
   __Pyx_XDECREF(__pyx_t_1);
-  __Pyx_AddTraceback("_cdec.Decoder.__cinit__", __pyx_clineno, __pyx_lineno, __pyx_filename);
-  __pyx_r = -1;
+  __Pyx_XDECREF(__pyx_t_3);
+  __Pyx_WriteUnraisable("_cdec.as_str", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __pyx_r = 0;
   __pyx_L0:;
+  __Pyx_XDECREF(__pyx_v_ret);
   __Pyx_RefNannyFinishContext();
   return __pyx_r;
 }
 
 /* Python wrapper */
-static void __pyx_pw_5_cdec_7Decoder_3__dealloc__(PyObject *__pyx_v_self); /*proto*/
-static void __pyx_pw_5_cdec_7Decoder_3__dealloc__(PyObject *__pyx_v_self) {
+static PyObject *__pyx_pw_5_cdec_9Candidate_5words_1__get__(PyObject *__pyx_v_self); /*proto*/
+static PyObject *__pyx_pw_5_cdec_9Candidate_5words_1__get__(PyObject *__pyx_v_self) {
+  PyObject *__pyx_r = 0;
   __Pyx_RefNannyDeclarations
-  __Pyx_RefNannySetupContext("__dealloc__ (wrapper)", 0);
-  __pyx_pf_5_cdec_7Decoder_2__dealloc__(((struct __pyx_obj_5_cdec_Decoder *)__pyx_v_self));
+  __Pyx_RefNannySetupContext("__get__ (wrapper)", 0);
+  __pyx_r = __pyx_pf_5_cdec_9Candidate_5words___get__(((struct __pyx_obj_5_cdec_Candidate *)__pyx_v_self));
   __Pyx_RefNannyFinishContext();
+  return __pyx_r;
 }
 
-/* "_cdec.pyx":27
- *         self.weights.vector = &self.dec.CurrentWeightVector()
+/* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":18
  * 
- *     def __dealloc__(self):             # <<<<<<<<<<<<<<
- *         del self.dec
+ *     property words:
+ *         def __get__(self):             # <<<<<<<<<<<<<<
+ *             return unicode(GetString(self.candidate.ewords).c_str(), encoding='utf8')
  * 
  */
 
-static void __pyx_pf_5_cdec_7Decoder_2__dealloc__(CYTHON_UNUSED struct __pyx_obj_5_cdec_Decoder *__pyx_v_self) {
+static PyObject *__pyx_pf_5_cdec_9Candidate_5words___get__(struct __pyx_obj_5_cdec_Candidate *__pyx_v_self) {
+  PyObject *__pyx_r = NULL;
   __Pyx_RefNannyDeclarations
-  __Pyx_RefNannySetupContext("__dealloc__", 0);
+  PyObject *__pyx_t_1 = NULL;
+  PyObject *__pyx_t_2 = NULL;
+  PyObject *__pyx_t_3 = NULL;
+  int __pyx_lineno = 0;
+  const char *__pyx_filename = NULL;
+  int __pyx_clineno = 0;
+  __Pyx_RefNannySetupContext("__get__", 0);
 
-  /* "_cdec.pyx":28
- * 
- *     def __dealloc__(self):
- *         del self.dec             # <<<<<<<<<<<<<<
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":19
+ *     property words:
+ *         def __get__(self):
+ *             return unicode(GetString(self.candidate.ewords).c_str(), encoding='utf8')             # <<<<<<<<<<<<<<
  * 
- *     def read_weights(self, cfg):
+ *     property fmap:
  */
-  delete __pyx_v_self->dec;
+  __Pyx_XDECREF(__pyx_r);
+  __pyx_t_1 = PyBytes_FromString(TD::GetString(__pyx_v_self->candidate->ewords).c_str()); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 19; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(((PyObject *)__pyx_t_1));
+  __pyx_t_2 = PyTuple_New(1); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 19; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_2);
+  PyTuple_SET_ITEM(__pyx_t_2, 0, ((PyObject *)__pyx_t_1));
+  __Pyx_GIVEREF(((PyObject *)__pyx_t_1));
+  __pyx_t_1 = 0;
+  __pyx_t_1 = PyDict_New(); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 19; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(((PyObject *)__pyx_t_1));
+  if (PyDict_SetItem(__pyx_t_1, ((PyObject *)__pyx_n_s__encoding), ((PyObject *)__pyx_n_s__utf8)) < 0) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 19; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_3 = PyObject_Call(((PyObject *)((PyObject*)(&PyUnicode_Type))), ((PyObject *)__pyx_t_2), ((PyObject *)__pyx_t_1)); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 19; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_3);
+  __Pyx_DECREF(((PyObject *)__pyx_t_2)); __pyx_t_2 = 0;
+  __Pyx_DECREF(((PyObject *)__pyx_t_1)); __pyx_t_1 = 0;
+  __pyx_r = __pyx_t_3;
+  __pyx_t_3 = 0;
+  goto __pyx_L0;
 
+  __pyx_r = Py_None; __Pyx_INCREF(Py_None);
+  goto __pyx_L0;
+  __pyx_L1_error:;
+  __Pyx_XDECREF(__pyx_t_1);
+  __Pyx_XDECREF(__pyx_t_2);
+  __Pyx_XDECREF(__pyx_t_3);
+  __Pyx_AddTraceback("_cdec.Candidate.words.__get__", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __pyx_r = NULL;
+  __pyx_L0:;
+  __Pyx_XGIVEREF(__pyx_r);
   __Pyx_RefNannyFinishContext();
+  return __pyx_r;
 }
 
 /* Python wrapper */
-static PyObject *__pyx_pw_5_cdec_7Decoder_5read_weights(PyObject *__pyx_v_self, PyObject *__pyx_v_cfg); /*proto*/
-static PyObject *__pyx_pw_5_cdec_7Decoder_5read_weights(PyObject *__pyx_v_self, PyObject *__pyx_v_cfg) {
+static PyObject *__pyx_pw_5_cdec_9Candidate_4fmap_1__get__(PyObject *__pyx_v_self); /*proto*/
+static PyObject *__pyx_pw_5_cdec_9Candidate_4fmap_1__get__(PyObject *__pyx_v_self) {
   PyObject *__pyx_r = 0;
   __Pyx_RefNannyDeclarations
-  __Pyx_RefNannySetupContext("read_weights (wrapper)", 0);
-  __pyx_r = __pyx_pf_5_cdec_7Decoder_4read_weights(((struct __pyx_obj_5_cdec_Decoder *)__pyx_v_self), ((PyObject *)__pyx_v_cfg));
+  __Pyx_RefNannySetupContext("__get__ (wrapper)", 0);
+  __pyx_r = __pyx_pf_5_cdec_9Candidate_4fmap___get__(((struct __pyx_obj_5_cdec_Candidate *)__pyx_v_self));
   __Pyx_RefNannyFinishContext();
   return __pyx_r;
 }
 
-/* "_cdec.pyx":30
- *         del self.dec
+/* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":22
  * 
- *     def read_weights(self, cfg):             # <<<<<<<<<<<<<<
- *         with open(cfg) as fp:
- *             for line in fp:
+ *     property fmap:
+ *         def __get__(self):             # <<<<<<<<<<<<<<
+ *             cdef SparseVector fmap = SparseVector()
+ *             fmap.vector = new FastSparseVector[weight_t](self.candidate.fmap)
  */
 
-static PyObject *__pyx_pf_5_cdec_7Decoder_4read_weights(struct __pyx_obj_5_cdec_Decoder *__pyx_v_self, PyObject *__pyx_v_cfg) {
-  PyObject *__pyx_v_fp = NULL;
-  PyObject *__pyx_v_line = NULL;
-  PyObject *__pyx_v_fname = NULL;
-  PyObject *__pyx_v_value = NULL;
+static PyObject *__pyx_pf_5_cdec_9Candidate_4fmap___get__(struct __pyx_obj_5_cdec_Candidate *__pyx_v_self) {
+  struct __pyx_obj_5_cdec_SparseVector *__pyx_v_fmap = 0;
   PyObject *__pyx_r = NULL;
   __Pyx_RefNannyDeclarations
   PyObject *__pyx_t_1 = NULL;
-  PyObject *__pyx_t_2 = NULL;
-  PyObject *__pyx_t_3 = NULL;
-  PyObject *__pyx_t_4 = NULL;
-  PyObject *__pyx_t_5 = NULL;
-  PyObject *__pyx_t_6 = NULL;
-  PyObject *__pyx_t_7 = NULL;
-  Py_ssize_t __pyx_t_8;
-  PyObject *(*__pyx_t_9)(PyObject *);
-  PyObject *__pyx_t_10 = NULL;
-  PyObject *__pyx_t_11 = NULL;
-  PyObject *(*__pyx_t_12)(PyObject *);
-  double __pyx_t_13;
-  int __pyx_t_14;
-  PyObject *__pyx_t_15 = NULL;
-  int __pyx_t_16;
   int __pyx_lineno = 0;
   const char *__pyx_filename = NULL;
   int __pyx_clineno = 0;
-  __Pyx_RefNannySetupContext("read_weights", 0);
+  __Pyx_RefNannySetupContext("__get__", 0);
 
-  /* "_cdec.pyx":31
- * 
- *     def read_weights(self, cfg):
- *         with open(cfg) as fp:             # <<<<<<<<<<<<<<
- *             for line in fp:
- *                 fname, value = line.split()
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":23
+ *     property fmap:
+ *         def __get__(self):
+ *             cdef SparseVector fmap = SparseVector()             # <<<<<<<<<<<<<<
+ *             fmap.vector = new FastSparseVector[weight_t](self.candidate.fmap)
+ *             return fmap
  */
-  /*with:*/ {
-    __pyx_t_1 = PyTuple_New(1); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 31; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-    __Pyx_GOTREF(__pyx_t_1);
-    __Pyx_INCREF(__pyx_v_cfg);
-    PyTuple_SET_ITEM(__pyx_t_1, 0, __pyx_v_cfg);
-    __Pyx_GIVEREF(__pyx_v_cfg);
-    __pyx_t_2 = PyObject_Call(__pyx_builtin_open, ((PyObject *)__pyx_t_1), NULL); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 31; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-    __Pyx_GOTREF(__pyx_t_2);
-    __Pyx_DECREF(((PyObject *)__pyx_t_1)); __pyx_t_1 = 0;
-    __pyx_t_3 = PyObject_GetAttr(__pyx_t_2, __pyx_n_s____exit__); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 31; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-    __Pyx_GOTREF(__pyx_t_3);
-    __pyx_t_1 = PyObject_GetAttr(__pyx_t_2, __pyx_n_s____enter__); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 31; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
-    __Pyx_GOTREF(__pyx_t_1);
-    __pyx_t_4 = PyObject_Call(__pyx_t_1, ((PyObject *)__pyx_empty_tuple), NULL); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 31; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
-    __Pyx_GOTREF(__pyx_t_4);
-    __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
-    __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
-    /*try:*/ {
-      {
-        __Pyx_ExceptionSave(&__pyx_t_5, &__pyx_t_6, &__pyx_t_7);
-        __Pyx_XGOTREF(__pyx_t_5);
-        __Pyx_XGOTREF(__pyx_t_6);
-        __Pyx_XGOTREF(__pyx_t_7);
-        /*try:*/ {
-          __Pyx_INCREF(__pyx_t_4);
-          __pyx_v_fp = __pyx_t_4;
-          __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
+  __pyx_t_1 = PyObject_Call(((PyObject *)((PyObject*)__pyx_ptype_5_cdec_SparseVector)), ((PyObject *)__pyx_empty_tuple), NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 23; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_1);
+  __pyx_v_fmap = ((struct __pyx_obj_5_cdec_SparseVector *)__pyx_t_1);
+  __pyx_t_1 = 0;
 
-          /* "_cdec.pyx":32
- *     def read_weights(self, cfg):
- *         with open(cfg) as fp:
- *             for line in fp:             # <<<<<<<<<<<<<<
- *                 fname, value = line.split()
- *                 self.weights[fname.strip()] = float(value)
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":24
+ *         def __get__(self):
+ *             cdef SparseVector fmap = SparseVector()
+ *             fmap.vector = new FastSparseVector[weight_t](self.candidate.fmap)             # <<<<<<<<<<<<<<
+ *             return fmap
+ * 
  */
-          if (PyList_CheckExact(__pyx_v_fp) || PyTuple_CheckExact(__pyx_v_fp)) {
-            __pyx_t_4 = __pyx_v_fp; __Pyx_INCREF(__pyx_t_4); __pyx_t_8 = 0;
-            __pyx_t_9 = NULL;
-          } else {
-            __pyx_t_8 = -1; __pyx_t_4 = PyObject_GetIter(__pyx_v_fp); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 32; __pyx_clineno = __LINE__; goto __pyx_L7_error;}
-            __Pyx_GOTREF(__pyx_t_4);
-            __pyx_t_9 = Py_TYPE(__pyx_t_4)->tp_iternext;
-          }
-          for (;;) {
-            if (!__pyx_t_9 && PyList_CheckExact(__pyx_t_4)) {
-              if (__pyx_t_8 >= PyList_GET_SIZE(__pyx_t_4)) break;
-              __pyx_t_2 = PyList_GET_ITEM(__pyx_t_4, __pyx_t_8); __Pyx_INCREF(__pyx_t_2); __pyx_t_8++;
-            } else if (!__pyx_t_9 && PyTuple_CheckExact(__pyx_t_4)) {
-              if (__pyx_t_8 >= PyTuple_GET_SIZE(__pyx_t_4)) break;
-              __pyx_t_2 = PyTuple_GET_ITEM(__pyx_t_4, __pyx_t_8); __Pyx_INCREF(__pyx_t_2); __pyx_t_8++;
-            } else {
-              __pyx_t_2 = __pyx_t_9(__pyx_t_4);
-              if (unlikely(!__pyx_t_2)) {
-                if (PyErr_Occurred()) {
-                  if (likely(PyErr_ExceptionMatches(PyExc_StopIteration))) PyErr_Clear();
-                  else {__pyx_filename = __pyx_f[0]; __pyx_lineno = 32; __pyx_clineno = __LINE__; goto __pyx_L7_error;}
-                }
-                break;
-              }
-              __Pyx_GOTREF(__pyx_t_2);
-            }
-            __Pyx_XDECREF(__pyx_v_line);
-            __pyx_v_line = __pyx_t_2;
-            __pyx_t_2 = 0;
+  __pyx_v_fmap->vector = new FastSparseVector<weight_t>(__pyx_v_self->candidate->fmap);
 
-            /* "_cdec.pyx":33
- *         with open(cfg) as fp:
- *             for line in fp:
- *                 fname, value = line.split()             # <<<<<<<<<<<<<<
- *                 self.weights[fname.strip()] = float(value)
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":25
+ *             cdef SparseVector fmap = SparseVector()
+ *             fmap.vector = new FastSparseVector[weight_t](self.candidate.fmap)
+ *             return fmap             # <<<<<<<<<<<<<<
  * 
+ * cdef class SufficientStats:
  */
-            __pyx_t_2 = PyObject_GetAttr(__pyx_v_line, __pyx_n_s__split); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 33; __pyx_clineno = __LINE__; goto __pyx_L7_error;}
-            __Pyx_GOTREF(__pyx_t_2);
-            __pyx_t_1 = PyObject_Call(__pyx_t_2, ((PyObject *)__pyx_empty_tuple), NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 33; __pyx_clineno = __LINE__; goto __pyx_L7_error;}
-            __Pyx_GOTREF(__pyx_t_1);
-            __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
-            if ((likely(PyTuple_CheckExact(__pyx_t_1))) || (PyList_CheckExact(__pyx_t_1))) {
-              PyObject* sequence = __pyx_t_1;
-              if (likely(PyTuple_CheckExact(sequence))) {
-                if (unlikely(PyTuple_GET_SIZE(sequence) != 2)) {
-                  if (PyTuple_GET_SIZE(sequence) > 2) __Pyx_RaiseTooManyValuesError(2);
-                  else __Pyx_RaiseNeedMoreValuesError(PyTuple_GET_SIZE(sequence));
-                  {__pyx_filename = __pyx_f[0]; __pyx_lineno = 33; __pyx_clineno = __LINE__; goto __pyx_L7_error;}
-                }
-                __pyx_t_2 = PyTuple_GET_ITEM(sequence, 0); 
-                __pyx_t_10 = PyTuple_GET_ITEM(sequence, 1); 
-              } else {
-                if (unlikely(PyList_GET_SIZE(sequence) != 2)) {
-                  if (PyList_GET_SIZE(sequence) > 2) __Pyx_RaiseTooManyValuesError(2);
-                  else __Pyx_RaiseNeedMoreValuesError(PyList_GET_SIZE(sequence));
-                  {__pyx_filename = __pyx_f[0]; __pyx_lineno = 33; __pyx_clineno = __LINE__; goto __pyx_L7_error;}
-                }
-                __pyx_t_2 = PyList_GET_ITEM(sequence, 0); 
-                __pyx_t_10 = PyList_GET_ITEM(sequence, 1); 
-              }
-              __Pyx_INCREF(__pyx_t_2);
-              __Pyx_INCREF(__pyx_t_10);
-              __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
-            } else {
-              Py_ssize_t index = -1;
-              __pyx_t_11 = PyObject_GetIter(__pyx_t_1); if (unlikely(!__pyx_t_11)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 33; __pyx_clineno = __LINE__; goto __pyx_L7_error;}
-              __Pyx_GOTREF(__pyx_t_11);
-              __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
-              __pyx_t_12 = Py_TYPE(__pyx_t_11)->tp_iternext;
-              index = 0; __pyx_t_2 = __pyx_t_12(__pyx_t_11); if (unlikely(!__pyx_t_2)) goto __pyx_L18_unpacking_failed;
-              __Pyx_GOTREF(__pyx_t_2);
-              index = 1; __pyx_t_10 = __pyx_t_12(__pyx_t_11); if (unlikely(!__pyx_t_10)) goto __pyx_L18_unpacking_failed;
-              __Pyx_GOTREF(__pyx_t_10);
-              if (__Pyx_IternextUnpackEndCheck(__pyx_t_12(__pyx_t_11), 2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 33; __pyx_clineno = __LINE__; goto __pyx_L7_error;}
-              __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0;
-              goto __pyx_L19_unpacking_done;
-              __pyx_L18_unpacking_failed:;
-              __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0;
-              if (PyErr_Occurred() && PyErr_ExceptionMatches(PyExc_StopIteration)) PyErr_Clear();
-              if (!PyErr_Occurred()) __Pyx_RaiseNeedMoreValuesError(index);
-              {__pyx_filename = __pyx_f[0]; __pyx_lineno = 33; __pyx_clineno = __LINE__; goto __pyx_L7_error;}
-              __pyx_L19_unpacking_done:;
-            }
-            __Pyx_XDECREF(__pyx_v_fname);
-            __pyx_v_fname = __pyx_t_2;
-            __pyx_t_2 = 0;
-            __Pyx_XDECREF(__pyx_v_value);
-            __pyx_v_value = __pyx_t_10;
-            __pyx_t_10 = 0;
-
-            /* "_cdec.pyx":34
- *             for line in fp:
- *                 fname, value = line.split()
- *                 self.weights[fname.strip()] = float(value)             # <<<<<<<<<<<<<<
- * 
- *     def translate(self, sentence, grammar=None):
- */
-            __pyx_t_13 = __Pyx_PyObject_AsDouble(__pyx_v_value); if (unlikely(__pyx_t_13 == ((double)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 34; __pyx_clineno = __LINE__; goto __pyx_L7_error;}
-            __pyx_t_1 = PyFloat_FromDouble(__pyx_t_13); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 34; __pyx_clineno = __LINE__; goto __pyx_L7_error;}
-            __Pyx_GOTREF(__pyx_t_1);
-            __pyx_t_10 = PyObject_GetAttr(__pyx_v_fname, __pyx_n_s__strip); if (unlikely(!__pyx_t_10)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 34; __pyx_clineno = __LINE__; goto __pyx_L7_error;}
-            __Pyx_GOTREF(__pyx_t_10);
-            __pyx_t_2 = PyObject_Call(__pyx_t_10, ((PyObject *)__pyx_empty_tuple), NULL); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 34; __pyx_clineno = __LINE__; goto __pyx_L7_error;}
-            __Pyx_GOTREF(__pyx_t_2);
-            __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0;
-            if (PyObject_SetItem(((PyObject *)__pyx_v_self->weights), __pyx_t_2, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 34; __pyx_clineno = __LINE__; goto __pyx_L7_error;}
-            __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
-            __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
-          }
-          __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
-        }
-        __Pyx_XDECREF(__pyx_t_5); __pyx_t_5 = 0;
-        __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0;
-        __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0;
-        goto __pyx_L14_try_end;
-        __pyx_L7_error:;
-        __Pyx_XDECREF(__pyx_t_11); __pyx_t_11 = 0;
-        __Pyx_XDECREF(__pyx_t_10); __pyx_t_10 = 0;
-        __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0;
-        __Pyx_XDECREF(__pyx_t_1); __pyx_t_1 = 0;
-        __Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0;
-
-        /* "_cdec.pyx":31
- * 
- *     def read_weights(self, cfg):
- *         with open(cfg) as fp:             # <<<<<<<<<<<<<<
- *             for line in fp:
- *                 fname, value = line.split()
- */
-        /*except:*/ {
-          __Pyx_AddTraceback("_cdec.Decoder.read_weights", __pyx_clineno, __pyx_lineno, __pyx_filename);
-          if (__Pyx_GetException(&__pyx_t_4, &__pyx_t_1, &__pyx_t_2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 31; __pyx_clineno = __LINE__; goto __pyx_L9_except_error;}
-          __Pyx_GOTREF(__pyx_t_4);
-          __Pyx_GOTREF(__pyx_t_1);
-          __Pyx_GOTREF(__pyx_t_2);
-          __pyx_t_10 = PyTuple_New(3); if (unlikely(!__pyx_t_10)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 31; __pyx_clineno = __LINE__; goto __pyx_L9_except_error;}
-          __Pyx_GOTREF(__pyx_t_10);
-          __Pyx_INCREF(__pyx_t_4);
-          PyTuple_SET_ITEM(__pyx_t_10, 0, __pyx_t_4);
-          __Pyx_GIVEREF(__pyx_t_4);
-          __Pyx_INCREF(__pyx_t_1);
-          PyTuple_SET_ITEM(__pyx_t_10, 1, __pyx_t_1);
-          __Pyx_GIVEREF(__pyx_t_1);
-          __Pyx_INCREF(__pyx_t_2);
-          PyTuple_SET_ITEM(__pyx_t_10, 2, __pyx_t_2);
-          __Pyx_GIVEREF(__pyx_t_2);
-          __pyx_t_15 = PyObject_Call(__pyx_t_3, __pyx_t_10, NULL);
-          __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
-          if (unlikely(!__pyx_t_15)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 31; __pyx_clineno = __LINE__; goto __pyx_L9_except_error;}
-          __Pyx_GOTREF(__pyx_t_15);
-          __pyx_t_14 = __Pyx_PyObject_IsTrue(__pyx_t_15);
-          __Pyx_DECREF(__pyx_t_15); __pyx_t_15 = 0;
-          if (unlikely(__pyx_t_14 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 31; __pyx_clineno = __LINE__; goto __pyx_L9_except_error;}
-          __pyx_t_16 = (!__pyx_t_14);
-          if (__pyx_t_16) {
-            __Pyx_GIVEREF(__pyx_t_4);
-            __Pyx_GIVEREF(__pyx_t_1);
-            __Pyx_GIVEREF(__pyx_t_2);
-            __Pyx_ErrRestore(__pyx_t_4, __pyx_t_1, __pyx_t_2);
-            __pyx_t_4 = 0; __pyx_t_1 = 0; __pyx_t_2 = 0; 
-            {__pyx_filename = __pyx_f[0]; __pyx_lineno = 31; __pyx_clineno = __LINE__; goto __pyx_L9_except_error;}
-            goto __pyx_L22;
-          }
-          __pyx_L22:;
-          __Pyx_DECREF(((PyObject *)__pyx_t_10)); __pyx_t_10 = 0;
-          __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
-          __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
-          __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
-          goto __pyx_L8_exception_handled;
-        }
-        __pyx_L9_except_error:;
-        __Pyx_XGIVEREF(__pyx_t_5);
-        __Pyx_XGIVEREF(__pyx_t_6);
-        __Pyx_XGIVEREF(__pyx_t_7);
-        __Pyx_ExceptionReset(__pyx_t_5, __pyx_t_6, __pyx_t_7);
-        goto __pyx_L1_error;
-        __pyx_L8_exception_handled:;
-        __Pyx_XGIVEREF(__pyx_t_5);
-        __Pyx_XGIVEREF(__pyx_t_6);
-        __Pyx_XGIVEREF(__pyx_t_7);
-        __Pyx_ExceptionReset(__pyx_t_5, __pyx_t_6, __pyx_t_7);
-        __pyx_L14_try_end:;
-      }
-    }
-    /*finally:*/ {
-      if (__pyx_t_3) {
-        __pyx_t_7 = PyObject_Call(__pyx_t_3, __pyx_k_tuple_19, NULL);
-        __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
-        if (unlikely(!__pyx_t_7)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 31; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-        __Pyx_GOTREF(__pyx_t_7);
-        __pyx_t_16 = __Pyx_PyObject_IsTrue(__pyx_t_7);
-        __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;
-        if (unlikely(__pyx_t_16 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 31; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-      }
-    }
-    goto __pyx_L23;
-    __pyx_L3_error:;
-    __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
-    goto __pyx_L1_error;
-    __pyx_L23:;
-  }
+  __Pyx_XDECREF(__pyx_r);
+  __Pyx_INCREF(((PyObject *)__pyx_v_fmap));
+  __pyx_r = ((PyObject *)__pyx_v_fmap);
+  goto __pyx_L0;
 
   __pyx_r = Py_None; __Pyx_INCREF(Py_None);
   goto __pyx_L0;
   __pyx_L1_error:;
   __Pyx_XDECREF(__pyx_t_1);
-  __Pyx_XDECREF(__pyx_t_2);
-  __Pyx_XDECREF(__pyx_t_4);
-  __Pyx_XDECREF(__pyx_t_10);
-  __Pyx_XDECREF(__pyx_t_11);
-  __Pyx_AddTraceback("_cdec.Decoder.read_weights", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __Pyx_AddTraceback("_cdec.Candidate.fmap.__get__", __pyx_clineno, __pyx_lineno, __pyx_filename);
   __pyx_r = NULL;
   __pyx_L0:;
-  __Pyx_XDECREF(__pyx_v_fp);
-  __Pyx_XDECREF(__pyx_v_line);
-  __Pyx_XDECREF(__pyx_v_fname);
-  __Pyx_XDECREF(__pyx_v_value);
+  __Pyx_XDECREF((PyObject *)__pyx_v_fmap);
   __Pyx_XGIVEREF(__pyx_r);
   __Pyx_RefNannyFinishContext();
   return __pyx_r;
 }
 
 /* Python wrapper */
-static PyObject *__pyx_pw_5_cdec_7Decoder_7translate(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/
-static PyObject *__pyx_pw_5_cdec_7Decoder_7translate(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) {
-  PyObject *__pyx_v_sentence = 0;
-  PyObject *__pyx_v_grammar = 0;
-  static PyObject **__pyx_pyargnames[] = {&__pyx_n_s__sentence,&__pyx_n_s__grammar,0};
+static PyObject *__pyx_pw_5_cdec_9Candidate_5score_1__get__(PyObject *__pyx_v_self); /*proto*/
+static PyObject *__pyx_pw_5_cdec_9Candidate_5score_1__get__(PyObject *__pyx_v_self) {
   PyObject *__pyx_r = 0;
   __Pyx_RefNannyDeclarations
-  __Pyx_RefNannySetupContext("translate (wrapper)", 0);
-  {
-    PyObject* values[2] = {0,0};
+  __Pyx_RefNannySetupContext("__get__ (wrapper)", 0);
+  __pyx_r = __pyx_pf_5_cdec_9Candidate_5score___get__(((struct __pyx_obj_5_cdec_Candidate *)__pyx_v_self));
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
 
-    /* "_cdec.pyx":36
- *                 self.weights[fname.strip()] = float(value)
+/* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":15
+ * cdef class Candidate:
+ *     cdef mteval.Candidate* candidate
+ *     cdef public float score             # <<<<<<<<<<<<<<
  * 
- *     def translate(self, sentence, grammar=None):             # <<<<<<<<<<<<<<
- *         if isinstance(sentence, unicode):
- *             inp = sentence.strip().encode('utf8')
+ *     property words:
  */
-    values[1] = ((PyObject *)Py_None);
-    if (unlikely(__pyx_kwds)) {
-      Py_ssize_t kw_args;
-      const Py_ssize_t pos_args = PyTuple_GET_SIZE(__pyx_args);
-      switch (pos_args) {
-        case  2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1);
-        case  1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0);
-        case  0: break;
-        default: goto __pyx_L5_argtuple_error;
-      }
-      kw_args = PyDict_Size(__pyx_kwds);
-      switch (pos_args) {
-        case  0:
-        values[0] = PyDict_GetItem(__pyx_kwds, __pyx_n_s__sentence);
-        if (likely(values[0])) kw_args--;
-        else goto __pyx_L5_argtuple_error;
-        case  1:
-        if (kw_args > 0) {
-          PyObject* value = PyDict_GetItem(__pyx_kwds, __pyx_n_s__grammar);
-          if (value) { values[1] = value; kw_args--; }
-        }
-      }
-      if (unlikely(kw_args > 0)) {
-        if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "translate") < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 36; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
-      }
-    } else {
-      switch (PyTuple_GET_SIZE(__pyx_args)) {
-        case  2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1);
-        case  1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0);
-        break;
-        default: goto __pyx_L5_argtuple_error;
-      }
-    }
-    __pyx_v_sentence = values[0];
-    __pyx_v_grammar = values[1];
-  }
-  goto __pyx_L4_argument_unpacking_done;
-  __pyx_L5_argtuple_error:;
-  __Pyx_RaiseArgtupleInvalid("translate", 0, 1, 2, PyTuple_GET_SIZE(__pyx_args)); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 36; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
-  __pyx_L3_error:;
-  __Pyx_AddTraceback("_cdec.Decoder.translate", __pyx_clineno, __pyx_lineno, __pyx_filename);
+
+static PyObject *__pyx_pf_5_cdec_9Candidate_5score___get__(struct __pyx_obj_5_cdec_Candidate *__pyx_v_self) {
+  PyObject *__pyx_r = NULL;
+  __Pyx_RefNannyDeclarations
+  PyObject *__pyx_t_1 = NULL;
+  int __pyx_lineno = 0;
+  const char *__pyx_filename = NULL;
+  int __pyx_clineno = 0;
+  __Pyx_RefNannySetupContext("__get__", 0);
+  __Pyx_XDECREF(__pyx_r);
+  __pyx_t_1 = PyFloat_FromDouble(__pyx_v_self->score); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 15; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_1);
+  __pyx_r = __pyx_t_1;
+  __pyx_t_1 = 0;
+  goto __pyx_L0;
+
+  __pyx_r = Py_None; __Pyx_INCREF(Py_None);
+  goto __pyx_L0;
+  __pyx_L1_error:;
+  __Pyx_XDECREF(__pyx_t_1);
+  __Pyx_AddTraceback("_cdec.Candidate.score.__get__", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __pyx_r = NULL;
+  __pyx_L0:;
+  __Pyx_XGIVEREF(__pyx_r);
   __Pyx_RefNannyFinishContext();
-  return NULL;
-  __pyx_L4_argument_unpacking_done:;
-  __pyx_r = __pyx_pf_5_cdec_7Decoder_6translate(((struct __pyx_obj_5_cdec_Decoder *)__pyx_v_self), __pyx_v_sentence, __pyx_v_grammar);
+  return __pyx_r;
+}
+
+/* Python wrapper */
+static int __pyx_pw_5_cdec_9Candidate_5score_3__set__(PyObject *__pyx_v_self, PyObject *__pyx_v_value); /*proto*/
+static int __pyx_pw_5_cdec_9Candidate_5score_3__set__(PyObject *__pyx_v_self, PyObject *__pyx_v_value) {
+  int __pyx_r;
+  __Pyx_RefNannyDeclarations
+  __Pyx_RefNannySetupContext("__set__ (wrapper)", 0);
+  __pyx_r = __pyx_pf_5_cdec_9Candidate_5score_2__set__(((struct __pyx_obj_5_cdec_Candidate *)__pyx_v_self), ((PyObject *)__pyx_v_value));
   __Pyx_RefNannyFinishContext();
   return __pyx_r;
 }
 
-static PyObject *__pyx_pf_5_cdec_7Decoder_6translate(struct __pyx_obj_5_cdec_Decoder *__pyx_v_self, PyObject *__pyx_v_sentence, PyObject *__pyx_v_grammar) {
-  PyObject *__pyx_v_inp = NULL;
-  BasicObserver __pyx_v_observer;
-  struct __pyx_obj_5_cdec_Hypergraph *__pyx_v_hg = 0;
-  PyObject *__pyx_r = NULL;
+static int __pyx_pf_5_cdec_9Candidate_5score_2__set__(struct __pyx_obj_5_cdec_Candidate *__pyx_v_self, PyObject *__pyx_v_value) {
+  int __pyx_r;
   __Pyx_RefNannyDeclarations
-  PyObject *__pyx_t_1 = NULL;
-  int __pyx_t_2;
-  PyObject *__pyx_t_3 = NULL;
-  char *__pyx_t_4;
+  float __pyx_t_1;
   int __pyx_lineno = 0;
   const char *__pyx_filename = NULL;
   int __pyx_clineno = 0;
-  __Pyx_RefNannySetupContext("translate", 0);
-
-  /* "_cdec.pyx":37
- * 
- *     def translate(self, sentence, grammar=None):
- *         if isinstance(sentence, unicode):             # <<<<<<<<<<<<<<
- *             inp = sentence.strip().encode('utf8')
- *         elif isinstance(sentence, str):
- */
-  __pyx_t_1 = ((PyObject *)((PyObject*)(&PyUnicode_Type)));
-  __Pyx_INCREF(__pyx_t_1);
-  __pyx_t_2 = __Pyx_TypeCheck(__pyx_v_sentence, __pyx_t_1); 
-  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
-  if (__pyx_t_2) {
-
-    /* "_cdec.pyx":38
- *     def translate(self, sentence, grammar=None):
- *         if isinstance(sentence, unicode):
- *             inp = sentence.strip().encode('utf8')             # <<<<<<<<<<<<<<
- *         elif isinstance(sentence, str):
- *             inp = sentence.strip()
- */
-    __pyx_t_1 = PyObject_GetAttr(__pyx_v_sentence, __pyx_n_s__strip); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 38; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-    __Pyx_GOTREF(__pyx_t_1);
-    __pyx_t_3 = PyObject_Call(__pyx_t_1, ((PyObject *)__pyx_empty_tuple), NULL); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 38; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-    __Pyx_GOTREF(__pyx_t_3);
-    __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
-    __pyx_t_1 = PyObject_GetAttr(__pyx_t_3, __pyx_n_s__encode); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 38; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-    __Pyx_GOTREF(__pyx_t_1);
-    __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
-    __pyx_t_3 = PyObject_Call(__pyx_t_1, ((PyObject *)__pyx_k_tuple_20), NULL); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 38; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-    __Pyx_GOTREF(__pyx_t_3);
-    __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
-    __pyx_v_inp = __pyx_t_3;
-    __pyx_t_3 = 0;
-    goto __pyx_L3;
-  }
-
-  /* "_cdec.pyx":39
- *         if isinstance(sentence, unicode):
- *             inp = sentence.strip().encode('utf8')
- *         elif isinstance(sentence, str):             # <<<<<<<<<<<<<<
- *             inp = sentence.strip()
- *         elif isinstance(sentence, Lattice):
- */
-  __pyx_t_3 = ((PyObject *)((PyObject*)(&PyString_Type)));
-  __Pyx_INCREF(__pyx_t_3);
-  __pyx_t_2 = __Pyx_TypeCheck(__pyx_v_sentence, __pyx_t_3); 
-  __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
-  if (__pyx_t_2) {
-
-    /* "_cdec.pyx":40
- *             inp = sentence.strip().encode('utf8')
- *         elif isinstance(sentence, str):
- *             inp = sentence.strip()             # <<<<<<<<<<<<<<
- *         elif isinstance(sentence, Lattice):
- *             inp = str(sentence) # PLF format
- */
-    __pyx_t_3 = PyObject_GetAttr(__pyx_v_sentence, __pyx_n_s__strip); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 40; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-    __Pyx_GOTREF(__pyx_t_3);
-    __pyx_t_1 = PyObject_Call(__pyx_t_3, ((PyObject *)__pyx_empty_tuple), NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 40; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-    __Pyx_GOTREF(__pyx_t_1);
-    __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
-    __pyx_v_inp = __pyx_t_1;
-    __pyx_t_1 = 0;
-    goto __pyx_L3;
-  }
+  __Pyx_RefNannySetupContext("__set__", 0);
+  __pyx_t_1 = __pyx_PyFloat_AsFloat(__pyx_v_value); if (unlikely((__pyx_t_1 == (float)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 15; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_v_self->score = __pyx_t_1;
 
-  /* "_cdec.pyx":41
- *         elif isinstance(sentence, str):
- *             inp = sentence.strip()
- *         elif isinstance(sentence, Lattice):             # <<<<<<<<<<<<<<
- *             inp = str(sentence) # PLF format
- *         else:
- */
-  __pyx_t_1 = ((PyObject *)((PyObject*)__pyx_ptype_5_cdec_Lattice));
-  __Pyx_INCREF(__pyx_t_1);
-  __pyx_t_2 = __Pyx_TypeCheck(__pyx_v_sentence, __pyx_t_1); 
-  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
-  if (__pyx_t_2) {
+  __pyx_r = 0;
+  goto __pyx_L0;
+  __pyx_L1_error:;
+  __Pyx_AddTraceback("_cdec.Candidate.score.__set__", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __pyx_r = -1;
+  __pyx_L0:;
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
 
-    /* "_cdec.pyx":42
- *             inp = sentence.strip()
- *         elif isinstance(sentence, Lattice):
- *             inp = str(sentence) # PLF format             # <<<<<<<<<<<<<<
- *         else:
- *             raise TypeError('Cannot translate input type %s' % type(sentence))
- */
-    __pyx_t_1 = PyTuple_New(1); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 42; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-    __Pyx_GOTREF(__pyx_t_1);
-    __Pyx_INCREF(__pyx_v_sentence);
-    PyTuple_SET_ITEM(__pyx_t_1, 0, __pyx_v_sentence);
-    __Pyx_GIVEREF(__pyx_v_sentence);
-    __pyx_t_3 = PyObject_Call(((PyObject *)((PyObject*)(&PyString_Type))), ((PyObject *)__pyx_t_1), NULL); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 42; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-    __Pyx_GOTREF(__pyx_t_3);
-    __Pyx_DECREF(((PyObject *)__pyx_t_1)); __pyx_t_1 = 0;
-    __pyx_v_inp = __pyx_t_3;
-    __pyx_t_3 = 0;
-    goto __pyx_L3;
-  }
-  /*else*/ {
+/* Python wrapper */
+static void __pyx_pw_5_cdec_15SufficientStats_1__dealloc__(PyObject *__pyx_v_self); /*proto*/
+static void __pyx_pw_5_cdec_15SufficientStats_1__dealloc__(PyObject *__pyx_v_self) {
+  __Pyx_RefNannyDeclarations
+  __Pyx_RefNannySetupContext("__dealloc__ (wrapper)", 0);
+  __pyx_pf_5_cdec_15SufficientStats___dealloc__(((struct __pyx_obj_5_cdec_SufficientStats *)__pyx_v_self));
+  __Pyx_RefNannyFinishContext();
+}
 
-    /* "_cdec.pyx":44
- *             inp = str(sentence) # PLF format
- *         else:
- *             raise TypeError('Cannot translate input type %s' % type(sentence))             # <<<<<<<<<<<<<<
- *         if grammar:
- *             self.dec.SetSentenceGrammarFromString(string(<char *> grammar))
+/* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":31
+ *     cdef mteval.EvaluationMetric* metric
+ * 
+ *     def __dealloc__(self):             # <<<<<<<<<<<<<<
+ *         del self.stats
+ * 
  */
-    __pyx_t_3 = PyNumber_Remainder(((PyObject *)__pyx_kp_s_21), ((PyObject *)Py_TYPE(__pyx_v_sentence))); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 44; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-    __Pyx_GOTREF(((PyObject *)__pyx_t_3));
-    __pyx_t_1 = PyTuple_New(1); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 44; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-    __Pyx_GOTREF(__pyx_t_1);
-    PyTuple_SET_ITEM(__pyx_t_1, 0, ((PyObject *)__pyx_t_3));
-    __Pyx_GIVEREF(((PyObject *)__pyx_t_3));
-    __pyx_t_3 = 0;
-    __pyx_t_3 = PyObject_Call(__pyx_builtin_TypeError, ((PyObject *)__pyx_t_1), NULL); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 44; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-    __Pyx_GOTREF(__pyx_t_3);
-    __Pyx_DECREF(((PyObject *)__pyx_t_1)); __pyx_t_1 = 0;
-    __Pyx_Raise(__pyx_t_3, 0, 0, 0);
-    __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
-    {__pyx_filename = __pyx_f[0]; __pyx_lineno = 44; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  }
-  __pyx_L3:;
 
-  /* "_cdec.pyx":45
- *         else:
- *             raise TypeError('Cannot translate input type %s' % type(sentence))
- *         if grammar:             # <<<<<<<<<<<<<<
- *             self.dec.SetSentenceGrammarFromString(string(<char *> grammar))
- *         cdef decoder.BasicObserver observer = decoder.BasicObserver()
- */
-  __pyx_t_2 = __Pyx_PyObject_IsTrue(__pyx_v_grammar); if (unlikely(__pyx_t_2 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 45; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  if (__pyx_t_2) {
+static void __pyx_pf_5_cdec_15SufficientStats___dealloc__(CYTHON_UNUSED struct __pyx_obj_5_cdec_SufficientStats *__pyx_v_self) {
+  __Pyx_RefNannyDeclarations
+  __Pyx_RefNannySetupContext("__dealloc__", 0);
 
-    /* "_cdec.pyx":46
- *             raise TypeError('Cannot translate input type %s' % type(sentence))
- *         if grammar:
- *             self.dec.SetSentenceGrammarFromString(string(<char *> grammar))             # <<<<<<<<<<<<<<
- *         cdef decoder.BasicObserver observer = decoder.BasicObserver()
- *         self.dec.Decode(string(<char *>inp), &observer)
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":32
+ * 
+ *     def __dealloc__(self):
+ *         del self.stats             # <<<<<<<<<<<<<<
+ * 
+ *     property score:
  */
-    __pyx_t_4 = PyBytes_AsString(__pyx_v_grammar); if (unlikely((!__pyx_t_4) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 46; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-    __pyx_v_self->dec->SetSentenceGrammarFromString(std::string(((char *)__pyx_t_4)));
-    goto __pyx_L4;
-  }
-  __pyx_L4:;
+  delete __pyx_v_self->stats;
 
-  /* "_cdec.pyx":47
- *         if grammar:
- *             self.dec.SetSentenceGrammarFromString(string(<char *> grammar))
- *         cdef decoder.BasicObserver observer = decoder.BasicObserver()             # <<<<<<<<<<<<<<
- *         self.dec.Decode(string(<char *>inp), &observer)
- *         if observer.hypergraph == NULL:
- */
-  __pyx_v_observer = BasicObserver();
+  __Pyx_RefNannyFinishContext();
+}
 
-  /* "_cdec.pyx":48
- *             self.dec.SetSentenceGrammarFromString(string(<char *> grammar))
- *         cdef decoder.BasicObserver observer = decoder.BasicObserver()
- *         self.dec.Decode(string(<char *>inp), &observer)             # <<<<<<<<<<<<<<
- *         if observer.hypergraph == NULL:
- *             raise ParseFailed()
- */
-  __pyx_t_4 = PyBytes_AsString(__pyx_v_inp); if (unlikely((!__pyx_t_4) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 48; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __pyx_v_self->dec->Decode(std::string(((char *)__pyx_t_4)), (&__pyx_v_observer));
+/* Python wrapper */
+static PyObject *__pyx_pw_5_cdec_15SufficientStats_5score_1__get__(PyObject *__pyx_v_self); /*proto*/
+static PyObject *__pyx_pw_5_cdec_15SufficientStats_5score_1__get__(PyObject *__pyx_v_self) {
+  PyObject *__pyx_r = 0;
+  __Pyx_RefNannyDeclarations
+  __Pyx_RefNannySetupContext("__get__ (wrapper)", 0);
+  __pyx_r = __pyx_pf_5_cdec_15SufficientStats_5score___get__(((struct __pyx_obj_5_cdec_SufficientStats *)__pyx_v_self));
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
 
-  /* "_cdec.pyx":49
- *         cdef decoder.BasicObserver observer = decoder.BasicObserver()
- *         self.dec.Decode(string(<char *>inp), &observer)
- *         if observer.hypergraph == NULL:             # <<<<<<<<<<<<<<
- *             raise ParseFailed()
- *         cdef Hypergraph hg = Hypergraph()
+/* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":35
+ * 
+ *     property score:
+ *         def __get__(self):             # <<<<<<<<<<<<<<
+ *             return self.metric.ComputeScore(self.stats[0])
+ * 
  */
-  __pyx_t_2 = (__pyx_v_observer.hypergraph == NULL);
-  if (__pyx_t_2) {
 
-    /* "_cdec.pyx":50
- *         self.dec.Decode(string(<char *>inp), &observer)
- *         if observer.hypergraph == NULL:
- *             raise ParseFailed()             # <<<<<<<<<<<<<<
- *         cdef Hypergraph hg = Hypergraph()
- *         hg.hg = new hypergraph.Hypergraph(observer.hypergraph[0])
- */
-    __pyx_t_3 = __Pyx_GetName(__pyx_m, __pyx_n_s__ParseFailed); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 50; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-    __Pyx_GOTREF(__pyx_t_3);
-    __pyx_t_1 = PyObject_Call(__pyx_t_3, ((PyObject *)__pyx_empty_tuple), NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 50; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-    __Pyx_GOTREF(__pyx_t_1);
-    __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
-    __Pyx_Raise(__pyx_t_1, 0, 0, 0);
-    __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
-    {__pyx_filename = __pyx_f[0]; __pyx_lineno = 50; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-    goto __pyx_L5;
-  }
-  __pyx_L5:;
+static PyObject *__pyx_pf_5_cdec_15SufficientStats_5score___get__(struct __pyx_obj_5_cdec_SufficientStats *__pyx_v_self) {
+  PyObject *__pyx_r = NULL;
+  __Pyx_RefNannyDeclarations
+  PyObject *__pyx_t_1 = NULL;
+  int __pyx_lineno = 0;
+  const char *__pyx_filename = NULL;
+  int __pyx_clineno = 0;
+  __Pyx_RefNannySetupContext("__get__", 0);
 
-  /* "_cdec.pyx":51
- *         if observer.hypergraph == NULL:
- *             raise ParseFailed()
- *         cdef Hypergraph hg = Hypergraph()             # <<<<<<<<<<<<<<
- *         hg.hg = new hypergraph.Hypergraph(observer.hypergraph[0])
- *         return hg
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":36
+ *     property score:
+ *         def __get__(self):
+ *             return self.metric.ComputeScore(self.stats[0])             # <<<<<<<<<<<<<<
+ * 
+ *     property detail:
  */
-  __pyx_t_1 = PyObject_Call(((PyObject *)((PyObject*)__pyx_ptype_5_cdec_Hypergraph)), ((PyObject *)__pyx_empty_tuple), NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 51; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_XDECREF(__pyx_r);
+  __pyx_t_1 = PyFloat_FromDouble(__pyx_v_self->metric->ComputeScore((__pyx_v_self->stats[0]))); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 36; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __Pyx_GOTREF(__pyx_t_1);
-  __pyx_v_hg = ((struct __pyx_obj_5_cdec_Hypergraph *)__pyx_t_1);
+  __pyx_r = __pyx_t_1;
   __pyx_t_1 = 0;
-
-  /* "_cdec.pyx":52
- *             raise ParseFailed()
- *         cdef Hypergraph hg = Hypergraph()
- *         hg.hg = new hypergraph.Hypergraph(observer.hypergraph[0])             # <<<<<<<<<<<<<<
- *         return hg
- */
-  __pyx_v_hg->hg = new Hypergraph((__pyx_v_observer.hypergraph[0]));
-
-  /* "_cdec.pyx":53
- *         cdef Hypergraph hg = Hypergraph()
- *         hg.hg = new hypergraph.Hypergraph(observer.hypergraph[0])
- *         return hg             # <<<<<<<<<<<<<<
- */
-  __Pyx_XDECREF(__pyx_r);
-  __Pyx_INCREF(((PyObject *)__pyx_v_hg));
-  __pyx_r = ((PyObject *)__pyx_v_hg);
   goto __pyx_L0;
 
   __pyx_r = Py_None; __Pyx_INCREF(Py_None);
   goto __pyx_L0;
   __pyx_L1_error:;
   __Pyx_XDECREF(__pyx_t_1);
-  __Pyx_XDECREF(__pyx_t_3);
-  __Pyx_AddTraceback("_cdec.Decoder.translate", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __Pyx_AddTraceback("_cdec.SufficientStats.score.__get__", __pyx_clineno, __pyx_lineno, __pyx_filename);
   __pyx_r = NULL;
   __pyx_L0:;
-  __Pyx_XDECREF(__pyx_v_inp);
-  __Pyx_XDECREF((PyObject *)__pyx_v_hg);
   __Pyx_XGIVEREF(__pyx_r);
   __Pyx_RefNannyFinishContext();
   return __pyx_r;
 }
 
 /* Python wrapper */
-static PyObject *__pyx_pw_5_cdec_7Decoder_7weights_1__get__(PyObject *__pyx_v_self); /*proto*/
-static PyObject *__pyx_pw_5_cdec_7Decoder_7weights_1__get__(PyObject *__pyx_v_self) {
+static PyObject *__pyx_pw_5_cdec_15SufficientStats_6detail_1__get__(PyObject *__pyx_v_self); /*proto*/
+static PyObject *__pyx_pw_5_cdec_15SufficientStats_6detail_1__get__(PyObject *__pyx_v_self) {
   PyObject *__pyx_r = 0;
   __Pyx_RefNannyDeclarations
   __Pyx_RefNannySetupContext("__get__ (wrapper)", 0);
-  __pyx_r = __pyx_pf_5_cdec_7Decoder_7weights___get__(((struct __pyx_obj_5_cdec_Decoder *)__pyx_v_self));
+  __pyx_r = __pyx_pf_5_cdec_15SufficientStats_6detail___get__(((struct __pyx_obj_5_cdec_SufficientStats *)__pyx_v_self));
   __Pyx_RefNannyFinishContext();
   return __pyx_r;
 }
 
-/* "_cdec.pyx":17
- * cdef class Decoder:
- *     cdef decoder.Decoder* dec
- *     cdef public DenseVector weights             # <<<<<<<<<<<<<<
+/* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":39
+ * 
+ *     property detail:
+ *         def __get__(self):             # <<<<<<<<<<<<<<
+ *             return self.metric.DetailedScore(self.stats[0]).c_str()
  * 
- *     def __cinit__(self, char* config):
  */
 
-static PyObject *__pyx_pf_5_cdec_7Decoder_7weights___get__(struct __pyx_obj_5_cdec_Decoder *__pyx_v_self) {
+static PyObject *__pyx_pf_5_cdec_15SufficientStats_6detail___get__(struct __pyx_obj_5_cdec_SufficientStats *__pyx_v_self) {
   PyObject *__pyx_r = NULL;
   __Pyx_RefNannyDeclarations
+  PyObject *__pyx_t_1 = NULL;
+  int __pyx_lineno = 0;
+  const char *__pyx_filename = NULL;
+  int __pyx_clineno = 0;
   __Pyx_RefNannySetupContext("__get__", 0);
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":40
+ *     property detail:
+ *         def __get__(self):
+ *             return self.metric.DetailedScore(self.stats[0]).c_str()             # <<<<<<<<<<<<<<
+ * 
+ *     def __len__(self):
+ */
   __Pyx_XDECREF(__pyx_r);
-  __Pyx_INCREF(((PyObject *)__pyx_v_self->weights));
-  __pyx_r = ((PyObject *)__pyx_v_self->weights);
+  __pyx_t_1 = PyBytes_FromString(__pyx_v_self->metric->DetailedScore((__pyx_v_self->stats[0])).c_str()); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 40; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(((PyObject *)__pyx_t_1));
+  __pyx_r = ((PyObject *)__pyx_t_1);
+  __pyx_t_1 = 0;
   goto __pyx_L0;
 
   __pyx_r = Py_None; __Pyx_INCREF(Py_None);
+  goto __pyx_L0;
+  __pyx_L1_error:;
+  __Pyx_XDECREF(__pyx_t_1);
+  __Pyx_AddTraceback("_cdec.SufficientStats.detail.__get__", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __pyx_r = NULL;
   __pyx_L0:;
   __Pyx_XGIVEREF(__pyx_r);
   __Pyx_RefNannyFinishContext();
@@ -5779,101 +6059,3402 @@ static PyObject *__pyx_pf_5_cdec_7Decoder_7weights___get__(struct __pyx_obj_5_cd
 }
 
 /* Python wrapper */
-static int __pyx_pw_5_cdec_7Decoder_7weights_3__set__(PyObject *__pyx_v_self, PyObject *__pyx_v_value); /*proto*/
-static int __pyx_pw_5_cdec_7Decoder_7weights_3__set__(PyObject *__pyx_v_self, PyObject *__pyx_v_value) {
-  int __pyx_r;
+static Py_ssize_t __pyx_pw_5_cdec_15SufficientStats_3__len__(PyObject *__pyx_v_self); /*proto*/
+static Py_ssize_t __pyx_pw_5_cdec_15SufficientStats_3__len__(PyObject *__pyx_v_self) {
+  Py_ssize_t __pyx_r;
   __Pyx_RefNannyDeclarations
-  __Pyx_RefNannySetupContext("__set__ (wrapper)", 0);
-  __pyx_r = __pyx_pf_5_cdec_7Decoder_7weights_2__set__(((struct __pyx_obj_5_cdec_Decoder *)__pyx_v_self), ((PyObject *)__pyx_v_value));
+  __Pyx_RefNannySetupContext("__len__ (wrapper)", 0);
+  __pyx_r = __pyx_pf_5_cdec_15SufficientStats_2__len__(((struct __pyx_obj_5_cdec_SufficientStats *)__pyx_v_self));
   __Pyx_RefNannyFinishContext();
   return __pyx_r;
 }
 
-static int __pyx_pf_5_cdec_7Decoder_7weights_2__set__(struct __pyx_obj_5_cdec_Decoder *__pyx_v_self, PyObject *__pyx_v_value) {
-  int __pyx_r;
+/* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":42
+ *             return self.metric.DetailedScore(self.stats[0]).c_str()
+ * 
+ *     def __len__(self):             # <<<<<<<<<<<<<<
+ *         return self.stats.size()
+ * 
+ */
+
+static Py_ssize_t __pyx_pf_5_cdec_15SufficientStats_2__len__(struct __pyx_obj_5_cdec_SufficientStats *__pyx_v_self) {
+  Py_ssize_t __pyx_r;
+  __Pyx_RefNannyDeclarations
+  __Pyx_RefNannySetupContext("__len__", 0);
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":43
+ * 
+ *     def __len__(self):
+ *         return self.stats.size()             # <<<<<<<<<<<<<<
+ * 
+ *     def __iter__(self):
+ */
+  __pyx_r = __pyx_v_self->stats->size();
+  goto __pyx_L0;
+
+  __pyx_r = 0;
+  __pyx_L0:;
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+static PyObject *__pyx_gb_5_cdec_15SufficientStats_6generator7(__pyx_GeneratorObject *__pyx_generator, PyObject *__pyx_sent_value); /* proto */
+
+/* Python wrapper */
+static PyObject *__pyx_pw_5_cdec_15SufficientStats_5__iter__(PyObject *__pyx_v_self); /*proto*/
+static PyObject *__pyx_pw_5_cdec_15SufficientStats_5__iter__(PyObject *__pyx_v_self) {
+  PyObject *__pyx_r = 0;
+  __Pyx_RefNannyDeclarations
+  __Pyx_RefNannySetupContext("__iter__ (wrapper)", 0);
+  __pyx_r = __pyx_pf_5_cdec_15SufficientStats_4__iter__(((struct __pyx_obj_5_cdec_SufficientStats *)__pyx_v_self));
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+/* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":45
+ *         return self.stats.size()
+ * 
+ *     def __iter__(self):             # <<<<<<<<<<<<<<
+ *         for i in range(len(self)):
+ *             yield self.stats[0][i]
+ */
+
+static PyObject *__pyx_pf_5_cdec_15SufficientStats_4__iter__(struct __pyx_obj_5_cdec_SufficientStats *__pyx_v_self) {
+  struct __pyx_obj_5_cdec___pyx_scope_struct_7___iter__ *__pyx_cur_scope;
+  PyObject *__pyx_r = NULL;
   __Pyx_RefNannyDeclarations
   int __pyx_lineno = 0;
   const char *__pyx_filename = NULL;
   int __pyx_clineno = 0;
-  __Pyx_RefNannySetupContext("__set__", 0);
-  if (!(likely(((__pyx_v_value) == Py_None) || likely(__Pyx_TypeTest(__pyx_v_value, __pyx_ptype_5_cdec_DenseVector))))) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 17; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __Pyx_INCREF(__pyx_v_value);
-  __Pyx_GIVEREF(__pyx_v_value);
-  __Pyx_GOTREF(__pyx_v_self->weights);
-  __Pyx_DECREF(((PyObject *)__pyx_v_self->weights));
-  __pyx_v_self->weights = ((struct __pyx_obj_5_cdec_DenseVector *)__pyx_v_value);
+  __Pyx_RefNannySetupContext("__iter__", 0);
+  __pyx_cur_scope = (struct __pyx_obj_5_cdec___pyx_scope_struct_7___iter__ *)__pyx_ptype_5_cdec___pyx_scope_struct_7___iter__->tp_new(__pyx_ptype_5_cdec___pyx_scope_struct_7___iter__, __pyx_empty_tuple, NULL);
+  if (unlikely(!__pyx_cur_scope)) {
+    __Pyx_RefNannyFinishContext();
+    return NULL;
+  }
+  __Pyx_GOTREF(__pyx_cur_scope);
+  __pyx_cur_scope->__pyx_v_self = __pyx_v_self;
+  __Pyx_INCREF((PyObject *)__pyx_cur_scope->__pyx_v_self);
+  __Pyx_GIVEREF((PyObject *)__pyx_cur_scope->__pyx_v_self);
+  {
+    __pyx_GeneratorObject *gen = __Pyx_Generator_New((__pyx_generator_body_t) __pyx_gb_5_cdec_15SufficientStats_6generator7, (PyObject *) __pyx_cur_scope); if (unlikely(!gen)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 45; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_DECREF(__pyx_cur_scope);
+    __Pyx_RefNannyFinishContext();
+    return (PyObject *) gen;
+  }
 
-  __pyx_r = 0;
+  __pyx_r = Py_None; __Pyx_INCREF(Py_None);
   goto __pyx_L0;
   __pyx_L1_error:;
-  __Pyx_AddTraceback("_cdec.Decoder.weights.__set__", __pyx_clineno, __pyx_lineno, __pyx_filename);
-  __pyx_r = -1;
+  __Pyx_AddTraceback("_cdec.SufficientStats.__iter__", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __pyx_r = NULL;
   __pyx_L0:;
+  __Pyx_DECREF(((PyObject *)__pyx_cur_scope));
+  __Pyx_XGIVEREF(__pyx_r);
   __Pyx_RefNannyFinishContext();
   return __pyx_r;
 }
 
+static PyObject *__pyx_gb_5_cdec_15SufficientStats_6generator7(__pyx_GeneratorObject *__pyx_generator, PyObject *__pyx_sent_value) /* generator body */
+{
+  struct __pyx_obj_5_cdec___pyx_scope_struct_7___iter__ *__pyx_cur_scope = ((struct __pyx_obj_5_cdec___pyx_scope_struct_7___iter__ *)__pyx_generator->closure);
+  PyObject *__pyx_r = NULL;
+  Py_ssize_t __pyx_t_1;
+  PyObject *__pyx_t_2 = NULL;
+  PyObject *__pyx_t_3 = NULL;
+  PyObject *(*__pyx_t_4)(PyObject *);
+  unsigned int __pyx_t_5;
+  __Pyx_RefNannyDeclarations
+  __Pyx_RefNannySetupContext("None", 0);
+  switch (__pyx_generator->resume_label) {
+    case 0: goto __pyx_L3_first_run;
+    case 1: goto __pyx_L6_resume_from_yield;
+    default: /* CPython raises the right error here */
+    __Pyx_RefNannyFinishContext();
+    return NULL;
+  }
+  __pyx_L3_first_run:;
+  if (unlikely(!__pyx_sent_value)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 45; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":46
+ * 
+ *     def __iter__(self):
+ *         for i in range(len(self)):             # <<<<<<<<<<<<<<
+ *             yield self.stats[0][i]
+ * 
+ */
+  __pyx_t_1 = PyObject_Length(((PyObject *)__pyx_cur_scope->__pyx_v_self)); if (unlikely(__pyx_t_1 == -1)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 46; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_2 = PyInt_FromSsize_t(__pyx_t_1); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 46; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_2);
+  __pyx_t_3 = PyTuple_New(1); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 46; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_3);
+  PyTuple_SET_ITEM(__pyx_t_3, 0, __pyx_t_2);
+  __Pyx_GIVEREF(__pyx_t_2);
+  __pyx_t_2 = 0;
+  __pyx_t_2 = PyObject_Call(__pyx_builtin_range, ((PyObject *)__pyx_t_3), NULL); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 46; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_2);
+  __Pyx_DECREF(((PyObject *)__pyx_t_3)); __pyx_t_3 = 0;
+  if (PyList_CheckExact(__pyx_t_2) || PyTuple_CheckExact(__pyx_t_2)) {
+    __pyx_t_3 = __pyx_t_2; __Pyx_INCREF(__pyx_t_3); __pyx_t_1 = 0;
+    __pyx_t_4 = NULL;
+  } else {
+    __pyx_t_1 = -1; __pyx_t_3 = PyObject_GetIter(__pyx_t_2); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 46; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_3);
+    __pyx_t_4 = Py_TYPE(__pyx_t_3)->tp_iternext;
+  }
+  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+  for (;;) {
+    if (!__pyx_t_4 && PyList_CheckExact(__pyx_t_3)) {
+      if (__pyx_t_1 >= PyList_GET_SIZE(__pyx_t_3)) break;
+      __pyx_t_2 = PyList_GET_ITEM(__pyx_t_3, __pyx_t_1); __Pyx_INCREF(__pyx_t_2); __pyx_t_1++;
+    } else if (!__pyx_t_4 && PyTuple_CheckExact(__pyx_t_3)) {
+      if (__pyx_t_1 >= PyTuple_GET_SIZE(__pyx_t_3)) break;
+      __pyx_t_2 = PyTuple_GET_ITEM(__pyx_t_3, __pyx_t_1); __Pyx_INCREF(__pyx_t_2); __pyx_t_1++;
+    } else {
+      __pyx_t_2 = __pyx_t_4(__pyx_t_3);
+      if (unlikely(!__pyx_t_2)) {
+        if (PyErr_Occurred()) {
+          if (likely(PyErr_ExceptionMatches(PyExc_StopIteration))) PyErr_Clear();
+          else {__pyx_filename = __pyx_f[4]; __pyx_lineno = 46; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+        }
+        break;
+      }
+      __Pyx_GOTREF(__pyx_t_2);
+    }
+    __Pyx_XGOTREF(__pyx_cur_scope->__pyx_v_i);
+    __Pyx_XDECREF(__pyx_cur_scope->__pyx_v_i);
+    __Pyx_GIVEREF(__pyx_t_2);
+    __pyx_cur_scope->__pyx_v_i = __pyx_t_2;
+    __pyx_t_2 = 0;
+
+    /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":47
+ *     def __iter__(self):
+ *         for i in range(len(self)):
+ *             yield self.stats[0][i]             # <<<<<<<<<<<<<<
+ * 
+ *     def __iadd__(SufficientStats self, SufficientStats other):
+ */
+    __pyx_t_5 = __Pyx_PyInt_AsUnsignedInt(__pyx_cur_scope->__pyx_v_i); if (unlikely((__pyx_t_5 == (unsigned int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 47; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_t_2 = PyFloat_FromDouble(((__pyx_cur_scope->__pyx_v_self->stats[0])[__pyx_t_5])); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 47; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_2);
+    __pyx_r = __pyx_t_2;
+    __pyx_t_2 = 0;
+    __pyx_cur_scope->__pyx_t_0 = __pyx_t_1;
+    __Pyx_XGIVEREF(__pyx_t_3);
+    __pyx_cur_scope->__pyx_t_1 = __pyx_t_3;
+    __pyx_cur_scope->__pyx_t_2 = __pyx_t_4;
+    __Pyx_XGIVEREF(__pyx_r);
+    __Pyx_RefNannyFinishContext();
+    /* return from generator, yielding value */
+    __pyx_generator->resume_label = 1;
+    return __pyx_r;
+    __pyx_L6_resume_from_yield:;
+    __pyx_t_1 = __pyx_cur_scope->__pyx_t_0;
+    __pyx_t_3 = __pyx_cur_scope->__pyx_t_1;
+    __pyx_cur_scope->__pyx_t_1 = 0;
+    __Pyx_XGOTREF(__pyx_t_3);
+    __pyx_t_4 = __pyx_cur_scope->__pyx_t_2;
+    if (unlikely(!__pyx_sent_value)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 47; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  }
+  __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
+  PyErr_SetNone(PyExc_StopIteration);
+  goto __pyx_L0;
+  __pyx_L1_error:;
+  __Pyx_XDECREF(__pyx_t_2);
+  __Pyx_XDECREF(__pyx_t_3);
+  __Pyx_AddTraceback("__iter__", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __pyx_L0:;
+  __Pyx_XDECREF(__pyx_r);
+  __pyx_generator->resume_label = -1;
+  __Pyx_RefNannyFinishContext();
+  return NULL;
+}
+
 /* Python wrapper */
-static int __pyx_pw_5_cdec_7Decoder_7weights_5__del__(PyObject *__pyx_v_self); /*proto*/
-static int __pyx_pw_5_cdec_7Decoder_7weights_5__del__(PyObject *__pyx_v_self) {
-  int __pyx_r;
+static PyObject *__pyx_pw_5_cdec_15SufficientStats_8__iadd__(PyObject *__pyx_v_self, PyObject *__pyx_v_other); /*proto*/
+static PyObject *__pyx_pw_5_cdec_15SufficientStats_8__iadd__(PyObject *__pyx_v_self, PyObject *__pyx_v_other) {
+  PyObject *__pyx_r = 0;
   __Pyx_RefNannyDeclarations
-  __Pyx_RefNannySetupContext("__del__ (wrapper)", 0);
-  __pyx_r = __pyx_pf_5_cdec_7Decoder_7weights_4__del__(((struct __pyx_obj_5_cdec_Decoder *)__pyx_v_self));
+  __Pyx_RefNannySetupContext("__iadd__ (wrapper)", 0);
+  if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_other), __pyx_ptype_5_cdec_SufficientStats, 1, "other", 0))) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 49; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_r = __pyx_pf_5_cdec_15SufficientStats_7__iadd__(((struct __pyx_obj_5_cdec_SufficientStats *)__pyx_v_self), ((struct __pyx_obj_5_cdec_SufficientStats *)__pyx_v_other));
+  goto __pyx_L0;
+  __pyx_L1_error:;
+  __pyx_r = NULL;
+  __pyx_L0:;
   __Pyx_RefNannyFinishContext();
   return __pyx_r;
 }
 
-static int __pyx_pf_5_cdec_7Decoder_7weights_4__del__(struct __pyx_obj_5_cdec_Decoder *__pyx_v_self) {
-  int __pyx_r;
+/* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":49
+ *             yield self.stats[0][i]
+ * 
+ *     def __iadd__(SufficientStats self, SufficientStats other):             # <<<<<<<<<<<<<<
+ *         self.stats[0] += other.stats[0]
+ *         return self
+ */
+
+static PyObject *__pyx_pf_5_cdec_15SufficientStats_7__iadd__(struct __pyx_obj_5_cdec_SufficientStats *__pyx_v_self, struct __pyx_obj_5_cdec_SufficientStats *__pyx_v_other) {
+  PyObject *__pyx_r = NULL;
   __Pyx_RefNannyDeclarations
-  __Pyx_RefNannySetupContext("__del__", 0);
-  __Pyx_INCREF(Py_None);
-  __Pyx_GIVEREF(Py_None);
-  __Pyx_GOTREF(__pyx_v_self->weights);
-  __Pyx_DECREF(((PyObject *)__pyx_v_self->weights));
-  __pyx_v_self->weights = ((struct __pyx_obj_5_cdec_DenseVector *)Py_None);
+  __Pyx_RefNannySetupContext("__iadd__", 0);
 
-  __pyx_r = 0;
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":50
+ * 
+ *     def __iadd__(SufficientStats self, SufficientStats other):
+ *         self.stats[0] += other.stats[0]             # <<<<<<<<<<<<<<
+ *         return self
+ * 
+ */
+  (__pyx_v_self->stats[0]) += (__pyx_v_other->stats[0]);
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":51
+ *     def __iadd__(SufficientStats self, SufficientStats other):
+ *         self.stats[0] += other.stats[0]
+ *         return self             # <<<<<<<<<<<<<<
+ * 
+ *     def __add__(SufficientStats x, SufficientStats y):
+ */
+  __Pyx_XDECREF(__pyx_r);
+  __Pyx_INCREF(((PyObject *)__pyx_v_self));
+  __pyx_r = ((PyObject *)__pyx_v_self);
+  goto __pyx_L0;
+
+  __pyx_r = Py_None; __Pyx_INCREF(Py_None);
+  __pyx_L0:;
+  __Pyx_XGIVEREF(__pyx_r);
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+/* Python wrapper */
+static PyObject *__pyx_pw_5_cdec_15SufficientStats_10__add__(PyObject *__pyx_v_x, PyObject *__pyx_v_y); /*proto*/
+static PyObject *__pyx_pw_5_cdec_15SufficientStats_10__add__(PyObject *__pyx_v_x, PyObject *__pyx_v_y) {
+  PyObject *__pyx_r = 0;
+  __Pyx_RefNannyDeclarations
+  __Pyx_RefNannySetupContext("__add__ (wrapper)", 0);
+  if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_x), __pyx_ptype_5_cdec_SufficientStats, 1, "x", 0))) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 53; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_y), __pyx_ptype_5_cdec_SufficientStats, 1, "y", 0))) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 53; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_r = __pyx_pf_5_cdec_15SufficientStats_9__add__(((struct __pyx_obj_5_cdec_SufficientStats *)__pyx_v_x), ((struct __pyx_obj_5_cdec_SufficientStats *)__pyx_v_y));
+  goto __pyx_L0;
+  __pyx_L1_error:;
+  __pyx_r = NULL;
+  __pyx_L0:;
   __Pyx_RefNannyFinishContext();
   return __pyx_r;
 }
 
-static PyObject *__pyx_tp_new_5_cdec_DenseVector(PyTypeObject *t, PyObject *a, PyObject *k) {
+/* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":53
+ *         return self
+ * 
+ *     def __add__(SufficientStats x, SufficientStats y):             # <<<<<<<<<<<<<<
+ *         cdef SufficientStats result = SufficientStats()
+ *         result.stats = new mteval.SufficientStats(mteval.add(x.stats[0], y.stats[0]))
+ */
+
+static PyObject *__pyx_pf_5_cdec_15SufficientStats_9__add__(struct __pyx_obj_5_cdec_SufficientStats *__pyx_v_x, struct __pyx_obj_5_cdec_SufficientStats *__pyx_v_y) {
+  struct __pyx_obj_5_cdec_SufficientStats *__pyx_v_result = 0;
+  PyObject *__pyx_r = NULL;
+  __Pyx_RefNannyDeclarations
+  PyObject *__pyx_t_1 = NULL;
+  int __pyx_lineno = 0;
+  const char *__pyx_filename = NULL;
+  int __pyx_clineno = 0;
+  __Pyx_RefNannySetupContext("__add__", 0);
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":54
+ * 
+ *     def __add__(SufficientStats x, SufficientStats y):
+ *         cdef SufficientStats result = SufficientStats()             # <<<<<<<<<<<<<<
+ *         result.stats = new mteval.SufficientStats(mteval.add(x.stats[0], y.stats[0]))
+ *         result.metric = x.metric
+ */
+  __pyx_t_1 = PyObject_Call(((PyObject *)((PyObject*)__pyx_ptype_5_cdec_SufficientStats)), ((PyObject *)__pyx_empty_tuple), NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 54; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_1);
+  __pyx_v_result = ((struct __pyx_obj_5_cdec_SufficientStats *)__pyx_t_1);
+  __pyx_t_1 = 0;
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":55
+ *     def __add__(SufficientStats x, SufficientStats y):
+ *         cdef SufficientStats result = SufficientStats()
+ *         result.stats = new mteval.SufficientStats(mteval.add(x.stats[0], y.stats[0]))             # <<<<<<<<<<<<<<
+ *         result.metric = x.metric
+ *         return result
+ */
+  __pyx_v_result->stats = new SufficientStats(operator+((__pyx_v_x->stats[0]), (__pyx_v_y->stats[0])));
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":56
+ *         cdef SufficientStats result = SufficientStats()
+ *         result.stats = new mteval.SufficientStats(mteval.add(x.stats[0], y.stats[0]))
+ *         result.metric = x.metric             # <<<<<<<<<<<<<<
+ *         return result
+ * 
+ */
+  __pyx_v_result->metric = __pyx_v_x->metric;
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":57
+ *         result.stats = new mteval.SufficientStats(mteval.add(x.stats[0], y.stats[0]))
+ *         result.metric = x.metric
+ *         return result             # <<<<<<<<<<<<<<
+ * 
+ * cdef class SegmentEvaluator:
+ */
+  __Pyx_XDECREF(__pyx_r);
+  __Pyx_INCREF(((PyObject *)__pyx_v_result));
+  __pyx_r = ((PyObject *)__pyx_v_result);
+  goto __pyx_L0;
+
+  __pyx_r = Py_None; __Pyx_INCREF(Py_None);
+  goto __pyx_L0;
+  __pyx_L1_error:;
+  __Pyx_XDECREF(__pyx_t_1);
+  __Pyx_AddTraceback("_cdec.SufficientStats.__add__", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __pyx_r = NULL;
+  __pyx_L0:;
+  __Pyx_XDECREF((PyObject *)__pyx_v_result);
+  __Pyx_XGIVEREF(__pyx_r);
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+/* Python wrapper */
+static void __pyx_pw_5_cdec_16SegmentEvaluator_1__dealloc__(PyObject *__pyx_v_self); /*proto*/
+static void __pyx_pw_5_cdec_16SegmentEvaluator_1__dealloc__(PyObject *__pyx_v_self) {
+  __Pyx_RefNannyDeclarations
+  __Pyx_RefNannySetupContext("__dealloc__ (wrapper)", 0);
+  __pyx_pf_5_cdec_16SegmentEvaluator___dealloc__(((struct __pyx_obj_5_cdec_SegmentEvaluator *)__pyx_v_self));
+  __Pyx_RefNannyFinishContext();
+}
+
+/* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":63
+ *     cdef mteval.EvaluationMetric* metric
+ * 
+ *     def __dealloc__(self):             # <<<<<<<<<<<<<<
+ *         del self.scorer
+ * 
+ */
+
+static void __pyx_pf_5_cdec_16SegmentEvaluator___dealloc__(CYTHON_UNUSED struct __pyx_obj_5_cdec_SegmentEvaluator *__pyx_v_self) {
+  __Pyx_RefNannyDeclarations
+  __Pyx_RefNannySetupContext("__dealloc__", 0);
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":64
+ * 
+ *     def __dealloc__(self):
+ *         del self.scorer             # <<<<<<<<<<<<<<
+ * 
+ *     def evaluate(self, sentence):
+ */
+  delete __pyx_v_self->scorer;
+
+  __Pyx_RefNannyFinishContext();
+}
+
+/* Python wrapper */
+static PyObject *__pyx_pw_5_cdec_16SegmentEvaluator_3evaluate(PyObject *__pyx_v_self, PyObject *__pyx_v_sentence); /*proto*/
+static PyObject *__pyx_pw_5_cdec_16SegmentEvaluator_3evaluate(PyObject *__pyx_v_self, PyObject *__pyx_v_sentence) {
+  PyObject *__pyx_r = 0;
+  __Pyx_RefNannyDeclarations
+  __Pyx_RefNannySetupContext("evaluate (wrapper)", 0);
+  __pyx_r = __pyx_pf_5_cdec_16SegmentEvaluator_2evaluate(((struct __pyx_obj_5_cdec_SegmentEvaluator *)__pyx_v_self), ((PyObject *)__pyx_v_sentence));
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+/* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":66
+ *         del self.scorer
+ * 
+ *     def evaluate(self, sentence):             # <<<<<<<<<<<<<<
+ *         cdef vector[WordID] hyp
+ *         cdef SufficientStats sf = SufficientStats()
+ */
+
+static PyObject *__pyx_pf_5_cdec_16SegmentEvaluator_2evaluate(struct __pyx_obj_5_cdec_SegmentEvaluator *__pyx_v_self, PyObject *__pyx_v_sentence) {
+  std::vector<WordID> __pyx_v_hyp;
+  struct __pyx_obj_5_cdec_SufficientStats *__pyx_v_sf = 0;
+  PyObject *__pyx_r = NULL;
+  __Pyx_RefNannyDeclarations
+  PyObject *__pyx_t_1 = NULL;
+  PyObject *__pyx_t_2 = NULL;
+  int __pyx_lineno = 0;
+  const char *__pyx_filename = NULL;
+  int __pyx_clineno = 0;
+  __Pyx_RefNannySetupContext("evaluate", 0);
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":68
+ *     def evaluate(self, sentence):
+ *         cdef vector[WordID] hyp
+ *         cdef SufficientStats sf = SufficientStats()             # <<<<<<<<<<<<<<
+ *         sf.metric = self.metric
+ *         sf.stats = new mteval.SufficientStats()
+ */
+  __pyx_t_1 = PyObject_Call(((PyObject *)((PyObject*)__pyx_ptype_5_cdec_SufficientStats)), ((PyObject *)__pyx_empty_tuple), NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 68; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_1);
+  __pyx_v_sf = ((struct __pyx_obj_5_cdec_SufficientStats *)__pyx_t_1);
+  __pyx_t_1 = 0;
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":69
+ *         cdef vector[WordID] hyp
+ *         cdef SufficientStats sf = SufficientStats()
+ *         sf.metric = self.metric             # <<<<<<<<<<<<<<
+ *         sf.stats = new mteval.SufficientStats()
+ *         ConvertSentence(string(as_str(sentence.strip())), &hyp)
+ */
+  __pyx_v_sf->metric = __pyx_v_self->metric;
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":70
+ *         cdef SufficientStats sf = SufficientStats()
+ *         sf.metric = self.metric
+ *         sf.stats = new mteval.SufficientStats()             # <<<<<<<<<<<<<<
+ *         ConvertSentence(string(as_str(sentence.strip())), &hyp)
+ *         self.scorer.get().Evaluate(hyp, sf.stats)
+ */
+  __pyx_v_sf->stats = new SufficientStats();
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":71
+ *         sf.metric = self.metric
+ *         sf.stats = new mteval.SufficientStats()
+ *         ConvertSentence(string(as_str(sentence.strip())), &hyp)             # <<<<<<<<<<<<<<
+ *         self.scorer.get().Evaluate(hyp, sf.stats)
+ *         return sf
+ */
+  __pyx_t_1 = PyObject_GetAttr(__pyx_v_sentence, __pyx_n_s__strip); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 71; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_1);
+  __pyx_t_2 = PyObject_Call(__pyx_t_1, ((PyObject *)__pyx_empty_tuple), NULL); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 71; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_2);
+  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+  TD::ConvertSentence(std::string(__pyx_f_5_cdec_as_str(__pyx_t_2, NULL)), (&__pyx_v_hyp));
+  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":72
+ *         sf.stats = new mteval.SufficientStats()
+ *         ConvertSentence(string(as_str(sentence.strip())), &hyp)
+ *         self.scorer.get().Evaluate(hyp, sf.stats)             # <<<<<<<<<<<<<<
+ *         return sf
+ * 
+ */
+  __pyx_v_self->scorer->get()->Evaluate(__pyx_v_hyp, __pyx_v_sf->stats);
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":73
+ *         ConvertSentence(string(as_str(sentence.strip())), &hyp)
+ *         self.scorer.get().Evaluate(hyp, sf.stats)
+ *         return sf             # <<<<<<<<<<<<<<
+ * 
+ *     def candidate_set(self, Hypergraph hypergraph, unsigned k):
+ */
+  __Pyx_XDECREF(__pyx_r);
+  __Pyx_INCREF(((PyObject *)__pyx_v_sf));
+  __pyx_r = ((PyObject *)__pyx_v_sf);
+  goto __pyx_L0;
+
+  __pyx_r = Py_None; __Pyx_INCREF(Py_None);
+  goto __pyx_L0;
+  __pyx_L1_error:;
+  __Pyx_XDECREF(__pyx_t_1);
+  __Pyx_XDECREF(__pyx_t_2);
+  __Pyx_AddTraceback("_cdec.SegmentEvaluator.evaluate", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __pyx_r = NULL;
+  __pyx_L0:;
+  __Pyx_XDECREF((PyObject *)__pyx_v_sf);
+  __Pyx_XGIVEREF(__pyx_r);
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+static PyObject *__pyx_gb_5_cdec_16SegmentEvaluator_6generator8(__pyx_GeneratorObject *__pyx_generator, PyObject *__pyx_sent_value); /* proto */
+
+/* Python wrapper */
+static PyObject *__pyx_pw_5_cdec_16SegmentEvaluator_5candidate_set(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/
+static PyObject *__pyx_pw_5_cdec_16SegmentEvaluator_5candidate_set(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) {
+  struct __pyx_obj_5_cdec_Hypergraph *__pyx_v_hypergraph = 0;
+  unsigned int __pyx_v_k;
+  static PyObject **__pyx_pyargnames[] = {&__pyx_n_s__hypergraph,&__pyx_n_s__k,0};
+  PyObject *__pyx_r = 0;
+  __Pyx_RefNannyDeclarations
+  __Pyx_RefNannySetupContext("candidate_set (wrapper)", 0);
+  {
+    PyObject* values[2] = {0,0};
+    if (unlikely(__pyx_kwds)) {
+      Py_ssize_t kw_args;
+      const Py_ssize_t pos_args = PyTuple_GET_SIZE(__pyx_args);
+      switch (pos_args) {
+        case  2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1);
+        case  1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0);
+        case  0: break;
+        default: goto __pyx_L5_argtuple_error;
+      }
+      kw_args = PyDict_Size(__pyx_kwds);
+      switch (pos_args) {
+        case  0:
+        values[0] = PyDict_GetItem(__pyx_kwds, __pyx_n_s__hypergraph);
+        if (likely(values[0])) kw_args--;
+        else goto __pyx_L5_argtuple_error;
+        case  1:
+        values[1] = PyDict_GetItem(__pyx_kwds, __pyx_n_s__k);
+        if (likely(values[1])) kw_args--;
+        else {
+          __Pyx_RaiseArgtupleInvalid("candidate_set", 1, 2, 2, 1); {__pyx_filename = __pyx_f[4]; __pyx_lineno = 75; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+        }
+      }
+      if (unlikely(kw_args > 0)) {
+        if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "candidate_set") < 0)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 75; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+      }
+    } else if (PyTuple_GET_SIZE(__pyx_args) != 2) {
+      goto __pyx_L5_argtuple_error;
+    } else {
+      values[0] = PyTuple_GET_ITEM(__pyx_args, 0);
+      values[1] = PyTuple_GET_ITEM(__pyx_args, 1);
+    }
+    __pyx_v_hypergraph = ((struct __pyx_obj_5_cdec_Hypergraph *)values[0]);
+    __pyx_v_k = __Pyx_PyInt_AsUnsignedInt(values[1]); if (unlikely((__pyx_v_k == (unsigned int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 75; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+  }
+  goto __pyx_L4_argument_unpacking_done;
+  __pyx_L5_argtuple_error:;
+  __Pyx_RaiseArgtupleInvalid("candidate_set", 1, 2, 2, PyTuple_GET_SIZE(__pyx_args)); {__pyx_filename = __pyx_f[4]; __pyx_lineno = 75; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+  __pyx_L3_error:;
+  __Pyx_AddTraceback("_cdec.SegmentEvaluator.candidate_set", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __Pyx_RefNannyFinishContext();
+  return NULL;
+  __pyx_L4_argument_unpacking_done:;
+  if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_hypergraph), __pyx_ptype_5_cdec_Hypergraph, 1, "hypergraph", 0))) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 75; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_r = __pyx_pf_5_cdec_16SegmentEvaluator_4candidate_set(((struct __pyx_obj_5_cdec_SegmentEvaluator *)__pyx_v_self), __pyx_v_hypergraph, __pyx_v_k);
+  goto __pyx_L0;
+  __pyx_L1_error:;
+  __pyx_r = NULL;
+  __pyx_L0:;
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+/* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":75
+ *         return sf
+ * 
+ *     def candidate_set(self, Hypergraph hypergraph, unsigned k):             # <<<<<<<<<<<<<<
+ *         cdef mteval.CandidateSet* cs = new mteval.CandidateSet()
+ *         cs.AddKBestCandidates(hypergraph.hg[0], k, self.scorer.get())
+ */
+
+static PyObject *__pyx_pf_5_cdec_16SegmentEvaluator_4candidate_set(struct __pyx_obj_5_cdec_SegmentEvaluator *__pyx_v_self, struct __pyx_obj_5_cdec_Hypergraph *__pyx_v_hypergraph, unsigned int __pyx_v_k) {
+  struct __pyx_obj_5_cdec___pyx_scope_struct_8_candidate_set *__pyx_cur_scope;
+  PyObject *__pyx_r = NULL;
+  __Pyx_RefNannyDeclarations
+  int __pyx_lineno = 0;
+  const char *__pyx_filename = NULL;
+  int __pyx_clineno = 0;
+  __Pyx_RefNannySetupContext("candidate_set", 0);
+  __pyx_cur_scope = (struct __pyx_obj_5_cdec___pyx_scope_struct_8_candidate_set *)__pyx_ptype_5_cdec___pyx_scope_struct_8_candidate_set->tp_new(__pyx_ptype_5_cdec___pyx_scope_struct_8_candidate_set, __pyx_empty_tuple, NULL);
+  if (unlikely(!__pyx_cur_scope)) {
+    __Pyx_RefNannyFinishContext();
+    return NULL;
+  }
+  __Pyx_GOTREF(__pyx_cur_scope);
+  __pyx_cur_scope->__pyx_v_self = __pyx_v_self;
+  __Pyx_INCREF((PyObject *)__pyx_cur_scope->__pyx_v_self);
+  __Pyx_GIVEREF((PyObject *)__pyx_cur_scope->__pyx_v_self);
+  __pyx_cur_scope->__pyx_v_hypergraph = __pyx_v_hypergraph;
+  __Pyx_INCREF((PyObject *)__pyx_cur_scope->__pyx_v_hypergraph);
+  __Pyx_GIVEREF((PyObject *)__pyx_cur_scope->__pyx_v_hypergraph);
+  __pyx_cur_scope->__pyx_v_k = __pyx_v_k;
+  {
+    __pyx_GeneratorObject *gen = __Pyx_Generator_New((__pyx_generator_body_t) __pyx_gb_5_cdec_16SegmentEvaluator_6generator8, (PyObject *) __pyx_cur_scope); if (unlikely(!gen)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 75; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_DECREF(__pyx_cur_scope);
+    __Pyx_RefNannyFinishContext();
+    return (PyObject *) gen;
+  }
+
+  __pyx_r = Py_None; __Pyx_INCREF(Py_None);
+  goto __pyx_L0;
+  __pyx_L1_error:;
+  __Pyx_AddTraceback("_cdec.SegmentEvaluator.candidate_set", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __pyx_r = NULL;
+  __pyx_L0:;
+  __Pyx_DECREF(((PyObject *)__pyx_cur_scope));
+  __Pyx_XGIVEREF(__pyx_r);
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+static PyObject *__pyx_gb_5_cdec_16SegmentEvaluator_6generator8(__pyx_GeneratorObject *__pyx_generator, PyObject *__pyx_sent_value) /* generator body */
+{
+  struct __pyx_obj_5_cdec___pyx_scope_struct_8_candidate_set *__pyx_cur_scope = ((struct __pyx_obj_5_cdec___pyx_scope_struct_8_candidate_set *)__pyx_generator->closure);
+  PyObject *__pyx_r = NULL;
+  unsigned int __pyx_t_1;
+  unsigned int __pyx_t_2;
+  PyObject *__pyx_t_3 = NULL;
+  __Pyx_RefNannyDeclarations
+  __Pyx_RefNannySetupContext("None", 0);
+  switch (__pyx_generator->resume_label) {
+    case 0: goto __pyx_L3_first_run;
+    case 1: goto __pyx_L6_resume_from_yield;
+    default: /* CPython raises the right error here */
+    __Pyx_RefNannyFinishContext();
+    return NULL;
+  }
+  __pyx_L3_first_run:;
+  if (unlikely(!__pyx_sent_value)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 75; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":76
+ * 
+ *     def candidate_set(self, Hypergraph hypergraph, unsigned k):
+ *         cdef mteval.CandidateSet* cs = new mteval.CandidateSet()             # <<<<<<<<<<<<<<
+ *         cs.AddKBestCandidates(hypergraph.hg[0], k, self.scorer.get())
+ *         cdef Candidate candidate
+ */
+  __pyx_cur_scope->__pyx_v_cs = new training::CandidateSet();
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":77
+ *     def candidate_set(self, Hypergraph hypergraph, unsigned k):
+ *         cdef mteval.CandidateSet* cs = new mteval.CandidateSet()
+ *         cs.AddKBestCandidates(hypergraph.hg[0], k, self.scorer.get())             # <<<<<<<<<<<<<<
+ *         cdef Candidate candidate
+ *         cdef unsigned i
+ */
+  __pyx_cur_scope->__pyx_v_cs->AddKBestCandidates((__pyx_cur_scope->__pyx_v_hypergraph->hg[0]), __pyx_cur_scope->__pyx_v_k, __pyx_cur_scope->__pyx_v_self->scorer->get());
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":80
+ *         cdef Candidate candidate
+ *         cdef unsigned i
+ *         for i in range(cs.size()):             # <<<<<<<<<<<<<<
+ *             candidate = Candidate()
+ *             candidate.candidate = &cs[0][i]
+ */
+  __pyx_t_1 = __pyx_cur_scope->__pyx_v_cs->size();
+  for (__pyx_t_2 = 0; __pyx_t_2 < __pyx_t_1; __pyx_t_2+=1) {
+    __pyx_cur_scope->__pyx_v_i = __pyx_t_2;
+
+    /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":81
+ *         cdef unsigned i
+ *         for i in range(cs.size()):
+ *             candidate = Candidate()             # <<<<<<<<<<<<<<
+ *             candidate.candidate = &cs[0][i]
+ *             candidate.score = self.metric.ComputeScore(cs[0][i].eval_feats)
+ */
+    __pyx_t_3 = PyObject_Call(((PyObject *)((PyObject*)__pyx_ptype_5_cdec_Candidate)), ((PyObject *)__pyx_empty_tuple), NULL); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 81; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_3);
+    __Pyx_XGOTREF(((PyObject *)__pyx_cur_scope->__pyx_v_candidate));
+    __Pyx_XDECREF(((PyObject *)__pyx_cur_scope->__pyx_v_candidate));
+    __Pyx_GIVEREF(__pyx_t_3);
+    __pyx_cur_scope->__pyx_v_candidate = ((struct __pyx_obj_5_cdec_Candidate *)__pyx_t_3);
+    __pyx_t_3 = 0;
+
+    /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":82
+ *         for i in range(cs.size()):
+ *             candidate = Candidate()
+ *             candidate.candidate = &cs[0][i]             # <<<<<<<<<<<<<<
+ *             candidate.score = self.metric.ComputeScore(cs[0][i].eval_feats)
+ *             yield candidate
+ */
+    __pyx_cur_scope->__pyx_v_candidate->candidate = (&((__pyx_cur_scope->__pyx_v_cs[0])[__pyx_cur_scope->__pyx_v_i]));
+
+    /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":83
+ *             candidate = Candidate()
+ *             candidate.candidate = &cs[0][i]
+ *             candidate.score = self.metric.ComputeScore(cs[0][i].eval_feats)             # <<<<<<<<<<<<<<
+ *             yield candidate
+ *         del cs
+ */
+    __pyx_cur_scope->__pyx_v_candidate->score = __pyx_cur_scope->__pyx_v_self->metric->ComputeScore(((__pyx_cur_scope->__pyx_v_cs[0])[__pyx_cur_scope->__pyx_v_i]).eval_feats);
+
+    /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":84
+ *             candidate.candidate = &cs[0][i]
+ *             candidate.score = self.metric.ComputeScore(cs[0][i].eval_feats)
+ *             yield candidate             # <<<<<<<<<<<<<<
+ *         del cs
+ * 
+ */
+    __Pyx_INCREF(((PyObject *)__pyx_cur_scope->__pyx_v_candidate));
+    __pyx_r = ((PyObject *)__pyx_cur_scope->__pyx_v_candidate);
+    __pyx_cur_scope->__pyx_t_0 = __pyx_t_1;
+    __pyx_cur_scope->__pyx_t_1 = __pyx_t_2;
+    __Pyx_XGIVEREF(__pyx_r);
+    __Pyx_RefNannyFinishContext();
+    /* return from generator, yielding value */
+    __pyx_generator->resume_label = 1;
+    return __pyx_r;
+    __pyx_L6_resume_from_yield:;
+    __pyx_t_1 = __pyx_cur_scope->__pyx_t_0;
+    __pyx_t_2 = __pyx_cur_scope->__pyx_t_1;
+    if (unlikely(!__pyx_sent_value)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 84; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  }
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":85
+ *             candidate.score = self.metric.ComputeScore(cs[0][i].eval_feats)
+ *             yield candidate
+ *         del cs             # <<<<<<<<<<<<<<
+ * 
+ * cdef class Scorer:
+ */
+  delete __pyx_cur_scope->__pyx_v_cs;
+  PyErr_SetNone(PyExc_StopIteration);
+  goto __pyx_L0;
+  __pyx_L1_error:;
+  __Pyx_XDECREF(__pyx_t_3);
+  __Pyx_AddTraceback("candidate_set", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __pyx_L0:;
+  __Pyx_XDECREF(__pyx_r);
+  __pyx_generator->resume_label = -1;
+  __Pyx_RefNannyFinishContext();
+  return NULL;
+}
+
+/* Python wrapper */
+static int __pyx_pw_5_cdec_6Scorer_1__cinit__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/
+static int __pyx_pw_5_cdec_6Scorer_1__cinit__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) {
+  char *__pyx_v_name;
+  static PyObject **__pyx_pyargnames[] = {&__pyx_n_s__name,0};
+  int __pyx_r;
+  __Pyx_RefNannyDeclarations
+  __Pyx_RefNannySetupContext("__cinit__ (wrapper)", 0);
+  {
+    PyObject* values[1] = {0};
+    if (unlikely(__pyx_kwds)) {
+      Py_ssize_t kw_args;
+      const Py_ssize_t pos_args = PyTuple_GET_SIZE(__pyx_args);
+      switch (pos_args) {
+        case  1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0);
+        case  0: break;
+        default: goto __pyx_L5_argtuple_error;
+      }
+      kw_args = PyDict_Size(__pyx_kwds);
+      switch (pos_args) {
+        case  0:
+        values[0] = PyDict_GetItem(__pyx_kwds, __pyx_n_s__name);
+        if (likely(values[0])) kw_args--;
+        else goto __pyx_L5_argtuple_error;
+      }
+      if (unlikely(kw_args > 0)) {
+        if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "__cinit__") < 0)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 90; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+      }
+    } else if (PyTuple_GET_SIZE(__pyx_args) != 1) {
+      goto __pyx_L5_argtuple_error;
+    } else {
+      values[0] = PyTuple_GET_ITEM(__pyx_args, 0);
+    }
+    __pyx_v_name = PyBytes_AsString(values[0]); if (unlikely((!__pyx_v_name) && PyErr_Occurred())) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 90; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+  }
+  goto __pyx_L4_argument_unpacking_done;
+  __pyx_L5_argtuple_error:;
+  __Pyx_RaiseArgtupleInvalid("__cinit__", 1, 1, 1, PyTuple_GET_SIZE(__pyx_args)); {__pyx_filename = __pyx_f[4]; __pyx_lineno = 90; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+  __pyx_L3_error:;
+  __Pyx_AddTraceback("_cdec.Scorer.__cinit__", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __Pyx_RefNannyFinishContext();
+  return -1;
+  __pyx_L4_argument_unpacking_done:;
+  __pyx_r = __pyx_pf_5_cdec_6Scorer___cinit__(((struct __pyx_obj_5_cdec_Scorer *)__pyx_v_self), __pyx_v_name);
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+/* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":90
+ *     cdef string* name
+ * 
+ *     def __cinit__(self, char* name):             # <<<<<<<<<<<<<<
+ *         self.name = new string(name)
+ * 
+ */
+
+static int __pyx_pf_5_cdec_6Scorer___cinit__(struct __pyx_obj_5_cdec_Scorer *__pyx_v_self, char *__pyx_v_name) {
+  int __pyx_r;
+  __Pyx_RefNannyDeclarations
+  __Pyx_RefNannySetupContext("__cinit__", 0);
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":91
+ * 
+ *     def __cinit__(self, char* name):
+ *         self.name = new string(name)             # <<<<<<<<<<<<<<
+ * 
+ *     def __call__(self, refs):
+ */
+  __pyx_v_self->name = new std::string(__pyx_v_name);
+
+  __pyx_r = 0;
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+/* Python wrapper */
+static PyObject *__pyx_pw_5_cdec_6Scorer_3__call__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/
+static PyObject *__pyx_pw_5_cdec_6Scorer_3__call__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) {
+  PyObject *__pyx_v_refs = 0;
+  static PyObject **__pyx_pyargnames[] = {&__pyx_n_s__refs,0};
+  PyObject *__pyx_r = 0;
+  __Pyx_RefNannyDeclarations
+  __Pyx_RefNannySetupContext("__call__ (wrapper)", 0);
+  {
+    PyObject* values[1] = {0};
+    if (unlikely(__pyx_kwds)) {
+      Py_ssize_t kw_args;
+      const Py_ssize_t pos_args = PyTuple_GET_SIZE(__pyx_args);
+      switch (pos_args) {
+        case  1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0);
+        case  0: break;
+        default: goto __pyx_L5_argtuple_error;
+      }
+      kw_args = PyDict_Size(__pyx_kwds);
+      switch (pos_args) {
+        case  0:
+        values[0] = PyDict_GetItem(__pyx_kwds, __pyx_n_s__refs);
+        if (likely(values[0])) kw_args--;
+        else goto __pyx_L5_argtuple_error;
+      }
+      if (unlikely(kw_args > 0)) {
+        if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "__call__") < 0)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 93; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+      }
+    } else if (PyTuple_GET_SIZE(__pyx_args) != 1) {
+      goto __pyx_L5_argtuple_error;
+    } else {
+      values[0] = PyTuple_GET_ITEM(__pyx_args, 0);
+    }
+    __pyx_v_refs = values[0];
+  }
+  goto __pyx_L4_argument_unpacking_done;
+  __pyx_L5_argtuple_error:;
+  __Pyx_RaiseArgtupleInvalid("__call__", 1, 1, 1, PyTuple_GET_SIZE(__pyx_args)); {__pyx_filename = __pyx_f[4]; __pyx_lineno = 93; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+  __pyx_L3_error:;
+  __Pyx_AddTraceback("_cdec.Scorer.__call__", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __Pyx_RefNannyFinishContext();
+  return NULL;
+  __pyx_L4_argument_unpacking_done:;
+  __pyx_r = __pyx_pf_5_cdec_6Scorer_2__call__(((struct __pyx_obj_5_cdec_Scorer *)__pyx_v_self), __pyx_v_refs);
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+/* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":93
+ *         self.name = new string(name)
+ * 
+ *     def __call__(self, refs):             # <<<<<<<<<<<<<<
+ *         cdef mteval.EvaluationMetric* metric = mteval.Instance(self.name[0])
+ *         if isinstance(refs, unicode) or isinstance(refs, str):
+ */
+
+static PyObject *__pyx_pf_5_cdec_6Scorer_2__call__(struct __pyx_obj_5_cdec_Scorer *__pyx_v_self, PyObject *__pyx_v_refs) {
+  EvaluationMetric *__pyx_v_metric;
+  std::vector<std::vector<WordID> > *__pyx_v_refsv;
+  std::vector<WordID> *__pyx_v_refv;
+  PyObject *__pyx_v_ref = NULL;
+  struct __pyx_obj_5_cdec_SegmentEvaluator *__pyx_v_evaluator = 0;
+  PyObject *__pyx_r = NULL;
+  __Pyx_RefNannyDeclarations
+  PyObject *__pyx_t_1 = NULL;
+  int __pyx_t_2;
+  int __pyx_t_3;
+  int __pyx_t_4;
+  Py_ssize_t __pyx_t_5;
+  PyObject *(*__pyx_t_6)(PyObject *);
+  PyObject *__pyx_t_7 = NULL;
+  PyObject *__pyx_t_8 = NULL;
+  int __pyx_lineno = 0;
+  const char *__pyx_filename = NULL;
+  int __pyx_clineno = 0;
+  __Pyx_RefNannySetupContext("__call__", 0);
+  __Pyx_INCREF(__pyx_v_refs);
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":94
+ * 
+ *     def __call__(self, refs):
+ *         cdef mteval.EvaluationMetric* metric = mteval.Instance(self.name[0])             # <<<<<<<<<<<<<<
+ *         if isinstance(refs, unicode) or isinstance(refs, str):
+ *             refs = [refs]
+ */
+  __pyx_v_metric = EvaluationMetric::Instance((__pyx_v_self->name[0]));
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":95
+ *     def __call__(self, refs):
+ *         cdef mteval.EvaluationMetric* metric = mteval.Instance(self.name[0])
+ *         if isinstance(refs, unicode) or isinstance(refs, str):             # <<<<<<<<<<<<<<
+ *             refs = [refs]
+ *         cdef vector[vector[WordID]]* refsv = new vector[vector[WordID]]()
+ */
+  __pyx_t_1 = ((PyObject *)((PyObject*)(&PyUnicode_Type)));
+  __Pyx_INCREF(__pyx_t_1);
+  __pyx_t_2 = __Pyx_TypeCheck(__pyx_v_refs, __pyx_t_1); 
+  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+  if (!__pyx_t_2) {
+    __pyx_t_1 = ((PyObject *)((PyObject*)(&PyString_Type)));
+    __Pyx_INCREF(__pyx_t_1);
+    __pyx_t_3 = __Pyx_TypeCheck(__pyx_v_refs, __pyx_t_1); 
+    __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+    __pyx_t_4 = __pyx_t_3;
+  } else {
+    __pyx_t_4 = __pyx_t_2;
+  }
+  if (__pyx_t_4) {
+
+    /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":96
+ *         cdef mteval.EvaluationMetric* metric = mteval.Instance(self.name[0])
+ *         if isinstance(refs, unicode) or isinstance(refs, str):
+ *             refs = [refs]             # <<<<<<<<<<<<<<
+ *         cdef vector[vector[WordID]]* refsv = new vector[vector[WordID]]()
+ *         cdef vector[WordID]* refv
+ */
+    __pyx_t_1 = PyList_New(1); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 96; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_1);
+    __Pyx_INCREF(__pyx_v_refs);
+    PyList_SET_ITEM(__pyx_t_1, 0, __pyx_v_refs);
+    __Pyx_GIVEREF(__pyx_v_refs);
+    __Pyx_DECREF(__pyx_v_refs);
+    __pyx_v_refs = ((PyObject *)__pyx_t_1);
+    __pyx_t_1 = 0;
+    goto __pyx_L3;
+  }
+  __pyx_L3:;
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":97
+ *         if isinstance(refs, unicode) or isinstance(refs, str):
+ *             refs = [refs]
+ *         cdef vector[vector[WordID]]* refsv = new vector[vector[WordID]]()             # <<<<<<<<<<<<<<
+ *         cdef vector[WordID]* refv
+ *         cdef bytes ref_str
+ */
+  __pyx_v_refsv = new std::vector<std::vector<WordID> >();
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":100
+ *         cdef vector[WordID]* refv
+ *         cdef bytes ref_str
+ *         for ref in refs:             # <<<<<<<<<<<<<<
+ *             refv = new vector[WordID]()
+ *             ConvertSentence(string(as_str(ref.strip())), refv)
+ */
+  if (PyList_CheckExact(__pyx_v_refs) || PyTuple_CheckExact(__pyx_v_refs)) {
+    __pyx_t_1 = __pyx_v_refs; __Pyx_INCREF(__pyx_t_1); __pyx_t_5 = 0;
+    __pyx_t_6 = NULL;
+  } else {
+    __pyx_t_5 = -1; __pyx_t_1 = PyObject_GetIter(__pyx_v_refs); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 100; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_1);
+    __pyx_t_6 = Py_TYPE(__pyx_t_1)->tp_iternext;
+  }
+  for (;;) {
+    if (!__pyx_t_6 && PyList_CheckExact(__pyx_t_1)) {
+      if (__pyx_t_5 >= PyList_GET_SIZE(__pyx_t_1)) break;
+      __pyx_t_7 = PyList_GET_ITEM(__pyx_t_1, __pyx_t_5); __Pyx_INCREF(__pyx_t_7); __pyx_t_5++;
+    } else if (!__pyx_t_6 && PyTuple_CheckExact(__pyx_t_1)) {
+      if (__pyx_t_5 >= PyTuple_GET_SIZE(__pyx_t_1)) break;
+      __pyx_t_7 = PyTuple_GET_ITEM(__pyx_t_1, __pyx_t_5); __Pyx_INCREF(__pyx_t_7); __pyx_t_5++;
+    } else {
+      __pyx_t_7 = __pyx_t_6(__pyx_t_1);
+      if (unlikely(!__pyx_t_7)) {
+        if (PyErr_Occurred()) {
+          if (likely(PyErr_ExceptionMatches(PyExc_StopIteration))) PyErr_Clear();
+          else {__pyx_filename = __pyx_f[4]; __pyx_lineno = 100; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+        }
+        break;
+      }
+      __Pyx_GOTREF(__pyx_t_7);
+    }
+    __Pyx_XDECREF(__pyx_v_ref);
+    __pyx_v_ref = __pyx_t_7;
+    __pyx_t_7 = 0;
+
+    /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":101
+ *         cdef bytes ref_str
+ *         for ref in refs:
+ *             refv = new vector[WordID]()             # <<<<<<<<<<<<<<
+ *             ConvertSentence(string(as_str(ref.strip())), refv)
+ *             refsv.push_back(refv[0])
+ */
+    __pyx_v_refv = new std::vector<WordID>();
+
+    /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":102
+ *         for ref in refs:
+ *             refv = new vector[WordID]()
+ *             ConvertSentence(string(as_str(ref.strip())), refv)             # <<<<<<<<<<<<<<
+ *             refsv.push_back(refv[0])
+ *             del refv
+ */
+    __pyx_t_7 = PyObject_GetAttr(__pyx_v_ref, __pyx_n_s__strip); if (unlikely(!__pyx_t_7)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 102; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_7);
+    __pyx_t_8 = PyObject_Call(__pyx_t_7, ((PyObject *)__pyx_empty_tuple), NULL); if (unlikely(!__pyx_t_8)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 102; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_8);
+    __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;
+    TD::ConvertSentence(std::string(__pyx_f_5_cdec_as_str(__pyx_t_8, NULL)), __pyx_v_refv);
+    __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0;
+
+    /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":103
+ *             refv = new vector[WordID]()
+ *             ConvertSentence(string(as_str(ref.strip())), refv)
+ *             refsv.push_back(refv[0])             # <<<<<<<<<<<<<<
+ *             del refv
+ *         cdef unsigned i
+ */
+    __pyx_v_refsv->push_back((__pyx_v_refv[0]));
+
+    /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":104
+ *             ConvertSentence(string(as_str(ref.strip())), refv)
+ *             refsv.push_back(refv[0])
+ *             del refv             # <<<<<<<<<<<<<<
+ *         cdef unsigned i
+ *         cdef SegmentEvaluator evaluator = SegmentEvaluator()
+ */
+    delete __pyx_v_refv;
+  }
+  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":106
+ *             del refv
+ *         cdef unsigned i
+ *         cdef SegmentEvaluator evaluator = SegmentEvaluator()             # <<<<<<<<<<<<<<
+ *         evaluator.metric = metric
+ *         evaluator.scorer = new shared_ptr[mteval.SegmentEvaluator](metric.CreateSegmentEvaluator(refsv[0]))
+ */
+  __pyx_t_1 = PyObject_Call(((PyObject *)((PyObject*)__pyx_ptype_5_cdec_SegmentEvaluator)), ((PyObject *)__pyx_empty_tuple), NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 106; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_1);
+  __pyx_v_evaluator = ((struct __pyx_obj_5_cdec_SegmentEvaluator *)__pyx_t_1);
+  __pyx_t_1 = 0;
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":107
+ *         cdef unsigned i
+ *         cdef SegmentEvaluator evaluator = SegmentEvaluator()
+ *         evaluator.metric = metric             # <<<<<<<<<<<<<<
+ *         evaluator.scorer = new shared_ptr[mteval.SegmentEvaluator](metric.CreateSegmentEvaluator(refsv[0]))
+ *         del refsv # in theory should not delete but store in SegmentEvaluator
+ */
+  __pyx_v_evaluator->metric = __pyx_v_metric;
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":108
+ *         cdef SegmentEvaluator evaluator = SegmentEvaluator()
+ *         evaluator.metric = metric
+ *         evaluator.scorer = new shared_ptr[mteval.SegmentEvaluator](metric.CreateSegmentEvaluator(refsv[0]))             # <<<<<<<<<<<<<<
+ *         del refsv # in theory should not delete but store in SegmentEvaluator
+ *         return evaluator
+ */
+  __pyx_v_evaluator->scorer = new boost::shared_ptr<SegmentEvaluator>(__pyx_v_metric->CreateSegmentEvaluator((__pyx_v_refsv[0])));
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":109
+ *         evaluator.metric = metric
+ *         evaluator.scorer = new shared_ptr[mteval.SegmentEvaluator](metric.CreateSegmentEvaluator(refsv[0]))
+ *         del refsv # in theory should not delete but store in SegmentEvaluator             # <<<<<<<<<<<<<<
+ *         return evaluator
+ * 
+ */
+  delete __pyx_v_refsv;
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":110
+ *         evaluator.scorer = new shared_ptr[mteval.SegmentEvaluator](metric.CreateSegmentEvaluator(refsv[0]))
+ *         del refsv # in theory should not delete but store in SegmentEvaluator
+ *         return evaluator             # <<<<<<<<<<<<<<
+ * 
+ *     def __str__(self):
+ */
+  __Pyx_XDECREF(__pyx_r);
+  __Pyx_INCREF(((PyObject *)__pyx_v_evaluator));
+  __pyx_r = ((PyObject *)__pyx_v_evaluator);
+  goto __pyx_L0;
+
+  __pyx_r = Py_None; __Pyx_INCREF(Py_None);
+  goto __pyx_L0;
+  __pyx_L1_error:;
+  __Pyx_XDECREF(__pyx_t_1);
+  __Pyx_XDECREF(__pyx_t_7);
+  __Pyx_XDECREF(__pyx_t_8);
+  __Pyx_AddTraceback("_cdec.Scorer.__call__", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __pyx_r = NULL;
+  __pyx_L0:;
+  __Pyx_XDECREF(__pyx_v_ref);
+  __Pyx_XDECREF((PyObject *)__pyx_v_evaluator);
+  __Pyx_XDECREF(__pyx_v_refs);
+  __Pyx_XGIVEREF(__pyx_r);
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+/* Python wrapper */
+static PyObject *__pyx_pw_5_cdec_6Scorer_5__str__(PyObject *__pyx_v_self); /*proto*/
+static PyObject *__pyx_pw_5_cdec_6Scorer_5__str__(PyObject *__pyx_v_self) {
+  PyObject *__pyx_r = 0;
+  __Pyx_RefNannyDeclarations
+  __Pyx_RefNannySetupContext("__str__ (wrapper)", 0);
+  __pyx_r = __pyx_pf_5_cdec_6Scorer_4__str__(((struct __pyx_obj_5_cdec_Scorer *)__pyx_v_self));
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+/* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":112
+ *         return evaluator
+ * 
+ *     def __str__(self):             # <<<<<<<<<<<<<<
+ *         return self.name.c_str()
+ * 
+ */
+
+static PyObject *__pyx_pf_5_cdec_6Scorer_4__str__(struct __pyx_obj_5_cdec_Scorer *__pyx_v_self) {
+  PyObject *__pyx_r = NULL;
+  __Pyx_RefNannyDeclarations
+  PyObject *__pyx_t_1 = NULL;
+  int __pyx_lineno = 0;
+  const char *__pyx_filename = NULL;
+  int __pyx_clineno = 0;
+  __Pyx_RefNannySetupContext("__str__", 0);
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":113
+ * 
+ *     def __str__(self):
+ *         return self.name.c_str()             # <<<<<<<<<<<<<<
+ * 
+ * BLEU = Scorer('IBM_BLEU')
+ */
+  __Pyx_XDECREF(__pyx_r);
+  __pyx_t_1 = PyBytes_FromString(__pyx_v_self->name->c_str()); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 113; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(((PyObject *)__pyx_t_1));
+  __pyx_r = ((PyObject *)__pyx_t_1);
+  __pyx_t_1 = 0;
+  goto __pyx_L0;
+
+  __pyx_r = Py_None; __Pyx_INCREF(Py_None);
+  goto __pyx_L0;
+  __pyx_L1_error:;
+  __Pyx_XDECREF(__pyx_t_1);
+  __Pyx_AddTraceback("_cdec.Scorer.__str__", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __pyx_r = NULL;
+  __pyx_L0:;
+  __Pyx_XGIVEREF(__pyx_r);
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+/* Python wrapper */
+static int __pyx_pw_5_cdec_7Decoder_1__cinit__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/
+static int __pyx_pw_5_cdec_7Decoder_1__cinit__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) {
+  char *__pyx_v_config;
+  static PyObject **__pyx_pyargnames[] = {&__pyx_n_s__config,0};
+  int __pyx_r;
+  __Pyx_RefNannyDeclarations
+  __Pyx_RefNannySetupContext("__cinit__ (wrapper)", 0);
+  {
+    PyObject* values[1] = {0};
+    if (unlikely(__pyx_kwds)) {
+      Py_ssize_t kw_args;
+      const Py_ssize_t pos_args = PyTuple_GET_SIZE(__pyx_args);
+      switch (pos_args) {
+        case  1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0);
+        case  0: break;
+        default: goto __pyx_L5_argtuple_error;
+      }
+      kw_args = PyDict_Size(__pyx_kwds);
+      switch (pos_args) {
+        case  0:
+        values[0] = PyDict_GetItem(__pyx_kwds, __pyx_n_s__config);
+        if (likely(values[0])) kw_args--;
+        else goto __pyx_L5_argtuple_error;
+      }
+      if (unlikely(kw_args > 0)) {
+        if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "__cinit__") < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 19; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+      }
+    } else if (PyTuple_GET_SIZE(__pyx_args) != 1) {
+      goto __pyx_L5_argtuple_error;
+    } else {
+      values[0] = PyTuple_GET_ITEM(__pyx_args, 0);
+    }
+    __pyx_v_config = PyBytes_AsString(values[0]); if (unlikely((!__pyx_v_config) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 19; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+  }
+  goto __pyx_L4_argument_unpacking_done;
+  __pyx_L5_argtuple_error:;
+  __Pyx_RaiseArgtupleInvalid("__cinit__", 1, 1, 1, PyTuple_GET_SIZE(__pyx_args)); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 19; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+  __pyx_L3_error:;
+  __Pyx_AddTraceback("_cdec.Decoder.__cinit__", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __Pyx_RefNannyFinishContext();
+  return -1;
+  __pyx_L4_argument_unpacking_done:;
+  __pyx_r = __pyx_pf_5_cdec_7Decoder___cinit__(((struct __pyx_obj_5_cdec_Decoder *)__pyx_v_self), __pyx_v_config);
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+/* "_cdec.pyx":19
+ *     cdef public DenseVector weights
+ * 
+ *     def __cinit__(self, char* config):             # <<<<<<<<<<<<<<
+ *         decoder.register_feature_functions()
+ *         cdef istringstream* config_stream = new istringstream(config)
+ */
+
+static int __pyx_pf_5_cdec_7Decoder___cinit__(struct __pyx_obj_5_cdec_Decoder *__pyx_v_self, char *__pyx_v_config) {
+  std::istringstream *__pyx_v_config_stream;
+  int __pyx_r;
+  __Pyx_RefNannyDeclarations
+  PyObject *__pyx_t_1 = NULL;
+  int __pyx_lineno = 0;
+  const char *__pyx_filename = NULL;
+  int __pyx_clineno = 0;
+  __Pyx_RefNannySetupContext("__cinit__", 0);
+
+  /* "_cdec.pyx":20
+ * 
+ *     def __cinit__(self, char* config):
+ *         decoder.register_feature_functions()             # <<<<<<<<<<<<<<
+ *         cdef istringstream* config_stream = new istringstream(config)
+ *         self.dec = new decoder.Decoder(config_stream)
+ */
+  register_feature_functions();
+
+  /* "_cdec.pyx":21
+ *     def __cinit__(self, char* config):
+ *         decoder.register_feature_functions()
+ *         cdef istringstream* config_stream = new istringstream(config)             # <<<<<<<<<<<<<<
+ *         self.dec = new decoder.Decoder(config_stream)
+ *         del config_stream
+ */
+  __pyx_v_config_stream = new std::istringstream(__pyx_v_config);
+
+  /* "_cdec.pyx":22
+ *         decoder.register_feature_functions()
+ *         cdef istringstream* config_stream = new istringstream(config)
+ *         self.dec = new decoder.Decoder(config_stream)             # <<<<<<<<<<<<<<
+ *         del config_stream
+ *         self.weights = DenseVector()
+ */
+  __pyx_v_self->dec = new Decoder(__pyx_v_config_stream);
+
+  /* "_cdec.pyx":23
+ *         cdef istringstream* config_stream = new istringstream(config)
+ *         self.dec = new decoder.Decoder(config_stream)
+ *         del config_stream             # <<<<<<<<<<<<<<
+ *         self.weights = DenseVector()
+ *         self.weights.vector = &self.dec.CurrentWeightVector()
+ */
+  delete __pyx_v_config_stream;
+
+  /* "_cdec.pyx":24
+ *         self.dec = new decoder.Decoder(config_stream)
+ *         del config_stream
+ *         self.weights = DenseVector()             # <<<<<<<<<<<<<<
+ *         self.weights.vector = &self.dec.CurrentWeightVector()
+ * 
+ */
+  __pyx_t_1 = PyObject_Call(((PyObject *)((PyObject*)__pyx_ptype_5_cdec_DenseVector)), ((PyObject *)__pyx_empty_tuple), NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 24; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_1);
+  __Pyx_GIVEREF(__pyx_t_1);
+  __Pyx_GOTREF(__pyx_v_self->weights);
+  __Pyx_DECREF(((PyObject *)__pyx_v_self->weights));
+  __pyx_v_self->weights = ((struct __pyx_obj_5_cdec_DenseVector *)__pyx_t_1);
+  __pyx_t_1 = 0;
+
+  /* "_cdec.pyx":25
+ *         del config_stream
+ *         self.weights = DenseVector()
+ *         self.weights.vector = &self.dec.CurrentWeightVector()             # <<<<<<<<<<<<<<
+ * 
+ *     def __dealloc__(self):
+ */
+  __pyx_v_self->weights->vector = (&__pyx_v_self->dec->CurrentWeightVector());
+
+  __pyx_r = 0;
+  goto __pyx_L0;
+  __pyx_L1_error:;
+  __Pyx_XDECREF(__pyx_t_1);
+  __Pyx_AddTraceback("_cdec.Decoder.__cinit__", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __pyx_r = -1;
+  __pyx_L0:;
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+/* Python wrapper */
+static void __pyx_pw_5_cdec_7Decoder_3__dealloc__(PyObject *__pyx_v_self); /*proto*/
+static void __pyx_pw_5_cdec_7Decoder_3__dealloc__(PyObject *__pyx_v_self) {
+  __Pyx_RefNannyDeclarations
+  __Pyx_RefNannySetupContext("__dealloc__ (wrapper)", 0);
+  __pyx_pf_5_cdec_7Decoder_2__dealloc__(((struct __pyx_obj_5_cdec_Decoder *)__pyx_v_self));
+  __Pyx_RefNannyFinishContext();
+}
+
+/* "_cdec.pyx":27
+ *         self.weights.vector = &self.dec.CurrentWeightVector()
+ * 
+ *     def __dealloc__(self):             # <<<<<<<<<<<<<<
+ *         del self.dec
+ * 
+ */
+
+static void __pyx_pf_5_cdec_7Decoder_2__dealloc__(CYTHON_UNUSED struct __pyx_obj_5_cdec_Decoder *__pyx_v_self) {
+  __Pyx_RefNannyDeclarations
+  __Pyx_RefNannySetupContext("__dealloc__", 0);
+
+  /* "_cdec.pyx":28
+ * 
+ *     def __dealloc__(self):
+ *         del self.dec             # <<<<<<<<<<<<<<
+ * 
+ *     def read_weights(self, cfg):
+ */
+  delete __pyx_v_self->dec;
+
+  __Pyx_RefNannyFinishContext();
+}
+
+/* Python wrapper */
+static PyObject *__pyx_pw_5_cdec_7Decoder_5read_weights(PyObject *__pyx_v_self, PyObject *__pyx_v_cfg); /*proto*/
+static PyObject *__pyx_pw_5_cdec_7Decoder_5read_weights(PyObject *__pyx_v_self, PyObject *__pyx_v_cfg) {
+  PyObject *__pyx_r = 0;
+  __Pyx_RefNannyDeclarations
+  __Pyx_RefNannySetupContext("read_weights (wrapper)", 0);
+  __pyx_r = __pyx_pf_5_cdec_7Decoder_4read_weights(((struct __pyx_obj_5_cdec_Decoder *)__pyx_v_self), ((PyObject *)__pyx_v_cfg));
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+/* "_cdec.pyx":30
+ *         del self.dec
+ * 
+ *     def read_weights(self, cfg):             # <<<<<<<<<<<<<<
+ *         with open(cfg) as fp:
+ *             for line in fp:
+ */
+
+static PyObject *__pyx_pf_5_cdec_7Decoder_4read_weights(struct __pyx_obj_5_cdec_Decoder *__pyx_v_self, PyObject *__pyx_v_cfg) {
+  PyObject *__pyx_v_fp = NULL;
+  PyObject *__pyx_v_line = NULL;
+  PyObject *__pyx_v_fname = NULL;
+  PyObject *__pyx_v_value = NULL;
+  PyObject *__pyx_r = NULL;
+  __Pyx_RefNannyDeclarations
+  PyObject *__pyx_t_1 = NULL;
+  PyObject *__pyx_t_2 = NULL;
+  PyObject *__pyx_t_3 = NULL;
+  PyObject *__pyx_t_4 = NULL;
+  PyObject *__pyx_t_5 = NULL;
+  PyObject *__pyx_t_6 = NULL;
+  PyObject *__pyx_t_7 = NULL;
+  Py_ssize_t __pyx_t_8;
+  PyObject *(*__pyx_t_9)(PyObject *);
+  PyObject *__pyx_t_10 = NULL;
+  PyObject *__pyx_t_11 = NULL;
+  PyObject *(*__pyx_t_12)(PyObject *);
+  double __pyx_t_13;
+  int __pyx_t_14;
+  PyObject *__pyx_t_15 = NULL;
+  int __pyx_t_16;
+  int __pyx_lineno = 0;
+  const char *__pyx_filename = NULL;
+  int __pyx_clineno = 0;
+  __Pyx_RefNannySetupContext("read_weights", 0);
+
+  /* "_cdec.pyx":31
+ * 
+ *     def read_weights(self, cfg):
+ *         with open(cfg) as fp:             # <<<<<<<<<<<<<<
+ *             for line in fp:
+ *                 fname, value = line.split()
+ */
+  /*with:*/ {
+    __pyx_t_1 = PyTuple_New(1); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 31; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_1);
+    __Pyx_INCREF(__pyx_v_cfg);
+    PyTuple_SET_ITEM(__pyx_t_1, 0, __pyx_v_cfg);
+    __Pyx_GIVEREF(__pyx_v_cfg);
+    __pyx_t_2 = PyObject_Call(__pyx_builtin_open, ((PyObject *)__pyx_t_1), NULL); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 31; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_2);
+    __Pyx_DECREF(((PyObject *)__pyx_t_1)); __pyx_t_1 = 0;
+    __pyx_t_3 = PyObject_GetAttr(__pyx_t_2, __pyx_n_s____exit__); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 31; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_3);
+    __pyx_t_1 = PyObject_GetAttr(__pyx_t_2, __pyx_n_s____enter__); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 31; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+    __Pyx_GOTREF(__pyx_t_1);
+    __pyx_t_4 = PyObject_Call(__pyx_t_1, ((PyObject *)__pyx_empty_tuple), NULL); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 31; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+    __Pyx_GOTREF(__pyx_t_4);
+    __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+    __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+    /*try:*/ {
+      {
+        __Pyx_ExceptionSave(&__pyx_t_5, &__pyx_t_6, &__pyx_t_7);
+        __Pyx_XGOTREF(__pyx_t_5);
+        __Pyx_XGOTREF(__pyx_t_6);
+        __Pyx_XGOTREF(__pyx_t_7);
+        /*try:*/ {
+          __Pyx_INCREF(__pyx_t_4);
+          __pyx_v_fp = __pyx_t_4;
+          __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
+
+          /* "_cdec.pyx":32
+ *     def read_weights(self, cfg):
+ *         with open(cfg) as fp:
+ *             for line in fp:             # <<<<<<<<<<<<<<
+ *                 fname, value = line.split()
+ *                 self.weights[fname.strip()] = float(value)
+ */
+          if (PyList_CheckExact(__pyx_v_fp) || PyTuple_CheckExact(__pyx_v_fp)) {
+            __pyx_t_4 = __pyx_v_fp; __Pyx_INCREF(__pyx_t_4); __pyx_t_8 = 0;
+            __pyx_t_9 = NULL;
+          } else {
+            __pyx_t_8 = -1; __pyx_t_4 = PyObject_GetIter(__pyx_v_fp); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 32; __pyx_clineno = __LINE__; goto __pyx_L7_error;}
+            __Pyx_GOTREF(__pyx_t_4);
+            __pyx_t_9 = Py_TYPE(__pyx_t_4)->tp_iternext;
+          }
+          for (;;) {
+            if (!__pyx_t_9 && PyList_CheckExact(__pyx_t_4)) {
+              if (__pyx_t_8 >= PyList_GET_SIZE(__pyx_t_4)) break;
+              __pyx_t_2 = PyList_GET_ITEM(__pyx_t_4, __pyx_t_8); __Pyx_INCREF(__pyx_t_2); __pyx_t_8++;
+            } else if (!__pyx_t_9 && PyTuple_CheckExact(__pyx_t_4)) {
+              if (__pyx_t_8 >= PyTuple_GET_SIZE(__pyx_t_4)) break;
+              __pyx_t_2 = PyTuple_GET_ITEM(__pyx_t_4, __pyx_t_8); __Pyx_INCREF(__pyx_t_2); __pyx_t_8++;
+            } else {
+              __pyx_t_2 = __pyx_t_9(__pyx_t_4);
+              if (unlikely(!__pyx_t_2)) {
+                if (PyErr_Occurred()) {
+                  if (likely(PyErr_ExceptionMatches(PyExc_StopIteration))) PyErr_Clear();
+                  else {__pyx_filename = __pyx_f[0]; __pyx_lineno = 32; __pyx_clineno = __LINE__; goto __pyx_L7_error;}
+                }
+                break;
+              }
+              __Pyx_GOTREF(__pyx_t_2);
+            }
+            __Pyx_XDECREF(__pyx_v_line);
+            __pyx_v_line = __pyx_t_2;
+            __pyx_t_2 = 0;
+
+            /* "_cdec.pyx":33
+ *         with open(cfg) as fp:
+ *             for line in fp:
+ *                 fname, value = line.split()             # <<<<<<<<<<<<<<
+ *                 self.weights[fname.strip()] = float(value)
+ * 
+ */
+            __pyx_t_2 = PyObject_GetAttr(__pyx_v_line, __pyx_n_s__split); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 33; __pyx_clineno = __LINE__; goto __pyx_L7_error;}
+            __Pyx_GOTREF(__pyx_t_2);
+            __pyx_t_1 = PyObject_Call(__pyx_t_2, ((PyObject *)__pyx_empty_tuple), NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 33; __pyx_clineno = __LINE__; goto __pyx_L7_error;}
+            __Pyx_GOTREF(__pyx_t_1);
+            __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+            if ((likely(PyTuple_CheckExact(__pyx_t_1))) || (PyList_CheckExact(__pyx_t_1))) {
+              PyObject* sequence = __pyx_t_1;
+              if (likely(PyTuple_CheckExact(sequence))) {
+                if (unlikely(PyTuple_GET_SIZE(sequence) != 2)) {
+                  if (PyTuple_GET_SIZE(sequence) > 2) __Pyx_RaiseTooManyValuesError(2);
+                  else __Pyx_RaiseNeedMoreValuesError(PyTuple_GET_SIZE(sequence));
+                  {__pyx_filename = __pyx_f[0]; __pyx_lineno = 33; __pyx_clineno = __LINE__; goto __pyx_L7_error;}
+                }
+                __pyx_t_2 = PyTuple_GET_ITEM(sequence, 0); 
+                __pyx_t_10 = PyTuple_GET_ITEM(sequence, 1); 
+              } else {
+                if (unlikely(PyList_GET_SIZE(sequence) != 2)) {
+                  if (PyList_GET_SIZE(sequence) > 2) __Pyx_RaiseTooManyValuesError(2);
+                  else __Pyx_RaiseNeedMoreValuesError(PyList_GET_SIZE(sequence));
+                  {__pyx_filename = __pyx_f[0]; __pyx_lineno = 33; __pyx_clineno = __LINE__; goto __pyx_L7_error;}
+                }
+                __pyx_t_2 = PyList_GET_ITEM(sequence, 0); 
+                __pyx_t_10 = PyList_GET_ITEM(sequence, 1); 
+              }
+              __Pyx_INCREF(__pyx_t_2);
+              __Pyx_INCREF(__pyx_t_10);
+              __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+            } else {
+              Py_ssize_t index = -1;
+              __pyx_t_11 = PyObject_GetIter(__pyx_t_1); if (unlikely(!__pyx_t_11)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 33; __pyx_clineno = __LINE__; goto __pyx_L7_error;}
+              __Pyx_GOTREF(__pyx_t_11);
+              __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+              __pyx_t_12 = Py_TYPE(__pyx_t_11)->tp_iternext;
+              index = 0; __pyx_t_2 = __pyx_t_12(__pyx_t_11); if (unlikely(!__pyx_t_2)) goto __pyx_L18_unpacking_failed;
+              __Pyx_GOTREF(__pyx_t_2);
+              index = 1; __pyx_t_10 = __pyx_t_12(__pyx_t_11); if (unlikely(!__pyx_t_10)) goto __pyx_L18_unpacking_failed;
+              __Pyx_GOTREF(__pyx_t_10);
+              if (__Pyx_IternextUnpackEndCheck(__pyx_t_12(__pyx_t_11), 2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 33; __pyx_clineno = __LINE__; goto __pyx_L7_error;}
+              __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0;
+              goto __pyx_L19_unpacking_done;
+              __pyx_L18_unpacking_failed:;
+              __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0;
+              if (PyErr_Occurred() && PyErr_ExceptionMatches(PyExc_StopIteration)) PyErr_Clear();
+              if (!PyErr_Occurred()) __Pyx_RaiseNeedMoreValuesError(index);
+              {__pyx_filename = __pyx_f[0]; __pyx_lineno = 33; __pyx_clineno = __LINE__; goto __pyx_L7_error;}
+              __pyx_L19_unpacking_done:;
+            }
+            __Pyx_XDECREF(__pyx_v_fname);
+            __pyx_v_fname = __pyx_t_2;
+            __pyx_t_2 = 0;
+            __Pyx_XDECREF(__pyx_v_value);
+            __pyx_v_value = __pyx_t_10;
+            __pyx_t_10 = 0;
+
+            /* "_cdec.pyx":34
+ *             for line in fp:
+ *                 fname, value = line.split()
+ *                 self.weights[fname.strip()] = float(value)             # <<<<<<<<<<<<<<
+ * 
+ *     def translate(self, sentence, grammar=None):
+ */
+            __pyx_t_13 = __Pyx_PyObject_AsDouble(__pyx_v_value); if (unlikely(__pyx_t_13 == ((double)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 34; __pyx_clineno = __LINE__; goto __pyx_L7_error;}
+            __pyx_t_1 = PyFloat_FromDouble(__pyx_t_13); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 34; __pyx_clineno = __LINE__; goto __pyx_L7_error;}
+            __Pyx_GOTREF(__pyx_t_1);
+            __pyx_t_10 = PyObject_GetAttr(__pyx_v_fname, __pyx_n_s__strip); if (unlikely(!__pyx_t_10)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 34; __pyx_clineno = __LINE__; goto __pyx_L7_error;}
+            __Pyx_GOTREF(__pyx_t_10);
+            __pyx_t_2 = PyObject_Call(__pyx_t_10, ((PyObject *)__pyx_empty_tuple), NULL); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 34; __pyx_clineno = __LINE__; goto __pyx_L7_error;}
+            __Pyx_GOTREF(__pyx_t_2);
+            __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0;
+            if (PyObject_SetItem(((PyObject *)__pyx_v_self->weights), __pyx_t_2, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 34; __pyx_clineno = __LINE__; goto __pyx_L7_error;}
+            __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+            __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+          }
+          __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
+        }
+        __Pyx_XDECREF(__pyx_t_5); __pyx_t_5 = 0;
+        __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0;
+        __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0;
+        goto __pyx_L14_try_end;
+        __pyx_L7_error:;
+        __Pyx_XDECREF(__pyx_t_11); __pyx_t_11 = 0;
+        __Pyx_XDECREF(__pyx_t_10); __pyx_t_10 = 0;
+        __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0;
+        __Pyx_XDECREF(__pyx_t_1); __pyx_t_1 = 0;
+        __Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0;
+
+        /* "_cdec.pyx":31
+ * 
+ *     def read_weights(self, cfg):
+ *         with open(cfg) as fp:             # <<<<<<<<<<<<<<
+ *             for line in fp:
+ *                 fname, value = line.split()
+ */
+        /*except:*/ {
+          __Pyx_AddTraceback("_cdec.Decoder.read_weights", __pyx_clineno, __pyx_lineno, __pyx_filename);
+          if (__Pyx_GetException(&__pyx_t_4, &__pyx_t_1, &__pyx_t_2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 31; __pyx_clineno = __LINE__; goto __pyx_L9_except_error;}
+          __Pyx_GOTREF(__pyx_t_4);
+          __Pyx_GOTREF(__pyx_t_1);
+          __Pyx_GOTREF(__pyx_t_2);
+          __pyx_t_10 = PyTuple_New(3); if (unlikely(!__pyx_t_10)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 31; __pyx_clineno = __LINE__; goto __pyx_L9_except_error;}
+          __Pyx_GOTREF(__pyx_t_10);
+          __Pyx_INCREF(__pyx_t_4);
+          PyTuple_SET_ITEM(__pyx_t_10, 0, __pyx_t_4);
+          __Pyx_GIVEREF(__pyx_t_4);
+          __Pyx_INCREF(__pyx_t_1);
+          PyTuple_SET_ITEM(__pyx_t_10, 1, __pyx_t_1);
+          __Pyx_GIVEREF(__pyx_t_1);
+          __Pyx_INCREF(__pyx_t_2);
+          PyTuple_SET_ITEM(__pyx_t_10, 2, __pyx_t_2);
+          __Pyx_GIVEREF(__pyx_t_2);
+          __pyx_t_15 = PyObject_Call(__pyx_t_3, __pyx_t_10, NULL);
+          __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
+          if (unlikely(!__pyx_t_15)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 31; __pyx_clineno = __LINE__; goto __pyx_L9_except_error;}
+          __Pyx_GOTREF(__pyx_t_15);
+          __pyx_t_14 = __Pyx_PyObject_IsTrue(__pyx_t_15);
+          __Pyx_DECREF(__pyx_t_15); __pyx_t_15 = 0;
+          if (unlikely(__pyx_t_14 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 31; __pyx_clineno = __LINE__; goto __pyx_L9_except_error;}
+          __pyx_t_16 = (!__pyx_t_14);
+          if (__pyx_t_16) {
+            __Pyx_GIVEREF(__pyx_t_4);
+            __Pyx_GIVEREF(__pyx_t_1);
+            __Pyx_GIVEREF(__pyx_t_2);
+            __Pyx_ErrRestore(__pyx_t_4, __pyx_t_1, __pyx_t_2);
+            __pyx_t_4 = 0; __pyx_t_1 = 0; __pyx_t_2 = 0; 
+            {__pyx_filename = __pyx_f[0]; __pyx_lineno = 31; __pyx_clineno = __LINE__; goto __pyx_L9_except_error;}
+            goto __pyx_L22;
+          }
+          __pyx_L22:;
+          __Pyx_DECREF(((PyObject *)__pyx_t_10)); __pyx_t_10 = 0;
+          __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
+          __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+          __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+          goto __pyx_L8_exception_handled;
+        }
+        __pyx_L9_except_error:;
+        __Pyx_XGIVEREF(__pyx_t_5);
+        __Pyx_XGIVEREF(__pyx_t_6);
+        __Pyx_XGIVEREF(__pyx_t_7);
+        __Pyx_ExceptionReset(__pyx_t_5, __pyx_t_6, __pyx_t_7);
+        goto __pyx_L1_error;
+        __pyx_L8_exception_handled:;
+        __Pyx_XGIVEREF(__pyx_t_5);
+        __Pyx_XGIVEREF(__pyx_t_6);
+        __Pyx_XGIVEREF(__pyx_t_7);
+        __Pyx_ExceptionReset(__pyx_t_5, __pyx_t_6, __pyx_t_7);
+        __pyx_L14_try_end:;
+      }
+    }
+    /*finally:*/ {
+      if (__pyx_t_3) {
+        __pyx_t_7 = PyObject_Call(__pyx_t_3, __pyx_k_tuple_21, NULL);
+        __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
+        if (unlikely(!__pyx_t_7)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 31; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+        __Pyx_GOTREF(__pyx_t_7);
+        __pyx_t_16 = __Pyx_PyObject_IsTrue(__pyx_t_7);
+        __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;
+        if (unlikely(__pyx_t_16 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 31; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      }
+    }
+    goto __pyx_L23;
+    __pyx_L3_error:;
+    __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
+    goto __pyx_L1_error;
+    __pyx_L23:;
+  }
+
+  __pyx_r = Py_None; __Pyx_INCREF(Py_None);
+  goto __pyx_L0;
+  __pyx_L1_error:;
+  __Pyx_XDECREF(__pyx_t_1);
+  __Pyx_XDECREF(__pyx_t_2);
+  __Pyx_XDECREF(__pyx_t_4);
+  __Pyx_XDECREF(__pyx_t_10);
+  __Pyx_XDECREF(__pyx_t_11);
+  __Pyx_AddTraceback("_cdec.Decoder.read_weights", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __pyx_r = NULL;
+  __pyx_L0:;
+  __Pyx_XDECREF(__pyx_v_fp);
+  __Pyx_XDECREF(__pyx_v_line);
+  __Pyx_XDECREF(__pyx_v_fname);
+  __Pyx_XDECREF(__pyx_v_value);
+  __Pyx_XGIVEREF(__pyx_r);
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+/* Python wrapper */
+static PyObject *__pyx_pw_5_cdec_7Decoder_7translate(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/
+static PyObject *__pyx_pw_5_cdec_7Decoder_7translate(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) {
+  PyObject *__pyx_v_sentence = 0;
+  PyObject *__pyx_v_grammar = 0;
+  static PyObject **__pyx_pyargnames[] = {&__pyx_n_s__sentence,&__pyx_n_s__grammar,0};
+  PyObject *__pyx_r = 0;
+  __Pyx_RefNannyDeclarations
+  __Pyx_RefNannySetupContext("translate (wrapper)", 0);
+  {
+    PyObject* values[2] = {0,0};
+
+    /* "_cdec.pyx":36
+ *                 self.weights[fname.strip()] = float(value)
+ * 
+ *     def translate(self, sentence, grammar=None):             # <<<<<<<<<<<<<<
+ *         if isinstance(sentence, unicode):
+ *             inp = sentence.strip().encode('utf8')
+ */
+    values[1] = ((PyObject *)Py_None);
+    if (unlikely(__pyx_kwds)) {
+      Py_ssize_t kw_args;
+      const Py_ssize_t pos_args = PyTuple_GET_SIZE(__pyx_args);
+      switch (pos_args) {
+        case  2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1);
+        case  1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0);
+        case  0: break;
+        default: goto __pyx_L5_argtuple_error;
+      }
+      kw_args = PyDict_Size(__pyx_kwds);
+      switch (pos_args) {
+        case  0:
+        values[0] = PyDict_GetItem(__pyx_kwds, __pyx_n_s__sentence);
+        if (likely(values[0])) kw_args--;
+        else goto __pyx_L5_argtuple_error;
+        case  1:
+        if (kw_args > 0) {
+          PyObject* value = PyDict_GetItem(__pyx_kwds, __pyx_n_s__grammar);
+          if (value) { values[1] = value; kw_args--; }
+        }
+      }
+      if (unlikely(kw_args > 0)) {
+        if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "translate") < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 36; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+      }
+    } else {
+      switch (PyTuple_GET_SIZE(__pyx_args)) {
+        case  2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1);
+        case  1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0);
+        break;
+        default: goto __pyx_L5_argtuple_error;
+      }
+    }
+    __pyx_v_sentence = values[0];
+    __pyx_v_grammar = values[1];
+  }
+  goto __pyx_L4_argument_unpacking_done;
+  __pyx_L5_argtuple_error:;
+  __Pyx_RaiseArgtupleInvalid("translate", 0, 1, 2, PyTuple_GET_SIZE(__pyx_args)); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 36; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+  __pyx_L3_error:;
+  __Pyx_AddTraceback("_cdec.Decoder.translate", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __Pyx_RefNannyFinishContext();
+  return NULL;
+  __pyx_L4_argument_unpacking_done:;
+  __pyx_r = __pyx_pf_5_cdec_7Decoder_6translate(((struct __pyx_obj_5_cdec_Decoder *)__pyx_v_self), __pyx_v_sentence, __pyx_v_grammar);
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+static PyObject *__pyx_pf_5_cdec_7Decoder_6translate(struct __pyx_obj_5_cdec_Decoder *__pyx_v_self, PyObject *__pyx_v_sentence, PyObject *__pyx_v_grammar) {
+  PyObject *__pyx_v_inp = NULL;
+  BasicObserver __pyx_v_observer;
+  struct __pyx_obj_5_cdec_Hypergraph *__pyx_v_hg = 0;
+  PyObject *__pyx_r = NULL;
+  __Pyx_RefNannyDeclarations
+  PyObject *__pyx_t_1 = NULL;
+  int __pyx_t_2;
+  PyObject *__pyx_t_3 = NULL;
+  char *__pyx_t_4;
+  int __pyx_lineno = 0;
+  const char *__pyx_filename = NULL;
+  int __pyx_clineno = 0;
+  __Pyx_RefNannySetupContext("translate", 0);
+
+  /* "_cdec.pyx":37
+ * 
+ *     def translate(self, sentence, grammar=None):
+ *         if isinstance(sentence, unicode):             # <<<<<<<<<<<<<<
+ *             inp = sentence.strip().encode('utf8')
+ *         elif isinstance(sentence, str):
+ */
+  __pyx_t_1 = ((PyObject *)((PyObject*)(&PyUnicode_Type)));
+  __Pyx_INCREF(__pyx_t_1);
+  __pyx_t_2 = __Pyx_TypeCheck(__pyx_v_sentence, __pyx_t_1); 
+  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+  if (__pyx_t_2) {
+
+    /* "_cdec.pyx":38
+ *     def translate(self, sentence, grammar=None):
+ *         if isinstance(sentence, unicode):
+ *             inp = sentence.strip().encode('utf8')             # <<<<<<<<<<<<<<
+ *         elif isinstance(sentence, str):
+ *             inp = sentence.strip()
+ */
+    __pyx_t_1 = PyObject_GetAttr(__pyx_v_sentence, __pyx_n_s__strip); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 38; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_1);
+    __pyx_t_3 = PyObject_Call(__pyx_t_1, ((PyObject *)__pyx_empty_tuple), NULL); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 38; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_3);
+    __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+    __pyx_t_1 = PyObject_GetAttr(__pyx_t_3, __pyx_n_s__encode); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 38; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_1);
+    __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
+    __pyx_t_3 = PyObject_Call(__pyx_t_1, ((PyObject *)__pyx_k_tuple_22), NULL); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 38; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_3);
+    __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+    __pyx_v_inp = __pyx_t_3;
+    __pyx_t_3 = 0;
+    goto __pyx_L3;
+  }
+
+  /* "_cdec.pyx":39
+ *         if isinstance(sentence, unicode):
+ *             inp = sentence.strip().encode('utf8')
+ *         elif isinstance(sentence, str):             # <<<<<<<<<<<<<<
+ *             inp = sentence.strip()
+ *         elif isinstance(sentence, Lattice):
+ */
+  __pyx_t_3 = ((PyObject *)((PyObject*)(&PyString_Type)));
+  __Pyx_INCREF(__pyx_t_3);
+  __pyx_t_2 = __Pyx_TypeCheck(__pyx_v_sentence, __pyx_t_3); 
+  __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
+  if (__pyx_t_2) {
+
+    /* "_cdec.pyx":40
+ *             inp = sentence.strip().encode('utf8')
+ *         elif isinstance(sentence, str):
+ *             inp = sentence.strip()             # <<<<<<<<<<<<<<
+ *         elif isinstance(sentence, Lattice):
+ *             inp = str(sentence) # PLF format
+ */
+    __pyx_t_3 = PyObject_GetAttr(__pyx_v_sentence, __pyx_n_s__strip); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 40; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_3);
+    __pyx_t_1 = PyObject_Call(__pyx_t_3, ((PyObject *)__pyx_empty_tuple), NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 40; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_1);
+    __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
+    __pyx_v_inp = __pyx_t_1;
+    __pyx_t_1 = 0;
+    goto __pyx_L3;
+  }
+
+  /* "_cdec.pyx":41
+ *         elif isinstance(sentence, str):
+ *             inp = sentence.strip()
+ *         elif isinstance(sentence, Lattice):             # <<<<<<<<<<<<<<
+ *             inp = str(sentence) # PLF format
+ *         else:
+ */
+  __pyx_t_1 = ((PyObject *)((PyObject*)__pyx_ptype_5_cdec_Lattice));
+  __Pyx_INCREF(__pyx_t_1);
+  __pyx_t_2 = __Pyx_TypeCheck(__pyx_v_sentence, __pyx_t_1); 
+  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+  if (__pyx_t_2) {
+
+    /* "_cdec.pyx":42
+ *             inp = sentence.strip()
+ *         elif isinstance(sentence, Lattice):
+ *             inp = str(sentence) # PLF format             # <<<<<<<<<<<<<<
+ *         else:
+ *             raise TypeError('Cannot translate input type %s' % type(sentence))
+ */
+    __pyx_t_1 = PyTuple_New(1); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 42; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_1);
+    __Pyx_INCREF(__pyx_v_sentence);
+    PyTuple_SET_ITEM(__pyx_t_1, 0, __pyx_v_sentence);
+    __Pyx_GIVEREF(__pyx_v_sentence);
+    __pyx_t_3 = PyObject_Call(((PyObject *)((PyObject*)(&PyString_Type))), ((PyObject *)__pyx_t_1), NULL); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 42; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_3);
+    __Pyx_DECREF(((PyObject *)__pyx_t_1)); __pyx_t_1 = 0;
+    __pyx_v_inp = __pyx_t_3;
+    __pyx_t_3 = 0;
+    goto __pyx_L3;
+  }
+  /*else*/ {
+
+    /* "_cdec.pyx":44
+ *             inp = str(sentence) # PLF format
+ *         else:
+ *             raise TypeError('Cannot translate input type %s' % type(sentence))             # <<<<<<<<<<<<<<
+ *         if grammar:
+ *             self.dec.SetSentenceGrammarFromString(string(<char *> grammar))
+ */
+    __pyx_t_3 = PyNumber_Remainder(((PyObject *)__pyx_kp_s_23), ((PyObject *)Py_TYPE(__pyx_v_sentence))); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 44; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(((PyObject *)__pyx_t_3));
+    __pyx_t_1 = PyTuple_New(1); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 44; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_1);
+    PyTuple_SET_ITEM(__pyx_t_1, 0, ((PyObject *)__pyx_t_3));
+    __Pyx_GIVEREF(((PyObject *)__pyx_t_3));
+    __pyx_t_3 = 0;
+    __pyx_t_3 = PyObject_Call(__pyx_builtin_TypeError, ((PyObject *)__pyx_t_1), NULL); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 44; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_3);
+    __Pyx_DECREF(((PyObject *)__pyx_t_1)); __pyx_t_1 = 0;
+    __Pyx_Raise(__pyx_t_3, 0, 0, 0);
+    __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
+    {__pyx_filename = __pyx_f[0]; __pyx_lineno = 44; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  }
+  __pyx_L3:;
+
+  /* "_cdec.pyx":45
+ *         else:
+ *             raise TypeError('Cannot translate input type %s' % type(sentence))
+ *         if grammar:             # <<<<<<<<<<<<<<
+ *             self.dec.SetSentenceGrammarFromString(string(<char *> grammar))
+ *         cdef decoder.BasicObserver observer = decoder.BasicObserver()
+ */
+  __pyx_t_2 = __Pyx_PyObject_IsTrue(__pyx_v_grammar); if (unlikely(__pyx_t_2 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 45; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (__pyx_t_2) {
+
+    /* "_cdec.pyx":46
+ *             raise TypeError('Cannot translate input type %s' % type(sentence))
+ *         if grammar:
+ *             self.dec.SetSentenceGrammarFromString(string(<char *> grammar))             # <<<<<<<<<<<<<<
+ *         cdef decoder.BasicObserver observer = decoder.BasicObserver()
+ *         self.dec.Decode(string(<char *>inp), &observer)
+ */
+    __pyx_t_4 = PyBytes_AsString(__pyx_v_grammar); if (unlikely((!__pyx_t_4) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 46; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_v_self->dec->SetSentenceGrammarFromString(std::string(((char *)__pyx_t_4)));
+    goto __pyx_L4;
+  }
+  __pyx_L4:;
+
+  /* "_cdec.pyx":47
+ *         if grammar:
+ *             self.dec.SetSentenceGrammarFromString(string(<char *> grammar))
+ *         cdef decoder.BasicObserver observer = decoder.BasicObserver()             # <<<<<<<<<<<<<<
+ *         self.dec.Decode(string(<char *>inp), &observer)
+ *         if observer.hypergraph == NULL:
+ */
+  __pyx_v_observer = BasicObserver();
+
+  /* "_cdec.pyx":48
+ *             self.dec.SetSentenceGrammarFromString(string(<char *> grammar))
+ *         cdef decoder.BasicObserver observer = decoder.BasicObserver()
+ *         self.dec.Decode(string(<char *>inp), &observer)             # <<<<<<<<<<<<<<
+ *         if observer.hypergraph == NULL:
+ *             raise ParseFailed()
+ */
+  __pyx_t_4 = PyBytes_AsString(__pyx_v_inp); if (unlikely((!__pyx_t_4) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 48; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_v_self->dec->Decode(std::string(((char *)__pyx_t_4)), (&__pyx_v_observer));
+
+  /* "_cdec.pyx":49
+ *         cdef decoder.BasicObserver observer = decoder.BasicObserver()
+ *         self.dec.Decode(string(<char *>inp), &observer)
+ *         if observer.hypergraph == NULL:             # <<<<<<<<<<<<<<
+ *             raise ParseFailed()
+ *         cdef Hypergraph hg = Hypergraph()
+ */
+  __pyx_t_2 = (__pyx_v_observer.hypergraph == NULL);
+  if (__pyx_t_2) {
+
+    /* "_cdec.pyx":50
+ *         self.dec.Decode(string(<char *>inp), &observer)
+ *         if observer.hypergraph == NULL:
+ *             raise ParseFailed()             # <<<<<<<<<<<<<<
+ *         cdef Hypergraph hg = Hypergraph()
+ *         hg.hg = new hypergraph.Hypergraph(observer.hypergraph[0])
+ */
+    __pyx_t_3 = __Pyx_GetName(__pyx_m, __pyx_n_s__ParseFailed); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 50; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_3);
+    __pyx_t_1 = PyObject_Call(__pyx_t_3, ((PyObject *)__pyx_empty_tuple), NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 50; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_1);
+    __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
+    __Pyx_Raise(__pyx_t_1, 0, 0, 0);
+    __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+    {__pyx_filename = __pyx_f[0]; __pyx_lineno = 50; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    goto __pyx_L5;
+  }
+  __pyx_L5:;
+
+  /* "_cdec.pyx":51
+ *         if observer.hypergraph == NULL:
+ *             raise ParseFailed()
+ *         cdef Hypergraph hg = Hypergraph()             # <<<<<<<<<<<<<<
+ *         hg.hg = new hypergraph.Hypergraph(observer.hypergraph[0])
+ *         return hg
+ */
+  __pyx_t_1 = PyObject_Call(((PyObject *)((PyObject*)__pyx_ptype_5_cdec_Hypergraph)), ((PyObject *)__pyx_empty_tuple), NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 51; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_1);
+  __pyx_v_hg = ((struct __pyx_obj_5_cdec_Hypergraph *)__pyx_t_1);
+  __pyx_t_1 = 0;
+
+  /* "_cdec.pyx":52
+ *             raise ParseFailed()
+ *         cdef Hypergraph hg = Hypergraph()
+ *         hg.hg = new hypergraph.Hypergraph(observer.hypergraph[0])             # <<<<<<<<<<<<<<
+ *         return hg
+ */
+  __pyx_v_hg->hg = new Hypergraph((__pyx_v_observer.hypergraph[0]));
+
+  /* "_cdec.pyx":53
+ *         cdef Hypergraph hg = Hypergraph()
+ *         hg.hg = new hypergraph.Hypergraph(observer.hypergraph[0])
+ *         return hg             # <<<<<<<<<<<<<<
+ */
+  __Pyx_XDECREF(__pyx_r);
+  __Pyx_INCREF(((PyObject *)__pyx_v_hg));
+  __pyx_r = ((PyObject *)__pyx_v_hg);
+  goto __pyx_L0;
+
+  __pyx_r = Py_None; __Pyx_INCREF(Py_None);
+  goto __pyx_L0;
+  __pyx_L1_error:;
+  __Pyx_XDECREF(__pyx_t_1);
+  __Pyx_XDECREF(__pyx_t_3);
+  __Pyx_AddTraceback("_cdec.Decoder.translate", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __pyx_r = NULL;
+  __pyx_L0:;
+  __Pyx_XDECREF(__pyx_v_inp);
+  __Pyx_XDECREF((PyObject *)__pyx_v_hg);
+  __Pyx_XGIVEREF(__pyx_r);
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+/* Python wrapper */
+static PyObject *__pyx_pw_5_cdec_7Decoder_7weights_1__get__(PyObject *__pyx_v_self); /*proto*/
+static PyObject *__pyx_pw_5_cdec_7Decoder_7weights_1__get__(PyObject *__pyx_v_self) {
+  PyObject *__pyx_r = 0;
+  __Pyx_RefNannyDeclarations
+  __Pyx_RefNannySetupContext("__get__ (wrapper)", 0);
+  __pyx_r = __pyx_pf_5_cdec_7Decoder_7weights___get__(((struct __pyx_obj_5_cdec_Decoder *)__pyx_v_self));
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+/* "_cdec.pyx":17
+ * cdef class Decoder:
+ *     cdef decoder.Decoder* dec
+ *     cdef public DenseVector weights             # <<<<<<<<<<<<<<
+ * 
+ *     def __cinit__(self, char* config):
+ */
+
+static PyObject *__pyx_pf_5_cdec_7Decoder_7weights___get__(struct __pyx_obj_5_cdec_Decoder *__pyx_v_self) {
+  PyObject *__pyx_r = NULL;
+  __Pyx_RefNannyDeclarations
+  __Pyx_RefNannySetupContext("__get__", 0);
+  __Pyx_XDECREF(__pyx_r);
+  __Pyx_INCREF(((PyObject *)__pyx_v_self->weights));
+  __pyx_r = ((PyObject *)__pyx_v_self->weights);
+  goto __pyx_L0;
+
+  __pyx_r = Py_None; __Pyx_INCREF(Py_None);
+  __pyx_L0:;
+  __Pyx_XGIVEREF(__pyx_r);
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+/* Python wrapper */
+static int __pyx_pw_5_cdec_7Decoder_7weights_3__set__(PyObject *__pyx_v_self, PyObject *__pyx_v_value); /*proto*/
+static int __pyx_pw_5_cdec_7Decoder_7weights_3__set__(PyObject *__pyx_v_self, PyObject *__pyx_v_value) {
+  int __pyx_r;
+  __Pyx_RefNannyDeclarations
+  __Pyx_RefNannySetupContext("__set__ (wrapper)", 0);
+  __pyx_r = __pyx_pf_5_cdec_7Decoder_7weights_2__set__(((struct __pyx_obj_5_cdec_Decoder *)__pyx_v_self), ((PyObject *)__pyx_v_value));
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+static int __pyx_pf_5_cdec_7Decoder_7weights_2__set__(struct __pyx_obj_5_cdec_Decoder *__pyx_v_self, PyObject *__pyx_v_value) {
+  int __pyx_r;
+  __Pyx_RefNannyDeclarations
+  int __pyx_lineno = 0;
+  const char *__pyx_filename = NULL;
+  int __pyx_clineno = 0;
+  __Pyx_RefNannySetupContext("__set__", 0);
+  if (!(likely(((__pyx_v_value) == Py_None) || likely(__Pyx_TypeTest(__pyx_v_value, __pyx_ptype_5_cdec_DenseVector))))) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 17; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_INCREF(__pyx_v_value);
+  __Pyx_GIVEREF(__pyx_v_value);
+  __Pyx_GOTREF(__pyx_v_self->weights);
+  __Pyx_DECREF(((PyObject *)__pyx_v_self->weights));
+  __pyx_v_self->weights = ((struct __pyx_obj_5_cdec_DenseVector *)__pyx_v_value);
+
+  __pyx_r = 0;
+  goto __pyx_L0;
+  __pyx_L1_error:;
+  __Pyx_AddTraceback("_cdec.Decoder.weights.__set__", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __pyx_r = -1;
+  __pyx_L0:;
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+/* Python wrapper */
+static int __pyx_pw_5_cdec_7Decoder_7weights_5__del__(PyObject *__pyx_v_self); /*proto*/
+static int __pyx_pw_5_cdec_7Decoder_7weights_5__del__(PyObject *__pyx_v_self) {
+  int __pyx_r;
+  __Pyx_RefNannyDeclarations
+  __Pyx_RefNannySetupContext("__del__ (wrapper)", 0);
+  __pyx_r = __pyx_pf_5_cdec_7Decoder_7weights_4__del__(((struct __pyx_obj_5_cdec_Decoder *)__pyx_v_self));
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+static int __pyx_pf_5_cdec_7Decoder_7weights_4__del__(struct __pyx_obj_5_cdec_Decoder *__pyx_v_self) {
+  int __pyx_r;
+  __Pyx_RefNannyDeclarations
+  __Pyx_RefNannySetupContext("__del__", 0);
+  __Pyx_INCREF(Py_None);
+  __Pyx_GIVEREF(Py_None);
+  __Pyx_GOTREF(__pyx_v_self->weights);
+  __Pyx_DECREF(((PyObject *)__pyx_v_self->weights));
+  __pyx_v_self->weights = ((struct __pyx_obj_5_cdec_DenseVector *)Py_None);
+
+  __pyx_r = 0;
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+static PyObject *__pyx_tp_new_5_cdec_DenseVector(PyTypeObject *t, PyObject *a, PyObject *k) {
+  PyObject *o = (*t->tp_alloc)(t, 0);
+  if (!o) return 0;
+  return o;
+}
+
+static void __pyx_tp_dealloc_5_cdec_DenseVector(PyObject *o) {
+  (*Py_TYPE(o)->tp_free)(o);
+}
+static PyObject *__pyx_sq_item_5_cdec_DenseVector(PyObject *o, Py_ssize_t i) {
+  PyObject *r;
+  PyObject *x = PyInt_FromSsize_t(i); if(!x) return 0;
+  r = Py_TYPE(o)->tp_as_mapping->mp_subscript(o, x);
+  Py_DECREF(x);
+  return r;
+}
+
+static int __pyx_mp_ass_subscript_5_cdec_DenseVector(PyObject *o, PyObject *i, PyObject *v) {
+  if (v) {
+    return __pyx_pw_5_cdec_11DenseVector_3__setitem__(o, i, v);
+  }
+  else {
+    PyErr_Format(PyExc_NotImplementedError,
+      "Subscript deletion not supported by %s", Py_TYPE(o)->tp_name);
+    return -1;
+  }
+}
+
+static PyMethodDef __pyx_methods_5_cdec_DenseVector[] = {
+  {__Pyx_NAMESTR("dot"), (PyCFunction)__pyx_pw_5_cdec_11DenseVector_8dot, METH_O, __Pyx_DOCSTR(0)},
+  {__Pyx_NAMESTR("tosparse"), (PyCFunction)__pyx_pw_5_cdec_11DenseVector_10tosparse, METH_NOARGS, __Pyx_DOCSTR(0)},
+  {0, 0, 0, 0}
+};
+
+static PyNumberMethods __pyx_tp_as_number_DenseVector = {
+  0, /*nb_add*/
+  0, /*nb_subtract*/
+  0, /*nb_multiply*/
+  #if PY_MAJOR_VERSION < 3
+  0, /*nb_divide*/
+  #endif
+  0, /*nb_remainder*/
+  0, /*nb_divmod*/
+  0, /*nb_power*/
+  0, /*nb_negative*/
+  0, /*nb_positive*/
+  0, /*nb_absolute*/
+  0, /*nb_nonzero*/
+  0, /*nb_invert*/
+  0, /*nb_lshift*/
+  0, /*nb_rshift*/
+  0, /*nb_and*/
+  0, /*nb_xor*/
+  0, /*nb_or*/
+  #if PY_MAJOR_VERSION < 3
+  0, /*nb_coerce*/
+  #endif
+  0, /*nb_int*/
+  #if PY_MAJOR_VERSION < 3
+  0, /*nb_long*/
+  #else
+  0, /*reserved*/
+  #endif
+  0, /*nb_float*/
+  #if PY_MAJOR_VERSION < 3
+  0, /*nb_oct*/
+  #endif
+  #if PY_MAJOR_VERSION < 3
+  0, /*nb_hex*/
+  #endif
+  0, /*nb_inplace_add*/
+  0, /*nb_inplace_subtract*/
+  0, /*nb_inplace_multiply*/
+  #if PY_MAJOR_VERSION < 3
+  0, /*nb_inplace_divide*/
+  #endif
+  0, /*nb_inplace_remainder*/
+  0, /*nb_inplace_power*/
+  0, /*nb_inplace_lshift*/
+  0, /*nb_inplace_rshift*/
+  0, /*nb_inplace_and*/
+  0, /*nb_inplace_xor*/
+  0, /*nb_inplace_or*/
+  0, /*nb_floor_divide*/
+  0, /*nb_true_divide*/
+  0, /*nb_inplace_floor_divide*/
+  0, /*nb_inplace_true_divide*/
+  #if PY_VERSION_HEX >= 0x02050000
+  0, /*nb_index*/
+  #endif
+};
+
+static PySequenceMethods __pyx_tp_as_sequence_DenseVector = {
+  0, /*sq_length*/
+  0, /*sq_concat*/
+  0, /*sq_repeat*/
+  __pyx_sq_item_5_cdec_DenseVector, /*sq_item*/
+  0, /*sq_slice*/
+  0, /*sq_ass_item*/
+  0, /*sq_ass_slice*/
+  0, /*sq_contains*/
+  0, /*sq_inplace_concat*/
+  0, /*sq_inplace_repeat*/
+};
+
+static PyMappingMethods __pyx_tp_as_mapping_DenseVector = {
+  0, /*mp_length*/
+  __pyx_pw_5_cdec_11DenseVector_1__getitem__, /*mp_subscript*/
+  __pyx_mp_ass_subscript_5_cdec_DenseVector, /*mp_ass_subscript*/
+};
+
+static PyBufferProcs __pyx_tp_as_buffer_DenseVector = {
+  #if PY_MAJOR_VERSION < 3
+  0, /*bf_getreadbuffer*/
+  #endif
+  #if PY_MAJOR_VERSION < 3
+  0, /*bf_getwritebuffer*/
+  #endif
+  #if PY_MAJOR_VERSION < 3
+  0, /*bf_getsegcount*/
+  #endif
+  #if PY_MAJOR_VERSION < 3
+  0, /*bf_getcharbuffer*/
+  #endif
+  #if PY_VERSION_HEX >= 0x02060000
+  0, /*bf_getbuffer*/
+  #endif
+  #if PY_VERSION_HEX >= 0x02060000
+  0, /*bf_releasebuffer*/
+  #endif
+};
+
+static PyTypeObject __pyx_type_5_cdec_DenseVector = {
+  PyVarObject_HEAD_INIT(0, 0)
+  __Pyx_NAMESTR("_cdec.DenseVector"), /*tp_name*/
+  sizeof(struct __pyx_obj_5_cdec_DenseVector), /*tp_basicsize*/
+  0, /*tp_itemsize*/
+  __pyx_tp_dealloc_5_cdec_DenseVector, /*tp_dealloc*/
+  0, /*tp_print*/
+  0, /*tp_getattr*/
+  0, /*tp_setattr*/
+  #if PY_MAJOR_VERSION < 3
+  0, /*tp_compare*/
+  #else
+  0, /*reserved*/
+  #endif
+  0, /*tp_repr*/
+  &__pyx_tp_as_number_DenseVector, /*tp_as_number*/
+  &__pyx_tp_as_sequence_DenseVector, /*tp_as_sequence*/
+  &__pyx_tp_as_mapping_DenseVector, /*tp_as_mapping*/
+  0, /*tp_hash*/
+  0, /*tp_call*/
+  0, /*tp_str*/
+  0, /*tp_getattro*/
+  0, /*tp_setattro*/
+  &__pyx_tp_as_buffer_DenseVector, /*tp_as_buffer*/
+  Py_TPFLAGS_DEFAULT|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_BASETYPE, /*tp_flags*/
+  0, /*tp_doc*/
+  0, /*tp_traverse*/
+  0, /*tp_clear*/
+  0, /*tp_richcompare*/
+  0, /*tp_weaklistoffset*/
+  __pyx_pw_5_cdec_11DenseVector_5__iter__, /*tp_iter*/
+  0, /*tp_iternext*/
+  __pyx_methods_5_cdec_DenseVector, /*tp_methods*/
+  0, /*tp_members*/
+  0, /*tp_getset*/
+  0, /*tp_base*/
+  0, /*tp_dict*/
+  0, /*tp_descr_get*/
+  0, /*tp_descr_set*/
+  0, /*tp_dictoffset*/
+  0, /*tp_init*/
+  0, /*tp_alloc*/
+  __pyx_tp_new_5_cdec_DenseVector, /*tp_new*/
+  0, /*tp_free*/
+  0, /*tp_is_gc*/
+  0, /*tp_bases*/
+  0, /*tp_mro*/
+  0, /*tp_cache*/
+  0, /*tp_subclasses*/
+  0, /*tp_weaklist*/
+  0, /*tp_del*/
+  #if PY_VERSION_HEX >= 0x02060000
+  0, /*tp_version_tag*/
+  #endif
+};
+
+static PyObject *__pyx_tp_new_5_cdec_SparseVector(PyTypeObject *t, PyObject *a, PyObject *k) {
+  PyObject *o = (*t->tp_alloc)(t, 0);
+  if (!o) return 0;
+  return o;
+}
+
+static void __pyx_tp_dealloc_5_cdec_SparseVector(PyObject *o) {
+  (*Py_TYPE(o)->tp_free)(o);
+}
+static PyObject *__pyx_sq_item_5_cdec_SparseVector(PyObject *o, Py_ssize_t i) {
+  PyObject *r;
+  PyObject *x = PyInt_FromSsize_t(i); if(!x) return 0;
+  r = Py_TYPE(o)->tp_as_mapping->mp_subscript(o, x);
+  Py_DECREF(x);
+  return r;
+}
+
+static int __pyx_mp_ass_subscript_5_cdec_SparseVector(PyObject *o, PyObject *i, PyObject *v) {
+  if (v) {
+    return __pyx_pw_5_cdec_12SparseVector_3__setitem__(o, i, v);
+  }
+  else {
+    PyErr_Format(PyExc_NotImplementedError,
+      "Subscript deletion not supported by %s", Py_TYPE(o)->tp_name);
+    return -1;
+  }
+}
+
+static PyMethodDef __pyx_methods_5_cdec_SparseVector[] = {
+  {__Pyx_NAMESTR("dot"), (PyCFunction)__pyx_pw_5_cdec_12SparseVector_8dot, METH_O, __Pyx_DOCSTR(0)},
+  {__Pyx_NAMESTR("todense"), (PyCFunction)__pyx_pw_5_cdec_12SparseVector_10todense, METH_NOARGS, __Pyx_DOCSTR(0)},
+  {0, 0, 0, 0}
+};
+
+static PyNumberMethods __pyx_tp_as_number_SparseVector = {
+  __pyx_pw_5_cdec_12SparseVector_26__add__, /*nb_add*/
+  __pyx_pw_5_cdec_12SparseVector_28__sub__, /*nb_subtract*/
+  __pyx_pw_5_cdec_12SparseVector_30__mul__, /*nb_multiply*/
+  #if PY_MAJOR_VERSION < 3
+  __pyx_pw_5_cdec_12SparseVector_32__div__, /*nb_divide*/
+  #endif
+  0, /*nb_remainder*/
+  0, /*nb_divmod*/
+  0, /*nb_power*/
+  0, /*nb_negative*/
+  0, /*nb_positive*/
+  0, /*nb_absolute*/
+  0, /*nb_nonzero*/
+  0, /*nb_invert*/
+  0, /*nb_lshift*/
+  0, /*nb_rshift*/
+  0, /*nb_and*/
+  0, /*nb_xor*/
+  0, /*nb_or*/
+  #if PY_MAJOR_VERSION < 3
+  0, /*nb_coerce*/
+  #endif
+  0, /*nb_int*/
+  #if PY_MAJOR_VERSION < 3
+  0, /*nb_long*/
+  #else
+  0, /*reserved*/
+  #endif
+  0, /*nb_float*/
+  #if PY_MAJOR_VERSION < 3
+  0, /*nb_oct*/
+  #endif
+  #if PY_MAJOR_VERSION < 3
+  0, /*nb_hex*/
+  #endif
+  __pyx_pw_5_cdec_12SparseVector_18__iadd__, /*nb_inplace_add*/
+  __pyx_pw_5_cdec_12SparseVector_20__isub__, /*nb_inplace_subtract*/
+  __pyx_pw_5_cdec_12SparseVector_22__imul__, /*nb_inplace_multiply*/
+  #if PY_MAJOR_VERSION < 3
+  __pyx_pw_5_cdec_12SparseVector_24__idiv__, /*nb_inplace_divide*/
+  #endif
+  0, /*nb_inplace_remainder*/
+  0, /*nb_inplace_power*/
+  0, /*nb_inplace_lshift*/
+  0, /*nb_inplace_rshift*/
+  0, /*nb_inplace_and*/
+  0, /*nb_inplace_xor*/
+  0, /*nb_inplace_or*/
+  0, /*nb_floor_divide*/
+  0, /*nb_true_divide*/
+  0, /*nb_inplace_floor_divide*/
+  0, /*nb_inplace_true_divide*/
+  #if PY_VERSION_HEX >= 0x02050000
+  0, /*nb_index*/
+  #endif
+};
+
+static PySequenceMethods __pyx_tp_as_sequence_SparseVector = {
+  __pyx_pw_5_cdec_12SparseVector_14__len__, /*sq_length*/
+  0, /*sq_concat*/
+  0, /*sq_repeat*/
+  __pyx_sq_item_5_cdec_SparseVector, /*sq_item*/
+  0, /*sq_slice*/
+  0, /*sq_ass_item*/
+  0, /*sq_ass_slice*/
+  __pyx_pw_5_cdec_12SparseVector_16__contains__, /*sq_contains*/
+  0, /*sq_inplace_concat*/
+  0, /*sq_inplace_repeat*/
+};
+
+static PyMappingMethods __pyx_tp_as_mapping_SparseVector = {
+  __pyx_pw_5_cdec_12SparseVector_14__len__, /*mp_length*/
+  __pyx_pw_5_cdec_12SparseVector_1__getitem__, /*mp_subscript*/
+  __pyx_mp_ass_subscript_5_cdec_SparseVector, /*mp_ass_subscript*/
+};
+
+static PyBufferProcs __pyx_tp_as_buffer_SparseVector = {
+  #if PY_MAJOR_VERSION < 3
+  0, /*bf_getreadbuffer*/
+  #endif
+  #if PY_MAJOR_VERSION < 3
+  0, /*bf_getwritebuffer*/
+  #endif
+  #if PY_MAJOR_VERSION < 3
+  0, /*bf_getsegcount*/
+  #endif
+  #if PY_MAJOR_VERSION < 3
+  0, /*bf_getcharbuffer*/
+  #endif
+  #if PY_VERSION_HEX >= 0x02060000
+  0, /*bf_getbuffer*/
+  #endif
+  #if PY_VERSION_HEX >= 0x02060000
+  0, /*bf_releasebuffer*/
+  #endif
+};
+
+static PyTypeObject __pyx_type_5_cdec_SparseVector = {
+  PyVarObject_HEAD_INIT(0, 0)
+  __Pyx_NAMESTR("_cdec.SparseVector"), /*tp_name*/
+  sizeof(struct __pyx_obj_5_cdec_SparseVector), /*tp_basicsize*/
+  0, /*tp_itemsize*/
+  __pyx_tp_dealloc_5_cdec_SparseVector, /*tp_dealloc*/
+  0, /*tp_print*/
+  0, /*tp_getattr*/
+  0, /*tp_setattr*/
+  #if PY_MAJOR_VERSION < 3
+  0, /*tp_compare*/
+  #else
+  0, /*reserved*/
+  #endif
+  0, /*tp_repr*/
+  &__pyx_tp_as_number_SparseVector, /*tp_as_number*/
+  &__pyx_tp_as_sequence_SparseVector, /*tp_as_sequence*/
+  &__pyx_tp_as_mapping_SparseVector, /*tp_as_mapping*/
+  0, /*tp_hash*/
+  0, /*tp_call*/
+  0, /*tp_str*/
+  0, /*tp_getattro*/
+  0, /*tp_setattro*/
+  &__pyx_tp_as_buffer_SparseVector, /*tp_as_buffer*/
+  Py_TPFLAGS_DEFAULT|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_BASETYPE, /*tp_flags*/
+  0, /*tp_doc*/
+  0, /*tp_traverse*/
+  0, /*tp_clear*/
+  __pyx_pw_5_cdec_12SparseVector_12__richcmp__, /*tp_richcompare*/
+  0, /*tp_weaklistoffset*/
+  __pyx_pw_5_cdec_12SparseVector_5__iter__, /*tp_iter*/
+  0, /*tp_iternext*/
+  __pyx_methods_5_cdec_SparseVector, /*tp_methods*/
+  0, /*tp_members*/
+  0, /*tp_getset*/
+  0, /*tp_base*/
+  0, /*tp_dict*/
+  0, /*tp_descr_get*/
+  0, /*tp_descr_set*/
+  0, /*tp_dictoffset*/
+  0, /*tp_init*/
+  0, /*tp_alloc*/
+  __pyx_tp_new_5_cdec_SparseVector, /*tp_new*/
+  0, /*tp_free*/
+  0, /*tp_is_gc*/
+  0, /*tp_bases*/
+  0, /*tp_mro*/
+  0, /*tp_cache*/
+  0, /*tp_subclasses*/
+  0, /*tp_weaklist*/
+  0, /*tp_del*/
+  #if PY_VERSION_HEX >= 0x02060000
+  0, /*tp_version_tag*/
+  #endif
+};
+
+static PyObject *__pyx_tp_new_5_cdec_Hypergraph(PyTypeObject *t, PyObject *a, PyObject *k) {
+  PyObject *o = (*t->tp_alloc)(t, 0);
+  if (!o) return 0;
+  return o;
+}
+
+static void __pyx_tp_dealloc_5_cdec_Hypergraph(PyObject *o) {
+  {
+    PyObject *etype, *eval, *etb;
+    PyErr_Fetch(&etype, &eval, &etb);
+    ++Py_REFCNT(o);
+    __pyx_pw_5_cdec_10Hypergraph_1__dealloc__(o);
+    if (PyErr_Occurred()) PyErr_WriteUnraisable(o);
+    --Py_REFCNT(o);
+    PyErr_Restore(etype, eval, etb);
+  }
+  (*Py_TYPE(o)->tp_free)(o);
+}
+
+static PyMethodDef __pyx_methods_5_cdec_Hypergraph[] = {
+  {__Pyx_NAMESTR("viterbi"), (PyCFunction)__pyx_pw_5_cdec_10Hypergraph_3viterbi, METH_NOARGS, __Pyx_DOCSTR(0)},
+  {__Pyx_NAMESTR("viterbi_tree"), (PyCFunction)__pyx_pw_5_cdec_10Hypergraph_5viterbi_tree, METH_NOARGS, __Pyx_DOCSTR(0)},
+  {__Pyx_NAMESTR("viterbi_source_tree"), (PyCFunction)__pyx_pw_5_cdec_10Hypergraph_7viterbi_source_tree, METH_NOARGS, __Pyx_DOCSTR(0)},
+  {__Pyx_NAMESTR("viterbi_features"), (PyCFunction)__pyx_pw_5_cdec_10Hypergraph_9viterbi_features, METH_NOARGS, __Pyx_DOCSTR(0)},
+  {__Pyx_NAMESTR("kbest"), (PyCFunction)__pyx_pw_5_cdec_10Hypergraph_11kbest, METH_O, __Pyx_DOCSTR(0)},
+  {__Pyx_NAMESTR("kbest_tree"), (PyCFunction)__pyx_pw_5_cdec_10Hypergraph_14kbest_tree, METH_O, __Pyx_DOCSTR(0)},
+  {__Pyx_NAMESTR("kbest_features"), (PyCFunction)__pyx_pw_5_cdec_10Hypergraph_17kbest_features, METH_O, __Pyx_DOCSTR(0)},
+  {__Pyx_NAMESTR("sample"), (PyCFunction)__pyx_pw_5_cdec_10Hypergraph_20sample, METH_O, __Pyx_DOCSTR(0)},
+  {__Pyx_NAMESTR("intersect"), (PyCFunction)__pyx_pw_5_cdec_10Hypergraph_23intersect, METH_O, __Pyx_DOCSTR(0)},
+  {__Pyx_NAMESTR("prune"), (PyCFunction)__pyx_pw_5_cdec_10Hypergraph_25prune, METH_VARARGS|METH_KEYWORDS, __Pyx_DOCSTR(0)},
+  {__Pyx_NAMESTR("lattice"), (PyCFunction)__pyx_pw_5_cdec_10Hypergraph_27lattice, METH_NOARGS, __Pyx_DOCSTR(0)},
+  {__Pyx_NAMESTR("reweight"), (PyCFunction)__pyx_pw_5_cdec_10Hypergraph_29reweight, METH_O, __Pyx_DOCSTR(0)},
+  {0, 0, 0, 0}
+};
+
+static PyNumberMethods __pyx_tp_as_number_Hypergraph = {
+  0, /*nb_add*/
+  0, /*nb_subtract*/
+  0, /*nb_multiply*/
+  #if PY_MAJOR_VERSION < 3
+  0, /*nb_divide*/
+  #endif
+  0, /*nb_remainder*/
+  0, /*nb_divmod*/
+  0, /*nb_power*/
+  0, /*nb_negative*/
+  0, /*nb_positive*/
+  0, /*nb_absolute*/
+  0, /*nb_nonzero*/
+  0, /*nb_invert*/
+  0, /*nb_lshift*/
+  0, /*nb_rshift*/
+  0, /*nb_and*/
+  0, /*nb_xor*/
+  0, /*nb_or*/
+  #if PY_MAJOR_VERSION < 3
+  0, /*nb_coerce*/
+  #endif
+  0, /*nb_int*/
+  #if PY_MAJOR_VERSION < 3
+  0, /*nb_long*/
+  #else
+  0, /*reserved*/
+  #endif
+  0, /*nb_float*/
+  #if PY_MAJOR_VERSION < 3
+  0, /*nb_oct*/
+  #endif
+  #if PY_MAJOR_VERSION < 3
+  0, /*nb_hex*/
+  #endif
+  0, /*nb_inplace_add*/
+  0, /*nb_inplace_subtract*/
+  0, /*nb_inplace_multiply*/
+  #if PY_MAJOR_VERSION < 3
+  0, /*nb_inplace_divide*/
+  #endif
+  0, /*nb_inplace_remainder*/
+  0, /*nb_inplace_power*/
+  0, /*nb_inplace_lshift*/
+  0, /*nb_inplace_rshift*/
+  0, /*nb_inplace_and*/
+  0, /*nb_inplace_xor*/
+  0, /*nb_inplace_or*/
+  0, /*nb_floor_divide*/
+  0, /*nb_true_divide*/
+  0, /*nb_inplace_floor_divide*/
+  0, /*nb_inplace_true_divide*/
+  #if PY_VERSION_HEX >= 0x02050000
+  0, /*nb_index*/
+  #endif
+};
+
+static PySequenceMethods __pyx_tp_as_sequence_Hypergraph = {
+  0, /*sq_length*/
+  0, /*sq_concat*/
+  0, /*sq_repeat*/
+  0, /*sq_item*/
+  0, /*sq_slice*/
+  0, /*sq_ass_item*/
+  0, /*sq_ass_slice*/
+  0, /*sq_contains*/
+  0, /*sq_inplace_concat*/
+  0, /*sq_inplace_repeat*/
+};
+
+static PyMappingMethods __pyx_tp_as_mapping_Hypergraph = {
+  0, /*mp_length*/
+  0, /*mp_subscript*/
+  0, /*mp_ass_subscript*/
+};
+
+static PyBufferProcs __pyx_tp_as_buffer_Hypergraph = {
+  #if PY_MAJOR_VERSION < 3
+  0, /*bf_getreadbuffer*/
+  #endif
+  #if PY_MAJOR_VERSION < 3
+  0, /*bf_getwritebuffer*/
+  #endif
+  #if PY_MAJOR_VERSION < 3
+  0, /*bf_getsegcount*/
+  #endif
+  #if PY_MAJOR_VERSION < 3
+  0, /*bf_getcharbuffer*/
+  #endif
+  #if PY_VERSION_HEX >= 0x02060000
+  0, /*bf_getbuffer*/
+  #endif
+  #if PY_VERSION_HEX >= 0x02060000
+  0, /*bf_releasebuffer*/
+  #endif
+};
+
+static PyTypeObject __pyx_type_5_cdec_Hypergraph = {
+  PyVarObject_HEAD_INIT(0, 0)
+  __Pyx_NAMESTR("_cdec.Hypergraph"), /*tp_name*/
+  sizeof(struct __pyx_obj_5_cdec_Hypergraph), /*tp_basicsize*/
+  0, /*tp_itemsize*/
+  __pyx_tp_dealloc_5_cdec_Hypergraph, /*tp_dealloc*/
+  0, /*tp_print*/
+  0, /*tp_getattr*/
+  0, /*tp_setattr*/
+  #if PY_MAJOR_VERSION < 3
+  0, /*tp_compare*/
+  #else
+  0, /*reserved*/
+  #endif
+  0, /*tp_repr*/
+  &__pyx_tp_as_number_Hypergraph, /*tp_as_number*/
+  &__pyx_tp_as_sequence_Hypergraph, /*tp_as_sequence*/
+  &__pyx_tp_as_mapping_Hypergraph, /*tp_as_mapping*/
+  0, /*tp_hash*/
+  0, /*tp_call*/
+  0, /*tp_str*/
+  0, /*tp_getattro*/
+  0, /*tp_setattro*/
+  &__pyx_tp_as_buffer_Hypergraph, /*tp_as_buffer*/
+  Py_TPFLAGS_DEFAULT|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_BASETYPE, /*tp_flags*/
+  0, /*tp_doc*/
+  0, /*tp_traverse*/
+  0, /*tp_clear*/
+  0, /*tp_richcompare*/
+  0, /*tp_weaklistoffset*/
+  0, /*tp_iter*/
+  0, /*tp_iternext*/
+  __pyx_methods_5_cdec_Hypergraph, /*tp_methods*/
+  0, /*tp_members*/
+  0, /*tp_getset*/
+  0, /*tp_base*/
+  0, /*tp_dict*/
+  0, /*tp_descr_get*/
+  0, /*tp_descr_set*/
+  0, /*tp_dictoffset*/
+  0, /*tp_init*/
+  0, /*tp_alloc*/
+  __pyx_tp_new_5_cdec_Hypergraph, /*tp_new*/
+  0, /*tp_free*/
+  0, /*tp_is_gc*/
+  0, /*tp_bases*/
+  0, /*tp_mro*/
+  0, /*tp_cache*/
+  0, /*tp_subclasses*/
+  0, /*tp_weaklist*/
+  0, /*tp_del*/
+  #if PY_VERSION_HEX >= 0x02060000
+  0, /*tp_version_tag*/
+  #endif
+};
+
+static PyObject *__pyx_tp_new_5_cdec_Lattice(PyTypeObject *t, PyObject *a, PyObject *k) {
+  PyObject *o = (*t->tp_alloc)(t, 0);
+  if (!o) return 0;
+  return o;
+}
+
+static void __pyx_tp_dealloc_5_cdec_Lattice(PyObject *o) {
+  {
+    PyObject *etype, *eval, *etb;
+    PyErr_Fetch(&etype, &eval, &etb);
+    ++Py_REFCNT(o);
+    __pyx_pw_5_cdec_7Lattice_14__dealloc__(o);
+    if (PyErr_Occurred()) PyErr_WriteUnraisable(o);
+    --Py_REFCNT(o);
+    PyErr_Restore(etype, eval, etb);
+  }
+  (*Py_TYPE(o)->tp_free)(o);
+}
+static PyObject *__pyx_sq_item_5_cdec_Lattice(PyObject *o, Py_ssize_t i) {
+  PyObject *r;
+  PyObject *x = PyInt_FromSsize_t(i); if(!x) return 0;
+  r = Py_TYPE(o)->tp_as_mapping->mp_subscript(o, x);
+  Py_DECREF(x);
+  return r;
+}
+
+static int __pyx_mp_ass_subscript_5_cdec_Lattice(PyObject *o, PyObject *i, PyObject *v) {
+  if (v) {
+    return __pyx_pw_5_cdec_7Lattice_5__setitem__(o, i, v);
+  }
+  else {
+    PyErr_Format(PyExc_NotImplementedError,
+      "Subscript deletion not supported by %s", Py_TYPE(o)->tp_name);
+    return -1;
+  }
+}
+
+static PyMethodDef __pyx_methods_5_cdec_Lattice[] = {
+  {0, 0, 0, 0}
+};
+
+static PyNumberMethods __pyx_tp_as_number_Lattice = {
+  0, /*nb_add*/
+  0, /*nb_subtract*/
+  0, /*nb_multiply*/
+  #if PY_MAJOR_VERSION < 3
+  0, /*nb_divide*/
+  #endif
+  0, /*nb_remainder*/
+  0, /*nb_divmod*/
+  0, /*nb_power*/
+  0, /*nb_negative*/
+  0, /*nb_positive*/
+  0, /*nb_absolute*/
+  0, /*nb_nonzero*/
+  0, /*nb_invert*/
+  0, /*nb_lshift*/
+  0, /*nb_rshift*/
+  0, /*nb_and*/
+  0, /*nb_xor*/
+  0, /*nb_or*/
+  #if PY_MAJOR_VERSION < 3
+  0, /*nb_coerce*/
+  #endif
+  0, /*nb_int*/
+  #if PY_MAJOR_VERSION < 3
+  0, /*nb_long*/
+  #else
+  0, /*reserved*/
+  #endif
+  0, /*nb_float*/
+  #if PY_MAJOR_VERSION < 3
+  0, /*nb_oct*/
+  #endif
+  #if PY_MAJOR_VERSION < 3
+  0, /*nb_hex*/
+  #endif
+  0, /*nb_inplace_add*/
+  0, /*nb_inplace_subtract*/
+  0, /*nb_inplace_multiply*/
+  #if PY_MAJOR_VERSION < 3
+  0, /*nb_inplace_divide*/
+  #endif
+  0, /*nb_inplace_remainder*/
+  0, /*nb_inplace_power*/
+  0, /*nb_inplace_lshift*/
+  0, /*nb_inplace_rshift*/
+  0, /*nb_inplace_and*/
+  0, /*nb_inplace_xor*/
+  0, /*nb_inplace_or*/
+  0, /*nb_floor_divide*/
+  0, /*nb_true_divide*/
+  0, /*nb_inplace_floor_divide*/
+  0, /*nb_inplace_true_divide*/
+  #if PY_VERSION_HEX >= 0x02050000
+  0, /*nb_index*/
+  #endif
+};
+
+static PySequenceMethods __pyx_tp_as_sequence_Lattice = {
+  __pyx_pw_5_cdec_7Lattice_7__len__, /*sq_length*/
+  0, /*sq_concat*/
+  0, /*sq_repeat*/
+  __pyx_sq_item_5_cdec_Lattice, /*sq_item*/
+  0, /*sq_slice*/
+  0, /*sq_ass_item*/
+  0, /*sq_ass_slice*/
+  0, /*sq_contains*/
+  0, /*sq_inplace_concat*/
+  0, /*sq_inplace_repeat*/
+};
+
+static PyMappingMethods __pyx_tp_as_mapping_Lattice = {
+  __pyx_pw_5_cdec_7Lattice_7__len__, /*mp_length*/
+  __pyx_pw_5_cdec_7Lattice_3__getitem__, /*mp_subscript*/
+  __pyx_mp_ass_subscript_5_cdec_Lattice, /*mp_ass_subscript*/
+};
+
+static PyBufferProcs __pyx_tp_as_buffer_Lattice = {
+  #if PY_MAJOR_VERSION < 3
+  0, /*bf_getreadbuffer*/
+  #endif
+  #if PY_MAJOR_VERSION < 3
+  0, /*bf_getwritebuffer*/
+  #endif
+  #if PY_MAJOR_VERSION < 3
+  0, /*bf_getsegcount*/
+  #endif
+  #if PY_MAJOR_VERSION < 3
+  0, /*bf_getcharbuffer*/
+  #endif
+  #if PY_VERSION_HEX >= 0x02060000
+  0, /*bf_getbuffer*/
+  #endif
+  #if PY_VERSION_HEX >= 0x02060000
+  0, /*bf_releasebuffer*/
+  #endif
+};
+
+static PyTypeObject __pyx_type_5_cdec_Lattice = {
+  PyVarObject_HEAD_INIT(0, 0)
+  __Pyx_NAMESTR("_cdec.Lattice"), /*tp_name*/
+  sizeof(struct __pyx_obj_5_cdec_Lattice), /*tp_basicsize*/
+  0, /*tp_itemsize*/
+  __pyx_tp_dealloc_5_cdec_Lattice, /*tp_dealloc*/
+  0, /*tp_print*/
+  0, /*tp_getattr*/
+  0, /*tp_setattr*/
+  #if PY_MAJOR_VERSION < 3
+  0, /*tp_compare*/
+  #else
+  0, /*reserved*/
+  #endif
+  0, /*tp_repr*/
+  &__pyx_tp_as_number_Lattice, /*tp_as_number*/
+  &__pyx_tp_as_sequence_Lattice, /*tp_as_sequence*/
+  &__pyx_tp_as_mapping_Lattice, /*tp_as_mapping*/
+  0, /*tp_hash*/
+  0, /*tp_call*/
+  __pyx_pw_5_cdec_7Lattice_9__str__, /*tp_str*/
+  0, /*tp_getattro*/
+  0, /*tp_setattro*/
+  &__pyx_tp_as_buffer_Lattice, /*tp_as_buffer*/
+  Py_TPFLAGS_DEFAULT|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_BASETYPE, /*tp_flags*/
+  0, /*tp_doc*/
+  0, /*tp_traverse*/
+  0, /*tp_clear*/
+  0, /*tp_richcompare*/
+  0, /*tp_weaklistoffset*/
+  __pyx_pw_5_cdec_7Lattice_11__iter__, /*tp_iter*/
+  0, /*tp_iternext*/
+  __pyx_methods_5_cdec_Lattice, /*tp_methods*/
+  0, /*tp_members*/
+  0, /*tp_getset*/
+  0, /*tp_base*/
+  0, /*tp_dict*/
+  0, /*tp_descr_get*/
+  0, /*tp_descr_set*/
+  0, /*tp_dictoffset*/
+  __pyx_pw_5_cdec_7Lattice_1__init__, /*tp_init*/
+  0, /*tp_alloc*/
+  __pyx_tp_new_5_cdec_Lattice, /*tp_new*/
+  0, /*tp_free*/
+  0, /*tp_is_gc*/
+  0, /*tp_bases*/
+  0, /*tp_mro*/
+  0, /*tp_cache*/
+  0, /*tp_subclasses*/
+  0, /*tp_weaklist*/
+  0, /*tp_del*/
+  #if PY_VERSION_HEX >= 0x02060000
+  0, /*tp_version_tag*/
+  #endif
+};
+
+static PyObject *__pyx_tp_new_5_cdec_Candidate(PyTypeObject *t, PyObject *a, PyObject *k) {
+  PyObject *o = (*t->tp_alloc)(t, 0);
+  if (!o) return 0;
+  return o;
+}
+
+static void __pyx_tp_dealloc_5_cdec_Candidate(PyObject *o) {
+  (*Py_TYPE(o)->tp_free)(o);
+}
+
+static PyObject *__pyx_getprop_5_cdec_9Candidate_words(PyObject *o, void *x) {
+  return __pyx_pw_5_cdec_9Candidate_5words_1__get__(o);
+}
+
+static PyObject *__pyx_getprop_5_cdec_9Candidate_fmap(PyObject *o, void *x) {
+  return __pyx_pw_5_cdec_9Candidate_4fmap_1__get__(o);
+}
+
+static PyObject *__pyx_getprop_5_cdec_9Candidate_score(PyObject *o, void *x) {
+  return __pyx_pw_5_cdec_9Candidate_5score_1__get__(o);
+}
+
+static int __pyx_setprop_5_cdec_9Candidate_score(PyObject *o, PyObject *v, void *x) {
+  if (v) {
+    return __pyx_pw_5_cdec_9Candidate_5score_3__set__(o, v);
+  }
+  else {
+    PyErr_SetString(PyExc_NotImplementedError, "__del__");
+    return -1;
+  }
+}
+
+static PyMethodDef __pyx_methods_5_cdec_Candidate[] = {
+  {0, 0, 0, 0}
+};
+
+static struct PyGetSetDef __pyx_getsets_5_cdec_Candidate[] = {
+  {(char *)"words", __pyx_getprop_5_cdec_9Candidate_words, 0, 0, 0},
+  {(char *)"fmap", __pyx_getprop_5_cdec_9Candidate_fmap, 0, 0, 0},
+  {(char *)"score", __pyx_getprop_5_cdec_9Candidate_score, __pyx_setprop_5_cdec_9Candidate_score, 0, 0},
+  {0, 0, 0, 0, 0}
+};
+
+static PyNumberMethods __pyx_tp_as_number_Candidate = {
+  0, /*nb_add*/
+  0, /*nb_subtract*/
+  0, /*nb_multiply*/
+  #if PY_MAJOR_VERSION < 3
+  0, /*nb_divide*/
+  #endif
+  0, /*nb_remainder*/
+  0, /*nb_divmod*/
+  0, /*nb_power*/
+  0, /*nb_negative*/
+  0, /*nb_positive*/
+  0, /*nb_absolute*/
+  0, /*nb_nonzero*/
+  0, /*nb_invert*/
+  0, /*nb_lshift*/
+  0, /*nb_rshift*/
+  0, /*nb_and*/
+  0, /*nb_xor*/
+  0, /*nb_or*/
+  #if PY_MAJOR_VERSION < 3
+  0, /*nb_coerce*/
+  #endif
+  0, /*nb_int*/
+  #if PY_MAJOR_VERSION < 3
+  0, /*nb_long*/
+  #else
+  0, /*reserved*/
+  #endif
+  0, /*nb_float*/
+  #if PY_MAJOR_VERSION < 3
+  0, /*nb_oct*/
+  #endif
+  #if PY_MAJOR_VERSION < 3
+  0, /*nb_hex*/
+  #endif
+  0, /*nb_inplace_add*/
+  0, /*nb_inplace_subtract*/
+  0, /*nb_inplace_multiply*/
+  #if PY_MAJOR_VERSION < 3
+  0, /*nb_inplace_divide*/
+  #endif
+  0, /*nb_inplace_remainder*/
+  0, /*nb_inplace_power*/
+  0, /*nb_inplace_lshift*/
+  0, /*nb_inplace_rshift*/
+  0, /*nb_inplace_and*/
+  0, /*nb_inplace_xor*/
+  0, /*nb_inplace_or*/
+  0, /*nb_floor_divide*/
+  0, /*nb_true_divide*/
+  0, /*nb_inplace_floor_divide*/
+  0, /*nb_inplace_true_divide*/
+  #if PY_VERSION_HEX >= 0x02050000
+  0, /*nb_index*/
+  #endif
+};
+
+static PySequenceMethods __pyx_tp_as_sequence_Candidate = {
+  0, /*sq_length*/
+  0, /*sq_concat*/
+  0, /*sq_repeat*/
+  0, /*sq_item*/
+  0, /*sq_slice*/
+  0, /*sq_ass_item*/
+  0, /*sq_ass_slice*/
+  0, /*sq_contains*/
+  0, /*sq_inplace_concat*/
+  0, /*sq_inplace_repeat*/
+};
+
+static PyMappingMethods __pyx_tp_as_mapping_Candidate = {
+  0, /*mp_length*/
+  0, /*mp_subscript*/
+  0, /*mp_ass_subscript*/
+};
+
+static PyBufferProcs __pyx_tp_as_buffer_Candidate = {
+  #if PY_MAJOR_VERSION < 3
+  0, /*bf_getreadbuffer*/
+  #endif
+  #if PY_MAJOR_VERSION < 3
+  0, /*bf_getwritebuffer*/
+  #endif
+  #if PY_MAJOR_VERSION < 3
+  0, /*bf_getsegcount*/
+  #endif
+  #if PY_MAJOR_VERSION < 3
+  0, /*bf_getcharbuffer*/
+  #endif
+  #if PY_VERSION_HEX >= 0x02060000
+  0, /*bf_getbuffer*/
+  #endif
+  #if PY_VERSION_HEX >= 0x02060000
+  0, /*bf_releasebuffer*/
+  #endif
+};
+
+static PyTypeObject __pyx_type_5_cdec_Candidate = {
+  PyVarObject_HEAD_INIT(0, 0)
+  __Pyx_NAMESTR("_cdec.Candidate"), /*tp_name*/
+  sizeof(struct __pyx_obj_5_cdec_Candidate), /*tp_basicsize*/
+  0, /*tp_itemsize*/
+  __pyx_tp_dealloc_5_cdec_Candidate, /*tp_dealloc*/
+  0, /*tp_print*/
+  0, /*tp_getattr*/
+  0, /*tp_setattr*/
+  #if PY_MAJOR_VERSION < 3
+  0, /*tp_compare*/
+  #else
+  0, /*reserved*/
+  #endif
+  0, /*tp_repr*/
+  &__pyx_tp_as_number_Candidate, /*tp_as_number*/
+  &__pyx_tp_as_sequence_Candidate, /*tp_as_sequence*/
+  &__pyx_tp_as_mapping_Candidate, /*tp_as_mapping*/
+  0, /*tp_hash*/
+  0, /*tp_call*/
+  0, /*tp_str*/
+  0, /*tp_getattro*/
+  0, /*tp_setattro*/
+  &__pyx_tp_as_buffer_Candidate, /*tp_as_buffer*/
+  Py_TPFLAGS_DEFAULT|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_BASETYPE, /*tp_flags*/
+  0, /*tp_doc*/
+  0, /*tp_traverse*/
+  0, /*tp_clear*/
+  0, /*tp_richcompare*/
+  0, /*tp_weaklistoffset*/
+  0, /*tp_iter*/
+  0, /*tp_iternext*/
+  __pyx_methods_5_cdec_Candidate, /*tp_methods*/
+  0, /*tp_members*/
+  __pyx_getsets_5_cdec_Candidate, /*tp_getset*/
+  0, /*tp_base*/
+  0, /*tp_dict*/
+  0, /*tp_descr_get*/
+  0, /*tp_descr_set*/
+  0, /*tp_dictoffset*/
+  0, /*tp_init*/
+  0, /*tp_alloc*/
+  __pyx_tp_new_5_cdec_Candidate, /*tp_new*/
+  0, /*tp_free*/
+  0, /*tp_is_gc*/
+  0, /*tp_bases*/
+  0, /*tp_mro*/
+  0, /*tp_cache*/
+  0, /*tp_subclasses*/
+  0, /*tp_weaklist*/
+  0, /*tp_del*/
+  #if PY_VERSION_HEX >= 0x02060000
+  0, /*tp_version_tag*/
+  #endif
+};
+
+static PyObject *__pyx_tp_new_5_cdec_SufficientStats(PyTypeObject *t, PyObject *a, PyObject *k) {
+  PyObject *o = (*t->tp_alloc)(t, 0);
+  if (!o) return 0;
+  return o;
+}
+
+static void __pyx_tp_dealloc_5_cdec_SufficientStats(PyObject *o) {
+  {
+    PyObject *etype, *eval, *etb;
+    PyErr_Fetch(&etype, &eval, &etb);
+    ++Py_REFCNT(o);
+    __pyx_pw_5_cdec_15SufficientStats_1__dealloc__(o);
+    if (PyErr_Occurred()) PyErr_WriteUnraisable(o);
+    --Py_REFCNT(o);
+    PyErr_Restore(etype, eval, etb);
+  }
+  (*Py_TYPE(o)->tp_free)(o);
+}
+
+static PyObject *__pyx_getprop_5_cdec_15SufficientStats_score(PyObject *o, void *x) {
+  return __pyx_pw_5_cdec_15SufficientStats_5score_1__get__(o);
+}
+
+static PyObject *__pyx_getprop_5_cdec_15SufficientStats_detail(PyObject *o, void *x) {
+  return __pyx_pw_5_cdec_15SufficientStats_6detail_1__get__(o);
+}
+
+static PyMethodDef __pyx_methods_5_cdec_SufficientStats[] = {
+  {0, 0, 0, 0}
+};
+
+static struct PyGetSetDef __pyx_getsets_5_cdec_SufficientStats[] = {
+  {(char *)"score", __pyx_getprop_5_cdec_15SufficientStats_score, 0, 0, 0},
+  {(char *)"detail", __pyx_getprop_5_cdec_15SufficientStats_detail, 0, 0, 0},
+  {0, 0, 0, 0, 0}
+};
+
+static PyNumberMethods __pyx_tp_as_number_SufficientStats = {
+  __pyx_pw_5_cdec_15SufficientStats_10__add__, /*nb_add*/
+  0, /*nb_subtract*/
+  0, /*nb_multiply*/
+  #if PY_MAJOR_VERSION < 3
+  0, /*nb_divide*/
+  #endif
+  0, /*nb_remainder*/
+  0, /*nb_divmod*/
+  0, /*nb_power*/
+  0, /*nb_negative*/
+  0, /*nb_positive*/
+  0, /*nb_absolute*/
+  0, /*nb_nonzero*/
+  0, /*nb_invert*/
+  0, /*nb_lshift*/
+  0, /*nb_rshift*/
+  0, /*nb_and*/
+  0, /*nb_xor*/
+  0, /*nb_or*/
+  #if PY_MAJOR_VERSION < 3
+  0, /*nb_coerce*/
+  #endif
+  0, /*nb_int*/
+  #if PY_MAJOR_VERSION < 3
+  0, /*nb_long*/
+  #else
+  0, /*reserved*/
+  #endif
+  0, /*nb_float*/
+  #if PY_MAJOR_VERSION < 3
+  0, /*nb_oct*/
+  #endif
+  #if PY_MAJOR_VERSION < 3
+  0, /*nb_hex*/
+  #endif
+  __pyx_pw_5_cdec_15SufficientStats_8__iadd__, /*nb_inplace_add*/
+  0, /*nb_inplace_subtract*/
+  0, /*nb_inplace_multiply*/
+  #if PY_MAJOR_VERSION < 3
+  0, /*nb_inplace_divide*/
+  #endif
+  0, /*nb_inplace_remainder*/
+  0, /*nb_inplace_power*/
+  0, /*nb_inplace_lshift*/
+  0, /*nb_inplace_rshift*/
+  0, /*nb_inplace_and*/
+  0, /*nb_inplace_xor*/
+  0, /*nb_inplace_or*/
+  0, /*nb_floor_divide*/
+  0, /*nb_true_divide*/
+  0, /*nb_inplace_floor_divide*/
+  0, /*nb_inplace_true_divide*/
+  #if PY_VERSION_HEX >= 0x02050000
+  0, /*nb_index*/
+  #endif
+};
+
+static PySequenceMethods __pyx_tp_as_sequence_SufficientStats = {
+  __pyx_pw_5_cdec_15SufficientStats_3__len__, /*sq_length*/
+  0, /*sq_concat*/
+  0, /*sq_repeat*/
+  0, /*sq_item*/
+  0, /*sq_slice*/
+  0, /*sq_ass_item*/
+  0, /*sq_ass_slice*/
+  0, /*sq_contains*/
+  0, /*sq_inplace_concat*/
+  0, /*sq_inplace_repeat*/
+};
+
+static PyMappingMethods __pyx_tp_as_mapping_SufficientStats = {
+  __pyx_pw_5_cdec_15SufficientStats_3__len__, /*mp_length*/
+  0, /*mp_subscript*/
+  0, /*mp_ass_subscript*/
+};
+
+static PyBufferProcs __pyx_tp_as_buffer_SufficientStats = {
+  #if PY_MAJOR_VERSION < 3
+  0, /*bf_getreadbuffer*/
+  #endif
+  #if PY_MAJOR_VERSION < 3
+  0, /*bf_getwritebuffer*/
+  #endif
+  #if PY_MAJOR_VERSION < 3
+  0, /*bf_getsegcount*/
+  #endif
+  #if PY_MAJOR_VERSION < 3
+  0, /*bf_getcharbuffer*/
+  #endif
+  #if PY_VERSION_HEX >= 0x02060000
+  0, /*bf_getbuffer*/
+  #endif
+  #if PY_VERSION_HEX >= 0x02060000
+  0, /*bf_releasebuffer*/
+  #endif
+};
+
+static PyTypeObject __pyx_type_5_cdec_SufficientStats = {
+  PyVarObject_HEAD_INIT(0, 0)
+  __Pyx_NAMESTR("_cdec.SufficientStats"), /*tp_name*/
+  sizeof(struct __pyx_obj_5_cdec_SufficientStats), /*tp_basicsize*/
+  0, /*tp_itemsize*/
+  __pyx_tp_dealloc_5_cdec_SufficientStats, /*tp_dealloc*/
+  0, /*tp_print*/
+  0, /*tp_getattr*/
+  0, /*tp_setattr*/
+  #if PY_MAJOR_VERSION < 3
+  0, /*tp_compare*/
+  #else
+  0, /*reserved*/
+  #endif
+  0, /*tp_repr*/
+  &__pyx_tp_as_number_SufficientStats, /*tp_as_number*/
+  &__pyx_tp_as_sequence_SufficientStats, /*tp_as_sequence*/
+  &__pyx_tp_as_mapping_SufficientStats, /*tp_as_mapping*/
+  0, /*tp_hash*/
+  0, /*tp_call*/
+  0, /*tp_str*/
+  0, /*tp_getattro*/
+  0, /*tp_setattro*/
+  &__pyx_tp_as_buffer_SufficientStats, /*tp_as_buffer*/
+  Py_TPFLAGS_DEFAULT|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_BASETYPE, /*tp_flags*/
+  0, /*tp_doc*/
+  0, /*tp_traverse*/
+  0, /*tp_clear*/
+  0, /*tp_richcompare*/
+  0, /*tp_weaklistoffset*/
+  __pyx_pw_5_cdec_15SufficientStats_5__iter__, /*tp_iter*/
+  0, /*tp_iternext*/
+  __pyx_methods_5_cdec_SufficientStats, /*tp_methods*/
+  0, /*tp_members*/
+  __pyx_getsets_5_cdec_SufficientStats, /*tp_getset*/
+  0, /*tp_base*/
+  0, /*tp_dict*/
+  0, /*tp_descr_get*/
+  0, /*tp_descr_set*/
+  0, /*tp_dictoffset*/
+  0, /*tp_init*/
+  0, /*tp_alloc*/
+  __pyx_tp_new_5_cdec_SufficientStats, /*tp_new*/
+  0, /*tp_free*/
+  0, /*tp_is_gc*/
+  0, /*tp_bases*/
+  0, /*tp_mro*/
+  0, /*tp_cache*/
+  0, /*tp_subclasses*/
+  0, /*tp_weaklist*/
+  0, /*tp_del*/
+  #if PY_VERSION_HEX >= 0x02060000
+  0, /*tp_version_tag*/
+  #endif
+};
+
+static PyObject *__pyx_tp_new_5_cdec_SegmentEvaluator(PyTypeObject *t, PyObject *a, PyObject *k) {
+  PyObject *o = (*t->tp_alloc)(t, 0);
+  if (!o) return 0;
+  return o;
+}
+
+static void __pyx_tp_dealloc_5_cdec_SegmentEvaluator(PyObject *o) {
+  {
+    PyObject *etype, *eval, *etb;
+    PyErr_Fetch(&etype, &eval, &etb);
+    ++Py_REFCNT(o);
+    __pyx_pw_5_cdec_16SegmentEvaluator_1__dealloc__(o);
+    if (PyErr_Occurred()) PyErr_WriteUnraisable(o);
+    --Py_REFCNT(o);
+    PyErr_Restore(etype, eval, etb);
+  }
+  (*Py_TYPE(o)->tp_free)(o);
+}
+
+static PyMethodDef __pyx_methods_5_cdec_SegmentEvaluator[] = {
+  {__Pyx_NAMESTR("evaluate"), (PyCFunction)__pyx_pw_5_cdec_16SegmentEvaluator_3evaluate, METH_O, __Pyx_DOCSTR(0)},
+  {__Pyx_NAMESTR("candidate_set"), (PyCFunction)__pyx_pw_5_cdec_16SegmentEvaluator_5candidate_set, METH_VARARGS|METH_KEYWORDS, __Pyx_DOCSTR(0)},
+  {0, 0, 0, 0}
+};
+
+static PyNumberMethods __pyx_tp_as_number_SegmentEvaluator = {
+  0, /*nb_add*/
+  0, /*nb_subtract*/
+  0, /*nb_multiply*/
+  #if PY_MAJOR_VERSION < 3
+  0, /*nb_divide*/
+  #endif
+  0, /*nb_remainder*/
+  0, /*nb_divmod*/
+  0, /*nb_power*/
+  0, /*nb_negative*/
+  0, /*nb_positive*/
+  0, /*nb_absolute*/
+  0, /*nb_nonzero*/
+  0, /*nb_invert*/
+  0, /*nb_lshift*/
+  0, /*nb_rshift*/
+  0, /*nb_and*/
+  0, /*nb_xor*/
+  0, /*nb_or*/
+  #if PY_MAJOR_VERSION < 3
+  0, /*nb_coerce*/
+  #endif
+  0, /*nb_int*/
+  #if PY_MAJOR_VERSION < 3
+  0, /*nb_long*/
+  #else
+  0, /*reserved*/
+  #endif
+  0, /*nb_float*/
+  #if PY_MAJOR_VERSION < 3
+  0, /*nb_oct*/
+  #endif
+  #if PY_MAJOR_VERSION < 3
+  0, /*nb_hex*/
+  #endif
+  0, /*nb_inplace_add*/
+  0, /*nb_inplace_subtract*/
+  0, /*nb_inplace_multiply*/
+  #if PY_MAJOR_VERSION < 3
+  0, /*nb_inplace_divide*/
+  #endif
+  0, /*nb_inplace_remainder*/
+  0, /*nb_inplace_power*/
+  0, /*nb_inplace_lshift*/
+  0, /*nb_inplace_rshift*/
+  0, /*nb_inplace_and*/
+  0, /*nb_inplace_xor*/
+  0, /*nb_inplace_or*/
+  0, /*nb_floor_divide*/
+  0, /*nb_true_divide*/
+  0, /*nb_inplace_floor_divide*/
+  0, /*nb_inplace_true_divide*/
+  #if PY_VERSION_HEX >= 0x02050000
+  0, /*nb_index*/
+  #endif
+};
+
+static PySequenceMethods __pyx_tp_as_sequence_SegmentEvaluator = {
+  0, /*sq_length*/
+  0, /*sq_concat*/
+  0, /*sq_repeat*/
+  0, /*sq_item*/
+  0, /*sq_slice*/
+  0, /*sq_ass_item*/
+  0, /*sq_ass_slice*/
+  0, /*sq_contains*/
+  0, /*sq_inplace_concat*/
+  0, /*sq_inplace_repeat*/
+};
+
+static PyMappingMethods __pyx_tp_as_mapping_SegmentEvaluator = {
+  0, /*mp_length*/
+  0, /*mp_subscript*/
+  0, /*mp_ass_subscript*/
+};
+
+static PyBufferProcs __pyx_tp_as_buffer_SegmentEvaluator = {
+  #if PY_MAJOR_VERSION < 3
+  0, /*bf_getreadbuffer*/
+  #endif
+  #if PY_MAJOR_VERSION < 3
+  0, /*bf_getwritebuffer*/
+  #endif
+  #if PY_MAJOR_VERSION < 3
+  0, /*bf_getsegcount*/
+  #endif
+  #if PY_MAJOR_VERSION < 3
+  0, /*bf_getcharbuffer*/
+  #endif
+  #if PY_VERSION_HEX >= 0x02060000
+  0, /*bf_getbuffer*/
+  #endif
+  #if PY_VERSION_HEX >= 0x02060000
+  0, /*bf_releasebuffer*/
+  #endif
+};
+
+static PyTypeObject __pyx_type_5_cdec_SegmentEvaluator = {
+  PyVarObject_HEAD_INIT(0, 0)
+  __Pyx_NAMESTR("_cdec.SegmentEvaluator"), /*tp_name*/
+  sizeof(struct __pyx_obj_5_cdec_SegmentEvaluator), /*tp_basicsize*/
+  0, /*tp_itemsize*/
+  __pyx_tp_dealloc_5_cdec_SegmentEvaluator, /*tp_dealloc*/
+  0, /*tp_print*/
+  0, /*tp_getattr*/
+  0, /*tp_setattr*/
+  #if PY_MAJOR_VERSION < 3
+  0, /*tp_compare*/
+  #else
+  0, /*reserved*/
+  #endif
+  0, /*tp_repr*/
+  &__pyx_tp_as_number_SegmentEvaluator, /*tp_as_number*/
+  &__pyx_tp_as_sequence_SegmentEvaluator, /*tp_as_sequence*/
+  &__pyx_tp_as_mapping_SegmentEvaluator, /*tp_as_mapping*/
+  0, /*tp_hash*/
+  0, /*tp_call*/
+  0, /*tp_str*/
+  0, /*tp_getattro*/
+  0, /*tp_setattro*/
+  &__pyx_tp_as_buffer_SegmentEvaluator, /*tp_as_buffer*/
+  Py_TPFLAGS_DEFAULT|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_BASETYPE, /*tp_flags*/
+  0, /*tp_doc*/
+  0, /*tp_traverse*/
+  0, /*tp_clear*/
+  0, /*tp_richcompare*/
+  0, /*tp_weaklistoffset*/
+  0, /*tp_iter*/
+  0, /*tp_iternext*/
+  __pyx_methods_5_cdec_SegmentEvaluator, /*tp_methods*/
+  0, /*tp_members*/
+  0, /*tp_getset*/
+  0, /*tp_base*/
+  0, /*tp_dict*/
+  0, /*tp_descr_get*/
+  0, /*tp_descr_set*/
+  0, /*tp_dictoffset*/
+  0, /*tp_init*/
+  0, /*tp_alloc*/
+  __pyx_tp_new_5_cdec_SegmentEvaluator, /*tp_new*/
+  0, /*tp_free*/
+  0, /*tp_is_gc*/
+  0, /*tp_bases*/
+  0, /*tp_mro*/
+  0, /*tp_cache*/
+  0, /*tp_subclasses*/
+  0, /*tp_weaklist*/
+  0, /*tp_del*/
+  #if PY_VERSION_HEX >= 0x02060000
+  0, /*tp_version_tag*/
+  #endif
+};
+
+static PyObject *__pyx_tp_new_5_cdec_Scorer(PyTypeObject *t, PyObject *a, PyObject *k) {
   PyObject *o = (*t->tp_alloc)(t, 0);
   if (!o) return 0;
+  if (__pyx_pw_5_cdec_6Scorer_1__cinit__(o, a, k) < 0) {
+    Py_DECREF(o); o = 0;
+  }
   return o;
 }
 
-static void __pyx_tp_dealloc_5_cdec_DenseVector(PyObject *o) {
+static void __pyx_tp_dealloc_5_cdec_Scorer(PyObject *o) {
   (*Py_TYPE(o)->tp_free)(o);
 }
-static PyObject *__pyx_sq_item_5_cdec_DenseVector(PyObject *o, Py_ssize_t i) {
-  PyObject *r;
-  PyObject *x = PyInt_FromSsize_t(i); if(!x) return 0;
-  r = Py_TYPE(o)->tp_as_mapping->mp_subscript(o, x);
-  Py_DECREF(x);
-  return r;
-}
-
-static int __pyx_mp_ass_subscript_5_cdec_DenseVector(PyObject *o, PyObject *i, PyObject *v) {
-  if (v) {
-    return __pyx_pw_5_cdec_11DenseVector_3__setitem__(o, i, v);
-  }
-  else {
-    PyErr_Format(PyExc_NotImplementedError,
-      "Subscript deletion not supported by %s", Py_TYPE(o)->tp_name);
-    return -1;
-  }
-}
 
-static PyMethodDef __pyx_methods_5_cdec_DenseVector[] = {
-  {__Pyx_NAMESTR("dot"), (PyCFunction)__pyx_pw_5_cdec_11DenseVector_8dot, METH_O, __Pyx_DOCSTR(0)},
-  {__Pyx_NAMESTR("tosparse"), (PyCFunction)__pyx_pw_5_cdec_11DenseVector_10tosparse, METH_NOARGS, __Pyx_DOCSTR(0)},
+static PyMethodDef __pyx_methods_5_cdec_Scorer[] = {
   {0, 0, 0, 0}
 };
 
-static PyNumberMethods __pyx_tp_as_number_DenseVector = {
+static PyNumberMethods __pyx_tp_as_number_Scorer = {
   0, /*nb_add*/
   0, /*nb_subtract*/
   0, /*nb_multiply*/
@@ -5931,11 +9512,11 @@ static PyNumberMethods __pyx_tp_as_number_DenseVector = {
   #endif
 };
 
-static PySequenceMethods __pyx_tp_as_sequence_DenseVector = {
+static PySequenceMethods __pyx_tp_as_sequence_Scorer = {
   0, /*sq_length*/
   0, /*sq_concat*/
   0, /*sq_repeat*/
-  __pyx_sq_item_5_cdec_DenseVector, /*sq_item*/
+  0, /*sq_item*/
   0, /*sq_slice*/
   0, /*sq_ass_item*/
   0, /*sq_ass_slice*/
@@ -5944,13 +9525,13 @@ static PySequenceMethods __pyx_tp_as_sequence_DenseVector = {
   0, /*sq_inplace_repeat*/
 };
 
-static PyMappingMethods __pyx_tp_as_mapping_DenseVector = {
+static PyMappingMethods __pyx_tp_as_mapping_Scorer = {
   0, /*mp_length*/
-  __pyx_pw_5_cdec_11DenseVector_1__getitem__, /*mp_subscript*/
-  __pyx_mp_ass_subscript_5_cdec_DenseVector, /*mp_ass_subscript*/
+  0, /*mp_subscript*/
+  0, /*mp_ass_subscript*/
 };
 
-static PyBufferProcs __pyx_tp_as_buffer_DenseVector = {
+static PyBufferProcs __pyx_tp_as_buffer_Scorer = {
   #if PY_MAJOR_VERSION < 3
   0, /*bf_getreadbuffer*/
   #endif
@@ -5971,12 +9552,12 @@ static PyBufferProcs __pyx_tp_as_buffer_DenseVector = {
   #endif
 };
 
-static PyTypeObject __pyx_type_5_cdec_DenseVector = {
+static PyTypeObject __pyx_type_5_cdec_Scorer = {
   PyVarObject_HEAD_INIT(0, 0)
-  __Pyx_NAMESTR("_cdec.DenseVector"), /*tp_name*/
-  sizeof(struct __pyx_obj_5_cdec_DenseVector), /*tp_basicsize*/
+  __Pyx_NAMESTR("_cdec.Scorer"), /*tp_name*/
+  sizeof(struct __pyx_obj_5_cdec_Scorer), /*tp_basicsize*/
   0, /*tp_itemsize*/
-  __pyx_tp_dealloc_5_cdec_DenseVector, /*tp_dealloc*/
+  __pyx_tp_dealloc_5_cdec_Scorer, /*tp_dealloc*/
   0, /*tp_print*/
   0, /*tp_getattr*/
   0, /*tp_setattr*/
@@ -5986,24 +9567,24 @@ static PyTypeObject __pyx_type_5_cdec_DenseVector = {
   0, /*reserved*/
   #endif
   0, /*tp_repr*/
-  &__pyx_tp_as_number_DenseVector, /*tp_as_number*/
-  &__pyx_tp_as_sequence_DenseVector, /*tp_as_sequence*/
-  &__pyx_tp_as_mapping_DenseVector, /*tp_as_mapping*/
+  &__pyx_tp_as_number_Scorer, /*tp_as_number*/
+  &__pyx_tp_as_sequence_Scorer, /*tp_as_sequence*/
+  &__pyx_tp_as_mapping_Scorer, /*tp_as_mapping*/
   0, /*tp_hash*/
-  0, /*tp_call*/
-  0, /*tp_str*/
+  __pyx_pw_5_cdec_6Scorer_3__call__, /*tp_call*/
+  __pyx_pw_5_cdec_6Scorer_5__str__, /*tp_str*/
   0, /*tp_getattro*/
   0, /*tp_setattro*/
-  &__pyx_tp_as_buffer_DenseVector, /*tp_as_buffer*/
+  &__pyx_tp_as_buffer_Scorer, /*tp_as_buffer*/
   Py_TPFLAGS_DEFAULT|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_BASETYPE, /*tp_flags*/
   0, /*tp_doc*/
   0, /*tp_traverse*/
   0, /*tp_clear*/
   0, /*tp_richcompare*/
   0, /*tp_weaklistoffset*/
-  __pyx_pw_5_cdec_11DenseVector_5__iter__, /*tp_iter*/
+  0, /*tp_iter*/
   0, /*tp_iternext*/
-  __pyx_methods_5_cdec_DenseVector, /*tp_methods*/
+  __pyx_methods_5_cdec_Scorer, /*tp_methods*/
   0, /*tp_members*/
   0, /*tp_getset*/
   0, /*tp_base*/
@@ -6013,7 +9594,7 @@ static PyTypeObject __pyx_type_5_cdec_DenseVector = {
   0, /*tp_dictoffset*/
   0, /*tp_init*/
   0, /*tp_alloc*/
-  __pyx_tp_new_5_cdec_DenseVector, /*tp_new*/
+  __pyx_tp_new_5_cdec_Scorer, /*tp_new*/
   0, /*tp_free*/
   0, /*tp_is_gc*/
   0, /*tp_bases*/
@@ -6027,43 +9608,78 @@ static PyTypeObject __pyx_type_5_cdec_DenseVector = {
   #endif
 };
 
-static PyObject *__pyx_tp_new_5_cdec_SparseVector(PyTypeObject *t, PyObject *a, PyObject *k) {
+static PyObject *__pyx_tp_new_5_cdec_Decoder(PyTypeObject *t, PyObject *a, PyObject *k) {
+  struct __pyx_obj_5_cdec_Decoder *p;
   PyObject *o = (*t->tp_alloc)(t, 0);
   if (!o) return 0;
+  p = ((struct __pyx_obj_5_cdec_Decoder *)o);
+  p->weights = ((struct __pyx_obj_5_cdec_DenseVector *)Py_None); Py_INCREF(Py_None);
+  if (__pyx_pw_5_cdec_7Decoder_1__cinit__(o, a, k) < 0) {
+    Py_DECREF(o); o = 0;
+  }
   return o;
 }
 
-static void __pyx_tp_dealloc_5_cdec_SparseVector(PyObject *o) {
+static void __pyx_tp_dealloc_5_cdec_Decoder(PyObject *o) {
+  struct __pyx_obj_5_cdec_Decoder *p = (struct __pyx_obj_5_cdec_Decoder *)o;
+  {
+    PyObject *etype, *eval, *etb;
+    PyErr_Fetch(&etype, &eval, &etb);
+    ++Py_REFCNT(o);
+    __pyx_pw_5_cdec_7Decoder_3__dealloc__(o);
+    if (PyErr_Occurred()) PyErr_WriteUnraisable(o);
+    --Py_REFCNT(o);
+    PyErr_Restore(etype, eval, etb);
+  }
+  Py_XDECREF(((PyObject *)p->weights));
   (*Py_TYPE(o)->tp_free)(o);
 }
-static PyObject *__pyx_sq_item_5_cdec_SparseVector(PyObject *o, Py_ssize_t i) {
-  PyObject *r;
-  PyObject *x = PyInt_FromSsize_t(i); if(!x) return 0;
-  r = Py_TYPE(o)->tp_as_mapping->mp_subscript(o, x);
-  Py_DECREF(x);
-  return r;
+
+static int __pyx_tp_traverse_5_cdec_Decoder(PyObject *o, visitproc v, void *a) {
+  int e;
+  struct __pyx_obj_5_cdec_Decoder *p = (struct __pyx_obj_5_cdec_Decoder *)o;
+  if (p->weights) {
+    e = (*v)(((PyObject*)p->weights), a); if (e) return e;
+  }
+  return 0;
 }
 
-static int __pyx_mp_ass_subscript_5_cdec_SparseVector(PyObject *o, PyObject *i, PyObject *v) {
+static int __pyx_tp_clear_5_cdec_Decoder(PyObject *o) {
+  struct __pyx_obj_5_cdec_Decoder *p = (struct __pyx_obj_5_cdec_Decoder *)o;
+  PyObject* tmp;
+  tmp = ((PyObject*)p->weights);
+  p->weights = ((struct __pyx_obj_5_cdec_DenseVector *)Py_None); Py_INCREF(Py_None);
+  Py_XDECREF(tmp);
+  return 0;
+}
+
+static PyObject *__pyx_getprop_5_cdec_7Decoder_weights(PyObject *o, void *x) {
+  return __pyx_pw_5_cdec_7Decoder_7weights_1__get__(o);
+}
+
+static int __pyx_setprop_5_cdec_7Decoder_weights(PyObject *o, PyObject *v, void *x) {
   if (v) {
-    return __pyx_pw_5_cdec_12SparseVector_3__setitem__(o, i, v);
+    return __pyx_pw_5_cdec_7Decoder_7weights_3__set__(o, v);
   }
   else {
-    PyErr_Format(PyExc_NotImplementedError,
-      "Subscript deletion not supported by %s", Py_TYPE(o)->tp_name);
-    return -1;
+    return __pyx_pw_5_cdec_7Decoder_7weights_5__del__(o);
   }
 }
 
-static PyMethodDef __pyx_methods_5_cdec_SparseVector[] = {
-  {__Pyx_NAMESTR("dot"), (PyCFunction)__pyx_pw_5_cdec_12SparseVector_8dot, METH_O, __Pyx_DOCSTR(0)},
-  {__Pyx_NAMESTR("todense"), (PyCFunction)__pyx_pw_5_cdec_12SparseVector_10todense, METH_NOARGS, __Pyx_DOCSTR(0)},
+static PyMethodDef __pyx_methods_5_cdec_Decoder[] = {
+  {__Pyx_NAMESTR("read_weights"), (PyCFunction)__pyx_pw_5_cdec_7Decoder_5read_weights, METH_O, __Pyx_DOCSTR(0)},
+  {__Pyx_NAMESTR("translate"), (PyCFunction)__pyx_pw_5_cdec_7Decoder_7translate, METH_VARARGS|METH_KEYWORDS, __Pyx_DOCSTR(0)},
   {0, 0, 0, 0}
 };
 
-static PyNumberMethods __pyx_tp_as_number_SparseVector = {
-  __pyx_pw_5_cdec_12SparseVector_26__add__, /*nb_add*/
-  __pyx_pw_5_cdec_12SparseVector_28__sub__, /*nb_subtract*/
+static struct PyGetSetDef __pyx_getsets_5_cdec_Decoder[] = {
+  {(char *)"weights", __pyx_getprop_5_cdec_7Decoder_weights, __pyx_setprop_5_cdec_7Decoder_weights, 0, 0},
+  {0, 0, 0, 0, 0}
+};
+
+static PyNumberMethods __pyx_tp_as_number_Decoder = {
+  0, /*nb_add*/
+  0, /*nb_subtract*/
   0, /*nb_multiply*/
   #if PY_MAJOR_VERSION < 3
   0, /*nb_divide*/
@@ -6097,11 +9713,11 @@ static PyNumberMethods __pyx_tp_as_number_SparseVector = {
   #if PY_MAJOR_VERSION < 3
   0, /*nb_hex*/
   #endif
-  __pyx_pw_5_cdec_12SparseVector_18__iadd__, /*nb_inplace_add*/
-  __pyx_pw_5_cdec_12SparseVector_20__isub__, /*nb_inplace_subtract*/
-  __pyx_pw_5_cdec_12SparseVector_22__imul__, /*nb_inplace_multiply*/
+  0, /*nb_inplace_add*/
+  0, /*nb_inplace_subtract*/
+  0, /*nb_inplace_multiply*/
   #if PY_MAJOR_VERSION < 3
-  __pyx_pw_5_cdec_12SparseVector_24__idiv__, /*nb_inplace_divide*/
+  0, /*nb_inplace_divide*/
   #endif
   0, /*nb_inplace_remainder*/
   0, /*nb_inplace_power*/
@@ -6119,26 +9735,26 @@ static PyNumberMethods __pyx_tp_as_number_SparseVector = {
   #endif
 };
 
-static PySequenceMethods __pyx_tp_as_sequence_SparseVector = {
-  __pyx_pw_5_cdec_12SparseVector_14__len__, /*sq_length*/
+static PySequenceMethods __pyx_tp_as_sequence_Decoder = {
+  0, /*sq_length*/
   0, /*sq_concat*/
   0, /*sq_repeat*/
-  __pyx_sq_item_5_cdec_SparseVector, /*sq_item*/
+  0, /*sq_item*/
   0, /*sq_slice*/
   0, /*sq_ass_item*/
   0, /*sq_ass_slice*/
-  __pyx_pw_5_cdec_12SparseVector_16__contains__, /*sq_contains*/
+  0, /*sq_contains*/
   0, /*sq_inplace_concat*/
   0, /*sq_inplace_repeat*/
 };
 
-static PyMappingMethods __pyx_tp_as_mapping_SparseVector = {
-  __pyx_pw_5_cdec_12SparseVector_14__len__, /*mp_length*/
-  __pyx_pw_5_cdec_12SparseVector_1__getitem__, /*mp_subscript*/
-  __pyx_mp_ass_subscript_5_cdec_SparseVector, /*mp_ass_subscript*/
+static PyMappingMethods __pyx_tp_as_mapping_Decoder = {
+  0, /*mp_length*/
+  0, /*mp_subscript*/
+  0, /*mp_ass_subscript*/
 };
 
-static PyBufferProcs __pyx_tp_as_buffer_SparseVector = {
+static PyBufferProcs __pyx_tp_as_buffer_Decoder = {
   #if PY_MAJOR_VERSION < 3
   0, /*bf_getreadbuffer*/
   #endif
@@ -6159,12 +9775,12 @@ static PyBufferProcs __pyx_tp_as_buffer_SparseVector = {
   #endif
 };
 
-static PyTypeObject __pyx_type_5_cdec_SparseVector = {
+static PyTypeObject __pyx_type_5_cdec_Decoder = {
   PyVarObject_HEAD_INIT(0, 0)
-  __Pyx_NAMESTR("_cdec.SparseVector"), /*tp_name*/
-  sizeof(struct __pyx_obj_5_cdec_SparseVector), /*tp_basicsize*/
+  __Pyx_NAMESTR("_cdec.Decoder"), /*tp_name*/
+  sizeof(struct __pyx_obj_5_cdec_Decoder), /*tp_basicsize*/
   0, /*tp_itemsize*/
-  __pyx_tp_dealloc_5_cdec_SparseVector, /*tp_dealloc*/
+  __pyx_tp_dealloc_5_cdec_Decoder, /*tp_dealloc*/
   0, /*tp_print*/
   0, /*tp_getattr*/
   0, /*tp_setattr*/
@@ -6174,26 +9790,26 @@ static PyTypeObject __pyx_type_5_cdec_SparseVector = {
   0, /*reserved*/
   #endif
   0, /*tp_repr*/
-  &__pyx_tp_as_number_SparseVector, /*tp_as_number*/
-  &__pyx_tp_as_sequence_SparseVector, /*tp_as_sequence*/
-  &__pyx_tp_as_mapping_SparseVector, /*tp_as_mapping*/
+  &__pyx_tp_as_number_Decoder, /*tp_as_number*/
+  &__pyx_tp_as_sequence_Decoder, /*tp_as_sequence*/
+  &__pyx_tp_as_mapping_Decoder, /*tp_as_mapping*/
   0, /*tp_hash*/
   0, /*tp_call*/
   0, /*tp_str*/
   0, /*tp_getattro*/
   0, /*tp_setattro*/
-  &__pyx_tp_as_buffer_SparseVector, /*tp_as_buffer*/
-  Py_TPFLAGS_DEFAULT|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_BASETYPE, /*tp_flags*/
+  &__pyx_tp_as_buffer_Decoder, /*tp_as_buffer*/
+  Py_TPFLAGS_DEFAULT|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_HAVE_GC, /*tp_flags*/
   0, /*tp_doc*/
-  0, /*tp_traverse*/
-  0, /*tp_clear*/
-  __pyx_pw_5_cdec_12SparseVector_12__richcmp__, /*tp_richcompare*/
+  __pyx_tp_traverse_5_cdec_Decoder, /*tp_traverse*/
+  __pyx_tp_clear_5_cdec_Decoder, /*tp_clear*/
+  0, /*tp_richcompare*/
   0, /*tp_weaklistoffset*/
-  __pyx_pw_5_cdec_12SparseVector_5__iter__, /*tp_iter*/
+  0, /*tp_iter*/
   0, /*tp_iternext*/
-  __pyx_methods_5_cdec_SparseVector, /*tp_methods*/
+  __pyx_methods_5_cdec_Decoder, /*tp_methods*/
   0, /*tp_members*/
-  0, /*tp_getset*/
+  __pyx_getsets_5_cdec_Decoder, /*tp_getset*/
   0, /*tp_base*/
   0, /*tp_dict*/
   0, /*tp_descr_get*/
@@ -6201,7 +9817,7 @@ static PyTypeObject __pyx_type_5_cdec_SparseVector = {
   0, /*tp_dictoffset*/
   0, /*tp_init*/
   0, /*tp_alloc*/
-  __pyx_tp_new_5_cdec_SparseVector, /*tp_new*/
+  __pyx_tp_new_5_cdec_Decoder, /*tp_new*/
   0, /*tp_free*/
   0, /*tp_is_gc*/
   0, /*tp_bases*/
@@ -6215,41 +9831,44 @@ static PyTypeObject __pyx_type_5_cdec_SparseVector = {
   #endif
 };
 
-static PyObject *__pyx_tp_new_5_cdec_Hypergraph(PyTypeObject *t, PyObject *a, PyObject *k) {
+static PyObject *__pyx_tp_new_5_cdec___pyx_scope_struct____iter__(PyTypeObject *t, PyObject *a, PyObject *k) {
+  struct __pyx_obj_5_cdec___pyx_scope_struct____iter__ *p;
   PyObject *o = (*t->tp_alloc)(t, 0);
   if (!o) return 0;
+  p = ((struct __pyx_obj_5_cdec___pyx_scope_struct____iter__ *)o);
+  p->__pyx_v_self = 0;
   return o;
 }
 
-static void __pyx_tp_dealloc_5_cdec_Hypergraph(PyObject *o) {
-  {
-    PyObject *etype, *eval, *etb;
-    PyErr_Fetch(&etype, &eval, &etb);
-    ++Py_REFCNT(o);
-    __pyx_pw_5_cdec_10Hypergraph_1__dealloc__(o);
-    if (PyErr_Occurred()) PyErr_WriteUnraisable(o);
-    --Py_REFCNT(o);
-    PyErr_Restore(etype, eval, etb);
-  }
+static void __pyx_tp_dealloc_5_cdec___pyx_scope_struct____iter__(PyObject *o) {
+  struct __pyx_obj_5_cdec___pyx_scope_struct____iter__ *p = (struct __pyx_obj_5_cdec___pyx_scope_struct____iter__ *)o;
+  Py_XDECREF(((PyObject *)p->__pyx_v_self));
   (*Py_TYPE(o)->tp_free)(o);
 }
 
-static PyMethodDef __pyx_methods_5_cdec_Hypergraph[] = {
-  {__Pyx_NAMESTR("viterbi"), (PyCFunction)__pyx_pw_5_cdec_10Hypergraph_3viterbi, METH_NOARGS, __Pyx_DOCSTR(0)},
-  {__Pyx_NAMESTR("viterbi_tree"), (PyCFunction)__pyx_pw_5_cdec_10Hypergraph_5viterbi_tree, METH_NOARGS, __Pyx_DOCSTR(0)},
-  {__Pyx_NAMESTR("viterbi_source_tree"), (PyCFunction)__pyx_pw_5_cdec_10Hypergraph_7viterbi_source_tree, METH_NOARGS, __Pyx_DOCSTR(0)},
-  {__Pyx_NAMESTR("viterbi_features"), (PyCFunction)__pyx_pw_5_cdec_10Hypergraph_9viterbi_features, METH_NOARGS, __Pyx_DOCSTR(0)},
-  {__Pyx_NAMESTR("kbest"), (PyCFunction)__pyx_pw_5_cdec_10Hypergraph_11kbest, METH_O, __Pyx_DOCSTR(0)},
-  {__Pyx_NAMESTR("kbest_tree"), (PyCFunction)__pyx_pw_5_cdec_10Hypergraph_14kbest_tree, METH_O, __Pyx_DOCSTR(0)},
-  {__Pyx_NAMESTR("sample"), (PyCFunction)__pyx_pw_5_cdec_10Hypergraph_17sample, METH_O, __Pyx_DOCSTR(0)},
-  {__Pyx_NAMESTR("intersect"), (PyCFunction)__pyx_pw_5_cdec_10Hypergraph_20intersect, METH_O, __Pyx_DOCSTR(0)},
-  {__Pyx_NAMESTR("prune"), (PyCFunction)__pyx_pw_5_cdec_10Hypergraph_22prune, METH_VARARGS|METH_KEYWORDS, __Pyx_DOCSTR(0)},
-  {__Pyx_NAMESTR("lattice"), (PyCFunction)__pyx_pw_5_cdec_10Hypergraph_24lattice, METH_NOARGS, __Pyx_DOCSTR(0)},
-  {__Pyx_NAMESTR("reweight"), (PyCFunction)__pyx_pw_5_cdec_10Hypergraph_26reweight, METH_O, __Pyx_DOCSTR(0)},
+static int __pyx_tp_traverse_5_cdec___pyx_scope_struct____iter__(PyObject *o, visitproc v, void *a) {
+  int e;
+  struct __pyx_obj_5_cdec___pyx_scope_struct____iter__ *p = (struct __pyx_obj_5_cdec___pyx_scope_struct____iter__ *)o;
+  if (p->__pyx_v_self) {
+    e = (*v)(((PyObject*)p->__pyx_v_self), a); if (e) return e;
+  }
+  return 0;
+}
+
+static int __pyx_tp_clear_5_cdec___pyx_scope_struct____iter__(PyObject *o) {
+  struct __pyx_obj_5_cdec___pyx_scope_struct____iter__ *p = (struct __pyx_obj_5_cdec___pyx_scope_struct____iter__ *)o;
+  PyObject* tmp;
+  tmp = ((PyObject*)p->__pyx_v_self);
+  p->__pyx_v_self = ((struct __pyx_obj_5_cdec_DenseVector *)Py_None); Py_INCREF(Py_None);
+  Py_XDECREF(tmp);
+  return 0;
+}
+
+static PyMethodDef __pyx_methods_5_cdec___pyx_scope_struct____iter__[] = {
   {0, 0, 0, 0}
 };
 
-static PyNumberMethods __pyx_tp_as_number_Hypergraph = {
+static PyNumberMethods __pyx_tp_as_number___pyx_scope_struct____iter__ = {
   0, /*nb_add*/
   0, /*nb_subtract*/
   0, /*nb_multiply*/
@@ -6307,7 +9926,7 @@ static PyNumberMethods __pyx_tp_as_number_Hypergraph = {
   #endif
 };
 
-static PySequenceMethods __pyx_tp_as_sequence_Hypergraph = {
+static PySequenceMethods __pyx_tp_as_sequence___pyx_scope_struct____iter__ = {
   0, /*sq_length*/
   0, /*sq_concat*/
   0, /*sq_repeat*/
@@ -6320,13 +9939,13 @@ static PySequenceMethods __pyx_tp_as_sequence_Hypergraph = {
   0, /*sq_inplace_repeat*/
 };
 
-static PyMappingMethods __pyx_tp_as_mapping_Hypergraph = {
+static PyMappingMethods __pyx_tp_as_mapping___pyx_scope_struct____iter__ = {
   0, /*mp_length*/
   0, /*mp_subscript*/
   0, /*mp_ass_subscript*/
 };
 
-static PyBufferProcs __pyx_tp_as_buffer_Hypergraph = {
+static PyBufferProcs __pyx_tp_as_buffer___pyx_scope_struct____iter__ = {
   #if PY_MAJOR_VERSION < 3
   0, /*bf_getreadbuffer*/
   #endif
@@ -6347,12 +9966,12 @@ static PyBufferProcs __pyx_tp_as_buffer_Hypergraph = {
   #endif
 };
 
-static PyTypeObject __pyx_type_5_cdec_Hypergraph = {
+static PyTypeObject __pyx_type_5_cdec___pyx_scope_struct____iter__ = {
   PyVarObject_HEAD_INIT(0, 0)
-  __Pyx_NAMESTR("_cdec.Hypergraph"), /*tp_name*/
-  sizeof(struct __pyx_obj_5_cdec_Hypergraph), /*tp_basicsize*/
+  __Pyx_NAMESTR("_cdec.__pyx_scope_struct____iter__"), /*tp_name*/
+  sizeof(struct __pyx_obj_5_cdec___pyx_scope_struct____iter__), /*tp_basicsize*/
   0, /*tp_itemsize*/
-  __pyx_tp_dealloc_5_cdec_Hypergraph, /*tp_dealloc*/
+  __pyx_tp_dealloc_5_cdec___pyx_scope_struct____iter__, /*tp_dealloc*/
   0, /*tp_print*/
   0, /*tp_getattr*/
   0, /*tp_setattr*/
@@ -6362,24 +9981,24 @@ static PyTypeObject __pyx_type_5_cdec_Hypergraph = {
   0, /*reserved*/
   #endif
   0, /*tp_repr*/
-  &__pyx_tp_as_number_Hypergraph, /*tp_as_number*/
-  &__pyx_tp_as_sequence_Hypergraph, /*tp_as_sequence*/
-  &__pyx_tp_as_mapping_Hypergraph, /*tp_as_mapping*/
+  &__pyx_tp_as_number___pyx_scope_struct____iter__, /*tp_as_number*/
+  &__pyx_tp_as_sequence___pyx_scope_struct____iter__, /*tp_as_sequence*/
+  &__pyx_tp_as_mapping___pyx_scope_struct____iter__, /*tp_as_mapping*/
   0, /*tp_hash*/
   0, /*tp_call*/
   0, /*tp_str*/
   0, /*tp_getattro*/
   0, /*tp_setattro*/
-  &__pyx_tp_as_buffer_Hypergraph, /*tp_as_buffer*/
-  Py_TPFLAGS_DEFAULT|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_BASETYPE, /*tp_flags*/
+  &__pyx_tp_as_buffer___pyx_scope_struct____iter__, /*tp_as_buffer*/
+  Py_TPFLAGS_DEFAULT|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_HAVE_GC, /*tp_flags*/
   0, /*tp_doc*/
-  0, /*tp_traverse*/
-  0, /*tp_clear*/
+  __pyx_tp_traverse_5_cdec___pyx_scope_struct____iter__, /*tp_traverse*/
+  __pyx_tp_clear_5_cdec___pyx_scope_struct____iter__, /*tp_clear*/
   0, /*tp_richcompare*/
   0, /*tp_weaklistoffset*/
   0, /*tp_iter*/
   0, /*tp_iternext*/
-  __pyx_methods_5_cdec_Hypergraph, /*tp_methods*/
+  __pyx_methods_5_cdec___pyx_scope_struct____iter__, /*tp_methods*/
   0, /*tp_members*/
   0, /*tp_getset*/
   0, /*tp_base*/
@@ -6389,7 +10008,7 @@ static PyTypeObject __pyx_type_5_cdec_Hypergraph = {
   0, /*tp_dictoffset*/
   0, /*tp_init*/
   0, /*tp_alloc*/
-  __pyx_tp_new_5_cdec_Hypergraph, /*tp_new*/
+  __pyx_tp_new_5_cdec___pyx_scope_struct____iter__, /*tp_new*/
   0, /*tp_free*/
   0, /*tp_is_gc*/
   0, /*tp_bases*/
@@ -6403,48 +10022,52 @@ static PyTypeObject __pyx_type_5_cdec_Hypergraph = {
   #endif
 };
 
-static PyObject *__pyx_tp_new_5_cdec_Lattice(PyTypeObject *t, PyObject *a, PyObject *k) {
+static PyObject *__pyx_tp_new_5_cdec___pyx_scope_struct_1___iter__(PyTypeObject *t, PyObject *a, PyObject *k) {
+  struct __pyx_obj_5_cdec___pyx_scope_struct_1___iter__ *p;
   PyObject *o = (*t->tp_alloc)(t, 0);
   if (!o) return 0;
+  p = ((struct __pyx_obj_5_cdec___pyx_scope_struct_1___iter__ *)o);
+  p->__pyx_v_fname = 0;
+  p->__pyx_v_self = 0;
   return o;
 }
 
-static void __pyx_tp_dealloc_5_cdec_Lattice(PyObject *o) {
-  {
-    PyObject *etype, *eval, *etb;
-    PyErr_Fetch(&etype, &eval, &etb);
-    ++Py_REFCNT(o);
-    __pyx_pw_5_cdec_7Lattice_14__dealloc__(o);
-    if (PyErr_Occurred()) PyErr_WriteUnraisable(o);
-    --Py_REFCNT(o);
-    PyErr_Restore(etype, eval, etb);
-  }
+static void __pyx_tp_dealloc_5_cdec___pyx_scope_struct_1___iter__(PyObject *o) {
+  struct __pyx_obj_5_cdec___pyx_scope_struct_1___iter__ *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_1___iter__ *)o;
+  Py_XDECREF(((PyObject *)p->__pyx_v_fname));
+  Py_XDECREF(((PyObject *)p->__pyx_v_self));
   (*Py_TYPE(o)->tp_free)(o);
 }
-static PyObject *__pyx_sq_item_5_cdec_Lattice(PyObject *o, Py_ssize_t i) {
-  PyObject *r;
-  PyObject *x = PyInt_FromSsize_t(i); if(!x) return 0;
-  r = Py_TYPE(o)->tp_as_mapping->mp_subscript(o, x);
-  Py_DECREF(x);
-  return r;
-}
 
-static int __pyx_mp_ass_subscript_5_cdec_Lattice(PyObject *o, PyObject *i, PyObject *v) {
-  if (v) {
-    return __pyx_pw_5_cdec_7Lattice_5__setitem__(o, i, v);
+static int __pyx_tp_traverse_5_cdec___pyx_scope_struct_1___iter__(PyObject *o, visitproc v, void *a) {
+  int e;
+  struct __pyx_obj_5_cdec___pyx_scope_struct_1___iter__ *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_1___iter__ *)o;
+  if (p->__pyx_v_fname) {
+    e = (*v)(p->__pyx_v_fname, a); if (e) return e;
   }
-  else {
-    PyErr_Format(PyExc_NotImplementedError,
-      "Subscript deletion not supported by %s", Py_TYPE(o)->tp_name);
-    return -1;
+  if (p->__pyx_v_self) {
+    e = (*v)(((PyObject*)p->__pyx_v_self), a); if (e) return e;
   }
+  return 0;
 }
 
-static PyMethodDef __pyx_methods_5_cdec_Lattice[] = {
+static int __pyx_tp_clear_5_cdec___pyx_scope_struct_1___iter__(PyObject *o) {
+  struct __pyx_obj_5_cdec___pyx_scope_struct_1___iter__ *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_1___iter__ *)o;
+  PyObject* tmp;
+  tmp = ((PyObject*)p->__pyx_v_fname);
+  p->__pyx_v_fname = ((PyObject*)Py_None); Py_INCREF(Py_None);
+  Py_XDECREF(tmp);
+  tmp = ((PyObject*)p->__pyx_v_self);
+  p->__pyx_v_self = ((struct __pyx_obj_5_cdec_SparseVector *)Py_None); Py_INCREF(Py_None);
+  Py_XDECREF(tmp);
+  return 0;
+}
+
+static PyMethodDef __pyx_methods_5_cdec___pyx_scope_struct_1___iter__[] = {
   {0, 0, 0, 0}
 };
 
-static PyNumberMethods __pyx_tp_as_number_Lattice = {
+static PyNumberMethods __pyx_tp_as_number___pyx_scope_struct_1___iter__ = {
   0, /*nb_add*/
   0, /*nb_subtract*/
   0, /*nb_multiply*/
@@ -6502,11 +10125,11 @@ static PyNumberMethods __pyx_tp_as_number_Lattice = {
   #endif
 };
 
-static PySequenceMethods __pyx_tp_as_sequence_Lattice = {
-  __pyx_pw_5_cdec_7Lattice_7__len__, /*sq_length*/
+static PySequenceMethods __pyx_tp_as_sequence___pyx_scope_struct_1___iter__ = {
+  0, /*sq_length*/
   0, /*sq_concat*/
   0, /*sq_repeat*/
-  __pyx_sq_item_5_cdec_Lattice, /*sq_item*/
+  0, /*sq_item*/
   0, /*sq_slice*/
   0, /*sq_ass_item*/
   0, /*sq_ass_slice*/
@@ -6515,13 +10138,13 @@ static PySequenceMethods __pyx_tp_as_sequence_Lattice = {
   0, /*sq_inplace_repeat*/
 };
 
-static PyMappingMethods __pyx_tp_as_mapping_Lattice = {
-  __pyx_pw_5_cdec_7Lattice_7__len__, /*mp_length*/
-  __pyx_pw_5_cdec_7Lattice_3__getitem__, /*mp_subscript*/
-  __pyx_mp_ass_subscript_5_cdec_Lattice, /*mp_ass_subscript*/
+static PyMappingMethods __pyx_tp_as_mapping___pyx_scope_struct_1___iter__ = {
+  0, /*mp_length*/
+  0, /*mp_subscript*/
+  0, /*mp_ass_subscript*/
 };
 
-static PyBufferProcs __pyx_tp_as_buffer_Lattice = {
+static PyBufferProcs __pyx_tp_as_buffer___pyx_scope_struct_1___iter__ = {
   #if PY_MAJOR_VERSION < 3
   0, /*bf_getreadbuffer*/
   #endif
@@ -6542,12 +10165,12 @@ static PyBufferProcs __pyx_tp_as_buffer_Lattice = {
   #endif
 };
 
-static PyTypeObject __pyx_type_5_cdec_Lattice = {
+static PyTypeObject __pyx_type_5_cdec___pyx_scope_struct_1___iter__ = {
   PyVarObject_HEAD_INIT(0, 0)
-  __Pyx_NAMESTR("_cdec.Lattice"), /*tp_name*/
-  sizeof(struct __pyx_obj_5_cdec_Lattice), /*tp_basicsize*/
+  __Pyx_NAMESTR("_cdec.__pyx_scope_struct_1___iter__"), /*tp_name*/
+  sizeof(struct __pyx_obj_5_cdec___pyx_scope_struct_1___iter__), /*tp_basicsize*/
   0, /*tp_itemsize*/
-  __pyx_tp_dealloc_5_cdec_Lattice, /*tp_dealloc*/
+  __pyx_tp_dealloc_5_cdec___pyx_scope_struct_1___iter__, /*tp_dealloc*/
   0, /*tp_print*/
   0, /*tp_getattr*/
   0, /*tp_setattr*/
@@ -6557,24 +10180,24 @@ static PyTypeObject __pyx_type_5_cdec_Lattice = {
   0, /*reserved*/
   #endif
   0, /*tp_repr*/
-  &__pyx_tp_as_number_Lattice, /*tp_as_number*/
-  &__pyx_tp_as_sequence_Lattice, /*tp_as_sequence*/
-  &__pyx_tp_as_mapping_Lattice, /*tp_as_mapping*/
+  &__pyx_tp_as_number___pyx_scope_struct_1___iter__, /*tp_as_number*/
+  &__pyx_tp_as_sequence___pyx_scope_struct_1___iter__, /*tp_as_sequence*/
+  &__pyx_tp_as_mapping___pyx_scope_struct_1___iter__, /*tp_as_mapping*/
   0, /*tp_hash*/
   0, /*tp_call*/
-  __pyx_pw_5_cdec_7Lattice_9__str__, /*tp_str*/
+  0, /*tp_str*/
   0, /*tp_getattro*/
   0, /*tp_setattro*/
-  &__pyx_tp_as_buffer_Lattice, /*tp_as_buffer*/
-  Py_TPFLAGS_DEFAULT|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_BASETYPE, /*tp_flags*/
+  &__pyx_tp_as_buffer___pyx_scope_struct_1___iter__, /*tp_as_buffer*/
+  Py_TPFLAGS_DEFAULT|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_HAVE_GC, /*tp_flags*/
   0, /*tp_doc*/
-  0, /*tp_traverse*/
-  0, /*tp_clear*/
+  __pyx_tp_traverse_5_cdec___pyx_scope_struct_1___iter__, /*tp_traverse*/
+  __pyx_tp_clear_5_cdec___pyx_scope_struct_1___iter__, /*tp_clear*/
   0, /*tp_richcompare*/
   0, /*tp_weaklistoffset*/
-  __pyx_pw_5_cdec_7Lattice_11__iter__, /*tp_iter*/
+  0, /*tp_iter*/
   0, /*tp_iternext*/
-  __pyx_methods_5_cdec_Lattice, /*tp_methods*/
+  __pyx_methods_5_cdec___pyx_scope_struct_1___iter__, /*tp_methods*/
   0, /*tp_members*/
   0, /*tp_getset*/
   0, /*tp_base*/
@@ -6582,9 +10205,9 @@ static PyTypeObject __pyx_type_5_cdec_Lattice = {
   0, /*tp_descr_get*/
   0, /*tp_descr_set*/
   0, /*tp_dictoffset*/
-  __pyx_pw_5_cdec_7Lattice_1__init__, /*tp_init*/
+  0, /*tp_init*/
   0, /*tp_alloc*/
-  __pyx_tp_new_5_cdec_Lattice, /*tp_new*/
+  __pyx_tp_new_5_cdec___pyx_scope_struct_1___iter__, /*tp_new*/
   0, /*tp_free*/
   0, /*tp_is_gc*/
   0, /*tp_bases*/
@@ -6598,76 +10221,60 @@ static PyTypeObject __pyx_type_5_cdec_Lattice = {
   #endif
 };
 
-static PyObject *__pyx_tp_new_5_cdec_Decoder(PyTypeObject *t, PyObject *a, PyObject *k) {
-  struct __pyx_obj_5_cdec_Decoder *p;
+static PyObject *__pyx_tp_new_5_cdec___pyx_scope_struct_2_kbest(PyTypeObject *t, PyObject *a, PyObject *k) {
+  struct __pyx_obj_5_cdec___pyx_scope_struct_2_kbest *p;
   PyObject *o = (*t->tp_alloc)(t, 0);
   if (!o) return 0;
-  p = ((struct __pyx_obj_5_cdec_Decoder *)o);
-  p->weights = ((struct __pyx_obj_5_cdec_DenseVector *)Py_None); Py_INCREF(Py_None);
-  if (__pyx_pw_5_cdec_7Decoder_1__cinit__(o, a, k) < 0) {
-    Py_DECREF(o); o = 0;
-  }
+  p = ((struct __pyx_obj_5_cdec___pyx_scope_struct_2_kbest *)o);
+  p->__pyx_v_self = 0;
+  p->__pyx_v_sentence = 0;
+  p->__pyx_v_size = 0;
   return o;
 }
 
-static void __pyx_tp_dealloc_5_cdec_Decoder(PyObject *o) {
-  struct __pyx_obj_5_cdec_Decoder *p = (struct __pyx_obj_5_cdec_Decoder *)o;
-  {
-    PyObject *etype, *eval, *etb;
-    PyErr_Fetch(&etype, &eval, &etb);
-    ++Py_REFCNT(o);
-    __pyx_pw_5_cdec_7Decoder_3__dealloc__(o);
-    if (PyErr_Occurred()) PyErr_WriteUnraisable(o);
-    --Py_REFCNT(o);
-    PyErr_Restore(etype, eval, etb);
-  }
-  Py_XDECREF(((PyObject *)p->weights));
+static void __pyx_tp_dealloc_5_cdec___pyx_scope_struct_2_kbest(PyObject *o) {
+  struct __pyx_obj_5_cdec___pyx_scope_struct_2_kbest *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_2_kbest *)o;
+  Py_XDECREF(((PyObject *)p->__pyx_v_self));
+  Py_XDECREF(((PyObject *)p->__pyx_v_sentence));
+  Py_XDECREF(p->__pyx_v_size);
   (*Py_TYPE(o)->tp_free)(o);
 }
 
-static int __pyx_tp_traverse_5_cdec_Decoder(PyObject *o, visitproc v, void *a) {
+static int __pyx_tp_traverse_5_cdec___pyx_scope_struct_2_kbest(PyObject *o, visitproc v, void *a) {
   int e;
-  struct __pyx_obj_5_cdec_Decoder *p = (struct __pyx_obj_5_cdec_Decoder *)o;
-  if (p->weights) {
-    e = (*v)(((PyObject*)p->weights), a); if (e) return e;
+  struct __pyx_obj_5_cdec___pyx_scope_struct_2_kbest *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_2_kbest *)o;
+  if (p->__pyx_v_self) {
+    e = (*v)(((PyObject*)p->__pyx_v_self), a); if (e) return e;
+  }
+  if (p->__pyx_v_sentence) {
+    e = (*v)(p->__pyx_v_sentence, a); if (e) return e;
+  }
+  if (p->__pyx_v_size) {
+    e = (*v)(p->__pyx_v_size, a); if (e) return e;
   }
   return 0;
 }
 
-static int __pyx_tp_clear_5_cdec_Decoder(PyObject *o) {
-  struct __pyx_obj_5_cdec_Decoder *p = (struct __pyx_obj_5_cdec_Decoder *)o;
+static int __pyx_tp_clear_5_cdec___pyx_scope_struct_2_kbest(PyObject *o) {
+  struct __pyx_obj_5_cdec___pyx_scope_struct_2_kbest *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_2_kbest *)o;
   PyObject* tmp;
-  tmp = ((PyObject*)p->weights);
-  p->weights = ((struct __pyx_obj_5_cdec_DenseVector *)Py_None); Py_INCREF(Py_None);
+  tmp = ((PyObject*)p->__pyx_v_self);
+  p->__pyx_v_self = ((struct __pyx_obj_5_cdec_Hypergraph *)Py_None); Py_INCREF(Py_None);
+  Py_XDECREF(tmp);
+  tmp = ((PyObject*)p->__pyx_v_sentence);
+  p->__pyx_v_sentence = ((PyObject*)Py_None); Py_INCREF(Py_None);
+  Py_XDECREF(tmp);
+  tmp = ((PyObject*)p->__pyx_v_size);
+  p->__pyx_v_size = Py_None; Py_INCREF(Py_None);
   Py_XDECREF(tmp);
   return 0;
 }
 
-static PyObject *__pyx_getprop_5_cdec_7Decoder_weights(PyObject *o, void *x) {
-  return __pyx_pw_5_cdec_7Decoder_7weights_1__get__(o);
-}
-
-static int __pyx_setprop_5_cdec_7Decoder_weights(PyObject *o, PyObject *v, void *x) {
-  if (v) {
-    return __pyx_pw_5_cdec_7Decoder_7weights_3__set__(o, v);
-  }
-  else {
-    return __pyx_pw_5_cdec_7Decoder_7weights_5__del__(o);
-  }
-}
-
-static PyMethodDef __pyx_methods_5_cdec_Decoder[] = {
-  {__Pyx_NAMESTR("read_weights"), (PyCFunction)__pyx_pw_5_cdec_7Decoder_5read_weights, METH_O, __Pyx_DOCSTR(0)},
-  {__Pyx_NAMESTR("translate"), (PyCFunction)__pyx_pw_5_cdec_7Decoder_7translate, METH_VARARGS|METH_KEYWORDS, __Pyx_DOCSTR(0)},
+static PyMethodDef __pyx_methods_5_cdec___pyx_scope_struct_2_kbest[] = {
   {0, 0, 0, 0}
 };
 
-static struct PyGetSetDef __pyx_getsets_5_cdec_Decoder[] = {
-  {(char *)"weights", __pyx_getprop_5_cdec_7Decoder_weights, __pyx_setprop_5_cdec_7Decoder_weights, 0, 0},
-  {0, 0, 0, 0, 0}
-};
-
-static PyNumberMethods __pyx_tp_as_number_Decoder = {
+static PyNumberMethods __pyx_tp_as_number___pyx_scope_struct_2_kbest = {
   0, /*nb_add*/
   0, /*nb_subtract*/
   0, /*nb_multiply*/
@@ -6725,7 +10332,7 @@ static PyNumberMethods __pyx_tp_as_number_Decoder = {
   #endif
 };
 
-static PySequenceMethods __pyx_tp_as_sequence_Decoder = {
+static PySequenceMethods __pyx_tp_as_sequence___pyx_scope_struct_2_kbest = {
   0, /*sq_length*/
   0, /*sq_concat*/
   0, /*sq_repeat*/
@@ -6738,13 +10345,13 @@ static PySequenceMethods __pyx_tp_as_sequence_Decoder = {
   0, /*sq_inplace_repeat*/
 };
 
-static PyMappingMethods __pyx_tp_as_mapping_Decoder = {
+static PyMappingMethods __pyx_tp_as_mapping___pyx_scope_struct_2_kbest = {
   0, /*mp_length*/
   0, /*mp_subscript*/
   0, /*mp_ass_subscript*/
 };
 
-static PyBufferProcs __pyx_tp_as_buffer_Decoder = {
+static PyBufferProcs __pyx_tp_as_buffer___pyx_scope_struct_2_kbest = {
   #if PY_MAJOR_VERSION < 3
   0, /*bf_getreadbuffer*/
   #endif
@@ -6765,12 +10372,12 @@ static PyBufferProcs __pyx_tp_as_buffer_Decoder = {
   #endif
 };
 
-static PyTypeObject __pyx_type_5_cdec_Decoder = {
+static PyTypeObject __pyx_type_5_cdec___pyx_scope_struct_2_kbest = {
   PyVarObject_HEAD_INIT(0, 0)
-  __Pyx_NAMESTR("_cdec.Decoder"), /*tp_name*/
-  sizeof(struct __pyx_obj_5_cdec_Decoder), /*tp_basicsize*/
+  __Pyx_NAMESTR("_cdec.__pyx_scope_struct_2_kbest"), /*tp_name*/
+  sizeof(struct __pyx_obj_5_cdec___pyx_scope_struct_2_kbest), /*tp_basicsize*/
   0, /*tp_itemsize*/
-  __pyx_tp_dealloc_5_cdec_Decoder, /*tp_dealloc*/
+  __pyx_tp_dealloc_5_cdec___pyx_scope_struct_2_kbest, /*tp_dealloc*/
   0, /*tp_print*/
   0, /*tp_getattr*/
   0, /*tp_setattr*/
@@ -6780,26 +10387,26 @@ static PyTypeObject __pyx_type_5_cdec_Decoder = {
   0, /*reserved*/
   #endif
   0, /*tp_repr*/
-  &__pyx_tp_as_number_Decoder, /*tp_as_number*/
-  &__pyx_tp_as_sequence_Decoder, /*tp_as_sequence*/
-  &__pyx_tp_as_mapping_Decoder, /*tp_as_mapping*/
+  &__pyx_tp_as_number___pyx_scope_struct_2_kbest, /*tp_as_number*/
+  &__pyx_tp_as_sequence___pyx_scope_struct_2_kbest, /*tp_as_sequence*/
+  &__pyx_tp_as_mapping___pyx_scope_struct_2_kbest, /*tp_as_mapping*/
   0, /*tp_hash*/
   0, /*tp_call*/
   0, /*tp_str*/
   0, /*tp_getattro*/
   0, /*tp_setattro*/
-  &__pyx_tp_as_buffer_Decoder, /*tp_as_buffer*/
-  Py_TPFLAGS_DEFAULT|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_HAVE_GC, /*tp_flags*/
+  &__pyx_tp_as_buffer___pyx_scope_struct_2_kbest, /*tp_as_buffer*/
+  Py_TPFLAGS_DEFAULT|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_HAVE_GC, /*tp_flags*/
   0, /*tp_doc*/
-  __pyx_tp_traverse_5_cdec_Decoder, /*tp_traverse*/
-  __pyx_tp_clear_5_cdec_Decoder, /*tp_clear*/
+  __pyx_tp_traverse_5_cdec___pyx_scope_struct_2_kbest, /*tp_traverse*/
+  __pyx_tp_clear_5_cdec___pyx_scope_struct_2_kbest, /*tp_clear*/
   0, /*tp_richcompare*/
   0, /*tp_weaklistoffset*/
   0, /*tp_iter*/
   0, /*tp_iternext*/
-  __pyx_methods_5_cdec_Decoder, /*tp_methods*/
+  __pyx_methods_5_cdec___pyx_scope_struct_2_kbest, /*tp_methods*/
   0, /*tp_members*/
-  __pyx_getsets_5_cdec_Decoder, /*tp_getset*/
+  0, /*tp_getset*/
   0, /*tp_base*/
   0, /*tp_dict*/
   0, /*tp_descr_get*/
@@ -6807,7 +10414,7 @@ static PyTypeObject __pyx_type_5_cdec_Decoder = {
   0, /*tp_dictoffset*/
   0, /*tp_init*/
   0, /*tp_alloc*/
-  __pyx_tp_new_5_cdec_Decoder, /*tp_new*/
+  __pyx_tp_new_5_cdec___pyx_scope_struct_2_kbest, /*tp_new*/
   0, /*tp_free*/
   0, /*tp_is_gc*/
   0, /*tp_bases*/
@@ -6821,44 +10428,60 @@ static PyTypeObject __pyx_type_5_cdec_Decoder = {
   #endif
 };
 
-static PyObject *__pyx_tp_new_5_cdec___pyx_scope_struct____iter__(PyTypeObject *t, PyObject *a, PyObject *k) {
-  struct __pyx_obj_5_cdec___pyx_scope_struct____iter__ *p;
+static PyObject *__pyx_tp_new_5_cdec___pyx_scope_struct_3_kbest_tree(PyTypeObject *t, PyObject *a, PyObject *k) {
+  struct __pyx_obj_5_cdec___pyx_scope_struct_3_kbest_tree *p;
   PyObject *o = (*t->tp_alloc)(t, 0);
   if (!o) return 0;
-  p = ((struct __pyx_obj_5_cdec___pyx_scope_struct____iter__ *)o);
+  p = ((struct __pyx_obj_5_cdec___pyx_scope_struct_3_kbest_tree *)o);
   p->__pyx_v_self = 0;
+  p->__pyx_v_size = 0;
+  p->__pyx_v_tree = 0;
   return o;
 }
 
-static void __pyx_tp_dealloc_5_cdec___pyx_scope_struct____iter__(PyObject *o) {
-  struct __pyx_obj_5_cdec___pyx_scope_struct____iter__ *p = (struct __pyx_obj_5_cdec___pyx_scope_struct____iter__ *)o;
+static void __pyx_tp_dealloc_5_cdec___pyx_scope_struct_3_kbest_tree(PyObject *o) {
+  struct __pyx_obj_5_cdec___pyx_scope_struct_3_kbest_tree *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_3_kbest_tree *)o;
   Py_XDECREF(((PyObject *)p->__pyx_v_self));
+  Py_XDECREF(p->__pyx_v_size);
+  Py_XDECREF(((PyObject *)p->__pyx_v_tree));
   (*Py_TYPE(o)->tp_free)(o);
 }
 
-static int __pyx_tp_traverse_5_cdec___pyx_scope_struct____iter__(PyObject *o, visitproc v, void *a) {
+static int __pyx_tp_traverse_5_cdec___pyx_scope_struct_3_kbest_tree(PyObject *o, visitproc v, void *a) {
   int e;
-  struct __pyx_obj_5_cdec___pyx_scope_struct____iter__ *p = (struct __pyx_obj_5_cdec___pyx_scope_struct____iter__ *)o;
+  struct __pyx_obj_5_cdec___pyx_scope_struct_3_kbest_tree *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_3_kbest_tree *)o;
   if (p->__pyx_v_self) {
     e = (*v)(((PyObject*)p->__pyx_v_self), a); if (e) return e;
   }
+  if (p->__pyx_v_size) {
+    e = (*v)(p->__pyx_v_size, a); if (e) return e;
+  }
+  if (p->__pyx_v_tree) {
+    e = (*v)(p->__pyx_v_tree, a); if (e) return e;
+  }
   return 0;
 }
 
-static int __pyx_tp_clear_5_cdec___pyx_scope_struct____iter__(PyObject *o) {
-  struct __pyx_obj_5_cdec___pyx_scope_struct____iter__ *p = (struct __pyx_obj_5_cdec___pyx_scope_struct____iter__ *)o;
+static int __pyx_tp_clear_5_cdec___pyx_scope_struct_3_kbest_tree(PyObject *o) {
+  struct __pyx_obj_5_cdec___pyx_scope_struct_3_kbest_tree *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_3_kbest_tree *)o;
   PyObject* tmp;
   tmp = ((PyObject*)p->__pyx_v_self);
-  p->__pyx_v_self = ((struct __pyx_obj_5_cdec_DenseVector *)Py_None); Py_INCREF(Py_None);
+  p->__pyx_v_self = ((struct __pyx_obj_5_cdec_Hypergraph *)Py_None); Py_INCREF(Py_None);
+  Py_XDECREF(tmp);
+  tmp = ((PyObject*)p->__pyx_v_size);
+  p->__pyx_v_size = Py_None; Py_INCREF(Py_None);
+  Py_XDECREF(tmp);
+  tmp = ((PyObject*)p->__pyx_v_tree);
+  p->__pyx_v_tree = ((PyObject*)Py_None); Py_INCREF(Py_None);
   Py_XDECREF(tmp);
   return 0;
 }
 
-static PyMethodDef __pyx_methods_5_cdec___pyx_scope_struct____iter__[] = {
+static PyMethodDef __pyx_methods_5_cdec___pyx_scope_struct_3_kbest_tree[] = {
   {0, 0, 0, 0}
 };
 
-static PyNumberMethods __pyx_tp_as_number___pyx_scope_struct____iter__ = {
+static PyNumberMethods __pyx_tp_as_number___pyx_scope_struct_3_kbest_tree = {
   0, /*nb_add*/
   0, /*nb_subtract*/
   0, /*nb_multiply*/
@@ -6916,7 +10539,7 @@ static PyNumberMethods __pyx_tp_as_number___pyx_scope_struct____iter__ = {
   #endif
 };
 
-static PySequenceMethods __pyx_tp_as_sequence___pyx_scope_struct____iter__ = {
+static PySequenceMethods __pyx_tp_as_sequence___pyx_scope_struct_3_kbest_tree = {
   0, /*sq_length*/
   0, /*sq_concat*/
   0, /*sq_repeat*/
@@ -6929,13 +10552,13 @@ static PySequenceMethods __pyx_tp_as_sequence___pyx_scope_struct____iter__ = {
   0, /*sq_inplace_repeat*/
 };
 
-static PyMappingMethods __pyx_tp_as_mapping___pyx_scope_struct____iter__ = {
+static PyMappingMethods __pyx_tp_as_mapping___pyx_scope_struct_3_kbest_tree = {
   0, /*mp_length*/
   0, /*mp_subscript*/
   0, /*mp_ass_subscript*/
 };
 
-static PyBufferProcs __pyx_tp_as_buffer___pyx_scope_struct____iter__ = {
+static PyBufferProcs __pyx_tp_as_buffer___pyx_scope_struct_3_kbest_tree = {
   #if PY_MAJOR_VERSION < 3
   0, /*bf_getreadbuffer*/
   #endif
@@ -6956,12 +10579,12 @@ static PyBufferProcs __pyx_tp_as_buffer___pyx_scope_struct____iter__ = {
   #endif
 };
 
-static PyTypeObject __pyx_type_5_cdec___pyx_scope_struct____iter__ = {
+static PyTypeObject __pyx_type_5_cdec___pyx_scope_struct_3_kbest_tree = {
   PyVarObject_HEAD_INIT(0, 0)
-  __Pyx_NAMESTR("_cdec.__pyx_scope_struct____iter__"), /*tp_name*/
-  sizeof(struct __pyx_obj_5_cdec___pyx_scope_struct____iter__), /*tp_basicsize*/
+  __Pyx_NAMESTR("_cdec.__pyx_scope_struct_3_kbest_tree"), /*tp_name*/
+  sizeof(struct __pyx_obj_5_cdec___pyx_scope_struct_3_kbest_tree), /*tp_basicsize*/
   0, /*tp_itemsize*/
-  __pyx_tp_dealloc_5_cdec___pyx_scope_struct____iter__, /*tp_dealloc*/
+  __pyx_tp_dealloc_5_cdec___pyx_scope_struct_3_kbest_tree, /*tp_dealloc*/
   0, /*tp_print*/
   0, /*tp_getattr*/
   0, /*tp_setattr*/
@@ -6971,24 +10594,24 @@ static PyTypeObject __pyx_type_5_cdec___pyx_scope_struct____iter__ = {
   0, /*reserved*/
   #endif
   0, /*tp_repr*/
-  &__pyx_tp_as_number___pyx_scope_struct____iter__, /*tp_as_number*/
-  &__pyx_tp_as_sequence___pyx_scope_struct____iter__, /*tp_as_sequence*/
-  &__pyx_tp_as_mapping___pyx_scope_struct____iter__, /*tp_as_mapping*/
+  &__pyx_tp_as_number___pyx_scope_struct_3_kbest_tree, /*tp_as_number*/
+  &__pyx_tp_as_sequence___pyx_scope_struct_3_kbest_tree, /*tp_as_sequence*/
+  &__pyx_tp_as_mapping___pyx_scope_struct_3_kbest_tree, /*tp_as_mapping*/
   0, /*tp_hash*/
   0, /*tp_call*/
   0, /*tp_str*/
   0, /*tp_getattro*/
   0, /*tp_setattro*/
-  &__pyx_tp_as_buffer___pyx_scope_struct____iter__, /*tp_as_buffer*/
+  &__pyx_tp_as_buffer___pyx_scope_struct_3_kbest_tree, /*tp_as_buffer*/
   Py_TPFLAGS_DEFAULT|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_HAVE_GC, /*tp_flags*/
   0, /*tp_doc*/
-  __pyx_tp_traverse_5_cdec___pyx_scope_struct____iter__, /*tp_traverse*/
-  __pyx_tp_clear_5_cdec___pyx_scope_struct____iter__, /*tp_clear*/
+  __pyx_tp_traverse_5_cdec___pyx_scope_struct_3_kbest_tree, /*tp_traverse*/
+  __pyx_tp_clear_5_cdec___pyx_scope_struct_3_kbest_tree, /*tp_clear*/
   0, /*tp_richcompare*/
   0, /*tp_weaklistoffset*/
   0, /*tp_iter*/
   0, /*tp_iternext*/
-  __pyx_methods_5_cdec___pyx_scope_struct____iter__, /*tp_methods*/
+  __pyx_methods_5_cdec___pyx_scope_struct_3_kbest_tree, /*tp_methods*/
   0, /*tp_members*/
   0, /*tp_getset*/
   0, /*tp_base*/
@@ -6998,7 +10621,7 @@ static PyTypeObject __pyx_type_5_cdec___pyx_scope_struct____iter__ = {
   0, /*tp_dictoffset*/
   0, /*tp_init*/
   0, /*tp_alloc*/
-  __pyx_tp_new_5_cdec___pyx_scope_struct____iter__, /*tp_new*/
+  __pyx_tp_new_5_cdec___pyx_scope_struct_3_kbest_tree, /*tp_new*/
   0, /*tp_free*/
   0, /*tp_is_gc*/
   0, /*tp_bases*/
@@ -7012,52 +10635,60 @@ static PyTypeObject __pyx_type_5_cdec___pyx_scope_struct____iter__ = {
   #endif
 };
 
-static PyObject *__pyx_tp_new_5_cdec___pyx_scope_struct_1___iter__(PyTypeObject *t, PyObject *a, PyObject *k) {
-  struct __pyx_obj_5_cdec___pyx_scope_struct_1___iter__ *p;
+static PyObject *__pyx_tp_new_5_cdec___pyx_scope_struct_4_kbest_features(PyTypeObject *t, PyObject *a, PyObject *k) {
+  struct __pyx_obj_5_cdec___pyx_scope_struct_4_kbest_features *p;
   PyObject *o = (*t->tp_alloc)(t, 0);
   if (!o) return 0;
-  p = ((struct __pyx_obj_5_cdec___pyx_scope_struct_1___iter__ *)o);
-  p->__pyx_v_fname = 0;
+  p = ((struct __pyx_obj_5_cdec___pyx_scope_struct_4_kbest_features *)o);
+  p->__pyx_v_fmap = 0;
   p->__pyx_v_self = 0;
+  p->__pyx_v_size = 0;
   return o;
 }
 
-static void __pyx_tp_dealloc_5_cdec___pyx_scope_struct_1___iter__(PyObject *o) {
-  struct __pyx_obj_5_cdec___pyx_scope_struct_1___iter__ *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_1___iter__ *)o;
-  Py_XDECREF(((PyObject *)p->__pyx_v_fname));
+static void __pyx_tp_dealloc_5_cdec___pyx_scope_struct_4_kbest_features(PyObject *o) {
+  struct __pyx_obj_5_cdec___pyx_scope_struct_4_kbest_features *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_4_kbest_features *)o;
+  Py_XDECREF(((PyObject *)p->__pyx_v_fmap));
   Py_XDECREF(((PyObject *)p->__pyx_v_self));
+  Py_XDECREF(p->__pyx_v_size);
   (*Py_TYPE(o)->tp_free)(o);
 }
 
-static int __pyx_tp_traverse_5_cdec___pyx_scope_struct_1___iter__(PyObject *o, visitproc v, void *a) {
+static int __pyx_tp_traverse_5_cdec___pyx_scope_struct_4_kbest_features(PyObject *o, visitproc v, void *a) {
   int e;
-  struct __pyx_obj_5_cdec___pyx_scope_struct_1___iter__ *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_1___iter__ *)o;
-  if (p->__pyx_v_fname) {
-    e = (*v)(p->__pyx_v_fname, a); if (e) return e;
+  struct __pyx_obj_5_cdec___pyx_scope_struct_4_kbest_features *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_4_kbest_features *)o;
+  if (p->__pyx_v_fmap) {
+    e = (*v)(((PyObject*)p->__pyx_v_fmap), a); if (e) return e;
   }
   if (p->__pyx_v_self) {
     e = (*v)(((PyObject*)p->__pyx_v_self), a); if (e) return e;
   }
+  if (p->__pyx_v_size) {
+    e = (*v)(p->__pyx_v_size, a); if (e) return e;
+  }
   return 0;
 }
 
-static int __pyx_tp_clear_5_cdec___pyx_scope_struct_1___iter__(PyObject *o) {
-  struct __pyx_obj_5_cdec___pyx_scope_struct_1___iter__ *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_1___iter__ *)o;
+static int __pyx_tp_clear_5_cdec___pyx_scope_struct_4_kbest_features(PyObject *o) {
+  struct __pyx_obj_5_cdec___pyx_scope_struct_4_kbest_features *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_4_kbest_features *)o;
   PyObject* tmp;
-  tmp = ((PyObject*)p->__pyx_v_fname);
-  p->__pyx_v_fname = ((PyObject*)Py_None); Py_INCREF(Py_None);
+  tmp = ((PyObject*)p->__pyx_v_fmap);
+  p->__pyx_v_fmap = ((struct __pyx_obj_5_cdec_SparseVector *)Py_None); Py_INCREF(Py_None);
   Py_XDECREF(tmp);
   tmp = ((PyObject*)p->__pyx_v_self);
-  p->__pyx_v_self = ((struct __pyx_obj_5_cdec_SparseVector *)Py_None); Py_INCREF(Py_None);
+  p->__pyx_v_self = ((struct __pyx_obj_5_cdec_Hypergraph *)Py_None); Py_INCREF(Py_None);
+  Py_XDECREF(tmp);
+  tmp = ((PyObject*)p->__pyx_v_size);
+  p->__pyx_v_size = Py_None; Py_INCREF(Py_None);
   Py_XDECREF(tmp);
   return 0;
 }
 
-static PyMethodDef __pyx_methods_5_cdec___pyx_scope_struct_1___iter__[] = {
+static PyMethodDef __pyx_methods_5_cdec___pyx_scope_struct_4_kbest_features[] = {
   {0, 0, 0, 0}
 };
 
-static PyNumberMethods __pyx_tp_as_number___pyx_scope_struct_1___iter__ = {
+static PyNumberMethods __pyx_tp_as_number___pyx_scope_struct_4_kbest_features = {
   0, /*nb_add*/
   0, /*nb_subtract*/
   0, /*nb_multiply*/
@@ -7115,7 +10746,7 @@ static PyNumberMethods __pyx_tp_as_number___pyx_scope_struct_1___iter__ = {
   #endif
 };
 
-static PySequenceMethods __pyx_tp_as_sequence___pyx_scope_struct_1___iter__ = {
+static PySequenceMethods __pyx_tp_as_sequence___pyx_scope_struct_4_kbest_features = {
   0, /*sq_length*/
   0, /*sq_concat*/
   0, /*sq_repeat*/
@@ -7128,13 +10759,13 @@ static PySequenceMethods __pyx_tp_as_sequence___pyx_scope_struct_1___iter__ = {
   0, /*sq_inplace_repeat*/
 };
 
-static PyMappingMethods __pyx_tp_as_mapping___pyx_scope_struct_1___iter__ = {
+static PyMappingMethods __pyx_tp_as_mapping___pyx_scope_struct_4_kbest_features = {
   0, /*mp_length*/
   0, /*mp_subscript*/
   0, /*mp_ass_subscript*/
 };
 
-static PyBufferProcs __pyx_tp_as_buffer___pyx_scope_struct_1___iter__ = {
+static PyBufferProcs __pyx_tp_as_buffer___pyx_scope_struct_4_kbest_features = {
   #if PY_MAJOR_VERSION < 3
   0, /*bf_getreadbuffer*/
   #endif
@@ -7155,12 +10786,12 @@ static PyBufferProcs __pyx_tp_as_buffer___pyx_scope_struct_1___iter__ = {
   #endif
 };
 
-static PyTypeObject __pyx_type_5_cdec___pyx_scope_struct_1___iter__ = {
+static PyTypeObject __pyx_type_5_cdec___pyx_scope_struct_4_kbest_features = {
   PyVarObject_HEAD_INIT(0, 0)
-  __Pyx_NAMESTR("_cdec.__pyx_scope_struct_1___iter__"), /*tp_name*/
-  sizeof(struct __pyx_obj_5_cdec___pyx_scope_struct_1___iter__), /*tp_basicsize*/
+  __Pyx_NAMESTR("_cdec.__pyx_scope_struct_4_kbest_features"), /*tp_name*/
+  sizeof(struct __pyx_obj_5_cdec___pyx_scope_struct_4_kbest_features), /*tp_basicsize*/
   0, /*tp_itemsize*/
-  __pyx_tp_dealloc_5_cdec___pyx_scope_struct_1___iter__, /*tp_dealloc*/
+  __pyx_tp_dealloc_5_cdec___pyx_scope_struct_4_kbest_features, /*tp_dealloc*/
   0, /*tp_print*/
   0, /*tp_getattr*/
   0, /*tp_setattr*/
@@ -7170,24 +10801,24 @@ static PyTypeObject __pyx_type_5_cdec___pyx_scope_struct_1___iter__ = {
   0, /*reserved*/
   #endif
   0, /*tp_repr*/
-  &__pyx_tp_as_number___pyx_scope_struct_1___iter__, /*tp_as_number*/
-  &__pyx_tp_as_sequence___pyx_scope_struct_1___iter__, /*tp_as_sequence*/
-  &__pyx_tp_as_mapping___pyx_scope_struct_1___iter__, /*tp_as_mapping*/
+  &__pyx_tp_as_number___pyx_scope_struct_4_kbest_features, /*tp_as_number*/
+  &__pyx_tp_as_sequence___pyx_scope_struct_4_kbest_features, /*tp_as_sequence*/
+  &__pyx_tp_as_mapping___pyx_scope_struct_4_kbest_features, /*tp_as_mapping*/
   0, /*tp_hash*/
   0, /*tp_call*/
   0, /*tp_str*/
   0, /*tp_getattro*/
   0, /*tp_setattro*/
-  &__pyx_tp_as_buffer___pyx_scope_struct_1___iter__, /*tp_as_buffer*/
+  &__pyx_tp_as_buffer___pyx_scope_struct_4_kbest_features, /*tp_as_buffer*/
   Py_TPFLAGS_DEFAULT|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_HAVE_GC, /*tp_flags*/
   0, /*tp_doc*/
-  __pyx_tp_traverse_5_cdec___pyx_scope_struct_1___iter__, /*tp_traverse*/
-  __pyx_tp_clear_5_cdec___pyx_scope_struct_1___iter__, /*tp_clear*/
+  __pyx_tp_traverse_5_cdec___pyx_scope_struct_4_kbest_features, /*tp_traverse*/
+  __pyx_tp_clear_5_cdec___pyx_scope_struct_4_kbest_features, /*tp_clear*/
   0, /*tp_richcompare*/
   0, /*tp_weaklistoffset*/
   0, /*tp_iter*/
   0, /*tp_iternext*/
-  __pyx_methods_5_cdec___pyx_scope_struct_1___iter__, /*tp_methods*/
+  __pyx_methods_5_cdec___pyx_scope_struct_4_kbest_features, /*tp_methods*/
   0, /*tp_members*/
   0, /*tp_getset*/
   0, /*tp_base*/
@@ -7197,7 +10828,7 @@ static PyTypeObject __pyx_type_5_cdec___pyx_scope_struct_1___iter__ = {
   0, /*tp_dictoffset*/
   0, /*tp_init*/
   0, /*tp_alloc*/
-  __pyx_tp_new_5_cdec___pyx_scope_struct_1___iter__, /*tp_new*/
+  __pyx_tp_new_5_cdec___pyx_scope_struct_4_kbest_features, /*tp_new*/
   0, /*tp_free*/
   0, /*tp_is_gc*/
   0, /*tp_bases*/
@@ -7211,42 +10842,37 @@ static PyTypeObject __pyx_type_5_cdec___pyx_scope_struct_1___iter__ = {
   #endif
 };
 
-static PyObject *__pyx_tp_new_5_cdec___pyx_scope_struct_2_kbest(PyTypeObject *t, PyObject *a, PyObject *k) {
-  struct __pyx_obj_5_cdec___pyx_scope_struct_2_kbest *p;
+static PyObject *__pyx_tp_new_5_cdec___pyx_scope_struct_5_sample(PyTypeObject *t, PyObject *a, PyObject *k) {
+  struct __pyx_obj_5_cdec___pyx_scope_struct_5_sample *p;
   PyObject *o = (*t->tp_alloc)(t, 0);
   if (!o) return 0;
-  p = ((struct __pyx_obj_5_cdec___pyx_scope_struct_2_kbest *)o);
+  p = ((struct __pyx_obj_5_cdec___pyx_scope_struct_5_sample *)o);
   p->__pyx_v_self = 0;
   p->__pyx_v_sentence = 0;
-  p->__pyx_v_size = 0;
   return o;
 }
 
-static void __pyx_tp_dealloc_5_cdec___pyx_scope_struct_2_kbest(PyObject *o) {
-  struct __pyx_obj_5_cdec___pyx_scope_struct_2_kbest *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_2_kbest *)o;
+static void __pyx_tp_dealloc_5_cdec___pyx_scope_struct_5_sample(PyObject *o) {
+  struct __pyx_obj_5_cdec___pyx_scope_struct_5_sample *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_5_sample *)o;
   Py_XDECREF(((PyObject *)p->__pyx_v_self));
   Py_XDECREF(((PyObject *)p->__pyx_v_sentence));
-  Py_XDECREF(p->__pyx_v_size);
   (*Py_TYPE(o)->tp_free)(o);
 }
 
-static int __pyx_tp_traverse_5_cdec___pyx_scope_struct_2_kbest(PyObject *o, visitproc v, void *a) {
+static int __pyx_tp_traverse_5_cdec___pyx_scope_struct_5_sample(PyObject *o, visitproc v, void *a) {
   int e;
-  struct __pyx_obj_5_cdec___pyx_scope_struct_2_kbest *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_2_kbest *)o;
+  struct __pyx_obj_5_cdec___pyx_scope_struct_5_sample *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_5_sample *)o;
   if (p->__pyx_v_self) {
     e = (*v)(((PyObject*)p->__pyx_v_self), a); if (e) return e;
   }
   if (p->__pyx_v_sentence) {
     e = (*v)(p->__pyx_v_sentence, a); if (e) return e;
   }
-  if (p->__pyx_v_size) {
-    e = (*v)(p->__pyx_v_size, a); if (e) return e;
-  }
   return 0;
 }
 
-static int __pyx_tp_clear_5_cdec___pyx_scope_struct_2_kbest(PyObject *o) {
-  struct __pyx_obj_5_cdec___pyx_scope_struct_2_kbest *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_2_kbest *)o;
+static int __pyx_tp_clear_5_cdec___pyx_scope_struct_5_sample(PyObject *o) {
+  struct __pyx_obj_5_cdec___pyx_scope_struct_5_sample *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_5_sample *)o;
   PyObject* tmp;
   tmp = ((PyObject*)p->__pyx_v_self);
   p->__pyx_v_self = ((struct __pyx_obj_5_cdec_Hypergraph *)Py_None); Py_INCREF(Py_None);
@@ -7254,17 +10880,14 @@ static int __pyx_tp_clear_5_cdec___pyx_scope_struct_2_kbest(PyObject *o) {
   tmp = ((PyObject*)p->__pyx_v_sentence);
   p->__pyx_v_sentence = ((PyObject*)Py_None); Py_INCREF(Py_None);
   Py_XDECREF(tmp);
-  tmp = ((PyObject*)p->__pyx_v_size);
-  p->__pyx_v_size = Py_None; Py_INCREF(Py_None);
-  Py_XDECREF(tmp);
   return 0;
 }
 
-static PyMethodDef __pyx_methods_5_cdec___pyx_scope_struct_2_kbest[] = {
+static PyMethodDef __pyx_methods_5_cdec___pyx_scope_struct_5_sample[] = {
   {0, 0, 0, 0}
 };
 
-static PyNumberMethods __pyx_tp_as_number___pyx_scope_struct_2_kbest = {
+static PyNumberMethods __pyx_tp_as_number___pyx_scope_struct_5_sample = {
   0, /*nb_add*/
   0, /*nb_subtract*/
   0, /*nb_multiply*/
@@ -7322,7 +10945,7 @@ static PyNumberMethods __pyx_tp_as_number___pyx_scope_struct_2_kbest = {
   #endif
 };
 
-static PySequenceMethods __pyx_tp_as_sequence___pyx_scope_struct_2_kbest = {
+static PySequenceMethods __pyx_tp_as_sequence___pyx_scope_struct_5_sample = {
   0, /*sq_length*/
   0, /*sq_concat*/
   0, /*sq_repeat*/
@@ -7335,13 +10958,13 @@ static PySequenceMethods __pyx_tp_as_sequence___pyx_scope_struct_2_kbest = {
   0, /*sq_inplace_repeat*/
 };
 
-static PyMappingMethods __pyx_tp_as_mapping___pyx_scope_struct_2_kbest = {
+static PyMappingMethods __pyx_tp_as_mapping___pyx_scope_struct_5_sample = {
   0, /*mp_length*/
   0, /*mp_subscript*/
   0, /*mp_ass_subscript*/
 };
 
-static PyBufferProcs __pyx_tp_as_buffer___pyx_scope_struct_2_kbest = {
+static PyBufferProcs __pyx_tp_as_buffer___pyx_scope_struct_5_sample = {
   #if PY_MAJOR_VERSION < 3
   0, /*bf_getreadbuffer*/
   #endif
@@ -7362,12 +10985,12 @@ static PyBufferProcs __pyx_tp_as_buffer___pyx_scope_struct_2_kbest = {
   #endif
 };
 
-static PyTypeObject __pyx_type_5_cdec___pyx_scope_struct_2_kbest = {
+static PyTypeObject __pyx_type_5_cdec___pyx_scope_struct_5_sample = {
   PyVarObject_HEAD_INIT(0, 0)
-  __Pyx_NAMESTR("_cdec.__pyx_scope_struct_2_kbest"), /*tp_name*/
-  sizeof(struct __pyx_obj_5_cdec___pyx_scope_struct_2_kbest), /*tp_basicsize*/
+  __Pyx_NAMESTR("_cdec.__pyx_scope_struct_5_sample"), /*tp_name*/
+  sizeof(struct __pyx_obj_5_cdec___pyx_scope_struct_5_sample), /*tp_basicsize*/
   0, /*tp_itemsize*/
-  __pyx_tp_dealloc_5_cdec___pyx_scope_struct_2_kbest, /*tp_dealloc*/
+  __pyx_tp_dealloc_5_cdec___pyx_scope_struct_5_sample, /*tp_dealloc*/
   0, /*tp_print*/
   0, /*tp_getattr*/
   0, /*tp_setattr*/
@@ -7377,24 +11000,24 @@ static PyTypeObject __pyx_type_5_cdec___pyx_scope_struct_2_kbest = {
   0, /*reserved*/
   #endif
   0, /*tp_repr*/
-  &__pyx_tp_as_number___pyx_scope_struct_2_kbest, /*tp_as_number*/
-  &__pyx_tp_as_sequence___pyx_scope_struct_2_kbest, /*tp_as_sequence*/
-  &__pyx_tp_as_mapping___pyx_scope_struct_2_kbest, /*tp_as_mapping*/
+  &__pyx_tp_as_number___pyx_scope_struct_5_sample, /*tp_as_number*/
+  &__pyx_tp_as_sequence___pyx_scope_struct_5_sample, /*tp_as_sequence*/
+  &__pyx_tp_as_mapping___pyx_scope_struct_5_sample, /*tp_as_mapping*/
   0, /*tp_hash*/
   0, /*tp_call*/
   0, /*tp_str*/
   0, /*tp_getattro*/
   0, /*tp_setattro*/
-  &__pyx_tp_as_buffer___pyx_scope_struct_2_kbest, /*tp_as_buffer*/
+  &__pyx_tp_as_buffer___pyx_scope_struct_5_sample, /*tp_as_buffer*/
   Py_TPFLAGS_DEFAULT|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_HAVE_GC, /*tp_flags*/
   0, /*tp_doc*/
-  __pyx_tp_traverse_5_cdec___pyx_scope_struct_2_kbest, /*tp_traverse*/
-  __pyx_tp_clear_5_cdec___pyx_scope_struct_2_kbest, /*tp_clear*/
+  __pyx_tp_traverse_5_cdec___pyx_scope_struct_5_sample, /*tp_traverse*/
+  __pyx_tp_clear_5_cdec___pyx_scope_struct_5_sample, /*tp_clear*/
   0, /*tp_richcompare*/
   0, /*tp_weaklistoffset*/
   0, /*tp_iter*/
   0, /*tp_iternext*/
-  __pyx_methods_5_cdec___pyx_scope_struct_2_kbest, /*tp_methods*/
+  __pyx_methods_5_cdec___pyx_scope_struct_5_sample, /*tp_methods*/
   0, /*tp_members*/
   0, /*tp_getset*/
   0, /*tp_base*/
@@ -7404,7 +11027,7 @@ static PyTypeObject __pyx_type_5_cdec___pyx_scope_struct_2_kbest = {
   0, /*tp_dictoffset*/
   0, /*tp_init*/
   0, /*tp_alloc*/
-  __pyx_tp_new_5_cdec___pyx_scope_struct_2_kbest, /*tp_new*/
+  __pyx_tp_new_5_cdec___pyx_scope_struct_5_sample, /*tp_new*/
   0, /*tp_free*/
   0, /*tp_is_gc*/
   0, /*tp_bases*/
@@ -7418,60 +11041,44 @@ static PyTypeObject __pyx_type_5_cdec___pyx_scope_struct_2_kbest = {
   #endif
 };
 
-static PyObject *__pyx_tp_new_5_cdec___pyx_scope_struct_3_kbest_tree(PyTypeObject *t, PyObject *a, PyObject *k) {
-  struct __pyx_obj_5_cdec___pyx_scope_struct_3_kbest_tree *p;
+static PyObject *__pyx_tp_new_5_cdec___pyx_scope_struct_6___iter__(PyTypeObject *t, PyObject *a, PyObject *k) {
+  struct __pyx_obj_5_cdec___pyx_scope_struct_6___iter__ *p;
   PyObject *o = (*t->tp_alloc)(t, 0);
   if (!o) return 0;
-  p = ((struct __pyx_obj_5_cdec___pyx_scope_struct_3_kbest_tree *)o);
+  p = ((struct __pyx_obj_5_cdec___pyx_scope_struct_6___iter__ *)o);
   p->__pyx_v_self = 0;
-  p->__pyx_v_size = 0;
-  p->__pyx_v_tree = 0;
   return o;
 }
 
-static void __pyx_tp_dealloc_5_cdec___pyx_scope_struct_3_kbest_tree(PyObject *o) {
-  struct __pyx_obj_5_cdec___pyx_scope_struct_3_kbest_tree *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_3_kbest_tree *)o;
+static void __pyx_tp_dealloc_5_cdec___pyx_scope_struct_6___iter__(PyObject *o) {
+  struct __pyx_obj_5_cdec___pyx_scope_struct_6___iter__ *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_6___iter__ *)o;
   Py_XDECREF(((PyObject *)p->__pyx_v_self));
-  Py_XDECREF(p->__pyx_v_size);
-  Py_XDECREF(((PyObject *)p->__pyx_v_tree));
   (*Py_TYPE(o)->tp_free)(o);
 }
 
-static int __pyx_tp_traverse_5_cdec___pyx_scope_struct_3_kbest_tree(PyObject *o, visitproc v, void *a) {
+static int __pyx_tp_traverse_5_cdec___pyx_scope_struct_6___iter__(PyObject *o, visitproc v, void *a) {
   int e;
-  struct __pyx_obj_5_cdec___pyx_scope_struct_3_kbest_tree *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_3_kbest_tree *)o;
+  struct __pyx_obj_5_cdec___pyx_scope_struct_6___iter__ *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_6___iter__ *)o;
   if (p->__pyx_v_self) {
     e = (*v)(((PyObject*)p->__pyx_v_self), a); if (e) return e;
   }
-  if (p->__pyx_v_size) {
-    e = (*v)(p->__pyx_v_size, a); if (e) return e;
-  }
-  if (p->__pyx_v_tree) {
-    e = (*v)(p->__pyx_v_tree, a); if (e) return e;
-  }
   return 0;
 }
 
-static int __pyx_tp_clear_5_cdec___pyx_scope_struct_3_kbest_tree(PyObject *o) {
-  struct __pyx_obj_5_cdec___pyx_scope_struct_3_kbest_tree *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_3_kbest_tree *)o;
+static int __pyx_tp_clear_5_cdec___pyx_scope_struct_6___iter__(PyObject *o) {
+  struct __pyx_obj_5_cdec___pyx_scope_struct_6___iter__ *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_6___iter__ *)o;
   PyObject* tmp;
   tmp = ((PyObject*)p->__pyx_v_self);
-  p->__pyx_v_self = ((struct __pyx_obj_5_cdec_Hypergraph *)Py_None); Py_INCREF(Py_None);
-  Py_XDECREF(tmp);
-  tmp = ((PyObject*)p->__pyx_v_size);
-  p->__pyx_v_size = Py_None; Py_INCREF(Py_None);
-  Py_XDECREF(tmp);
-  tmp = ((PyObject*)p->__pyx_v_tree);
-  p->__pyx_v_tree = ((PyObject*)Py_None); Py_INCREF(Py_None);
+  p->__pyx_v_self = ((struct __pyx_obj_5_cdec_Lattice *)Py_None); Py_INCREF(Py_None);
   Py_XDECREF(tmp);
   return 0;
 }
 
-static PyMethodDef __pyx_methods_5_cdec___pyx_scope_struct_3_kbest_tree[] = {
+static PyMethodDef __pyx_methods_5_cdec___pyx_scope_struct_6___iter__[] = {
   {0, 0, 0, 0}
 };
 
-static PyNumberMethods __pyx_tp_as_number___pyx_scope_struct_3_kbest_tree = {
+static PyNumberMethods __pyx_tp_as_number___pyx_scope_struct_6___iter__ = {
   0, /*nb_add*/
   0, /*nb_subtract*/
   0, /*nb_multiply*/
@@ -7529,7 +11136,7 @@ static PyNumberMethods __pyx_tp_as_number___pyx_scope_struct_3_kbest_tree = {
   #endif
 };
 
-static PySequenceMethods __pyx_tp_as_sequence___pyx_scope_struct_3_kbest_tree = {
+static PySequenceMethods __pyx_tp_as_sequence___pyx_scope_struct_6___iter__ = {
   0, /*sq_length*/
   0, /*sq_concat*/
   0, /*sq_repeat*/
@@ -7542,13 +11149,13 @@ static PySequenceMethods __pyx_tp_as_sequence___pyx_scope_struct_3_kbest_tree =
   0, /*sq_inplace_repeat*/
 };
 
-static PyMappingMethods __pyx_tp_as_mapping___pyx_scope_struct_3_kbest_tree = {
+static PyMappingMethods __pyx_tp_as_mapping___pyx_scope_struct_6___iter__ = {
   0, /*mp_length*/
   0, /*mp_subscript*/
   0, /*mp_ass_subscript*/
 };
 
-static PyBufferProcs __pyx_tp_as_buffer___pyx_scope_struct_3_kbest_tree = {
+static PyBufferProcs __pyx_tp_as_buffer___pyx_scope_struct_6___iter__ = {
   #if PY_MAJOR_VERSION < 3
   0, /*bf_getreadbuffer*/
   #endif
@@ -7569,12 +11176,12 @@ static PyBufferProcs __pyx_tp_as_buffer___pyx_scope_struct_3_kbest_tree = {
   #endif
 };
 
-static PyTypeObject __pyx_type_5_cdec___pyx_scope_struct_3_kbest_tree = {
+static PyTypeObject __pyx_type_5_cdec___pyx_scope_struct_6___iter__ = {
   PyVarObject_HEAD_INIT(0, 0)
-  __Pyx_NAMESTR("_cdec.__pyx_scope_struct_3_kbest_tree"), /*tp_name*/
-  sizeof(struct __pyx_obj_5_cdec___pyx_scope_struct_3_kbest_tree), /*tp_basicsize*/
+  __Pyx_NAMESTR("_cdec.__pyx_scope_struct_6___iter__"), /*tp_name*/
+  sizeof(struct __pyx_obj_5_cdec___pyx_scope_struct_6___iter__), /*tp_basicsize*/
   0, /*tp_itemsize*/
-  __pyx_tp_dealloc_5_cdec___pyx_scope_struct_3_kbest_tree, /*tp_dealloc*/
+  __pyx_tp_dealloc_5_cdec___pyx_scope_struct_6___iter__, /*tp_dealloc*/
   0, /*tp_print*/
   0, /*tp_getattr*/
   0, /*tp_setattr*/
@@ -7584,24 +11191,24 @@ static PyTypeObject __pyx_type_5_cdec___pyx_scope_struct_3_kbest_tree = {
   0, /*reserved*/
   #endif
   0, /*tp_repr*/
-  &__pyx_tp_as_number___pyx_scope_struct_3_kbest_tree, /*tp_as_number*/
-  &__pyx_tp_as_sequence___pyx_scope_struct_3_kbest_tree, /*tp_as_sequence*/
-  &__pyx_tp_as_mapping___pyx_scope_struct_3_kbest_tree, /*tp_as_mapping*/
+  &__pyx_tp_as_number___pyx_scope_struct_6___iter__, /*tp_as_number*/
+  &__pyx_tp_as_sequence___pyx_scope_struct_6___iter__, /*tp_as_sequence*/
+  &__pyx_tp_as_mapping___pyx_scope_struct_6___iter__, /*tp_as_mapping*/
   0, /*tp_hash*/
   0, /*tp_call*/
   0, /*tp_str*/
   0, /*tp_getattro*/
   0, /*tp_setattro*/
-  &__pyx_tp_as_buffer___pyx_scope_struct_3_kbest_tree, /*tp_as_buffer*/
+  &__pyx_tp_as_buffer___pyx_scope_struct_6___iter__, /*tp_as_buffer*/
   Py_TPFLAGS_DEFAULT|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_HAVE_GC, /*tp_flags*/
   0, /*tp_doc*/
-  __pyx_tp_traverse_5_cdec___pyx_scope_struct_3_kbest_tree, /*tp_traverse*/
-  __pyx_tp_clear_5_cdec___pyx_scope_struct_3_kbest_tree, /*tp_clear*/
+  __pyx_tp_traverse_5_cdec___pyx_scope_struct_6___iter__, /*tp_traverse*/
+  __pyx_tp_clear_5_cdec___pyx_scope_struct_6___iter__, /*tp_clear*/
   0, /*tp_richcompare*/
   0, /*tp_weaklistoffset*/
   0, /*tp_iter*/
   0, /*tp_iternext*/
-  __pyx_methods_5_cdec___pyx_scope_struct_3_kbest_tree, /*tp_methods*/
+  __pyx_methods_5_cdec___pyx_scope_struct_6___iter__, /*tp_methods*/
   0, /*tp_members*/
   0, /*tp_getset*/
   0, /*tp_base*/
@@ -7611,7 +11218,7 @@ static PyTypeObject __pyx_type_5_cdec___pyx_scope_struct_3_kbest_tree = {
   0, /*tp_dictoffset*/
   0, /*tp_init*/
   0, /*tp_alloc*/
-  __pyx_tp_new_5_cdec___pyx_scope_struct_3_kbest_tree, /*tp_new*/
+  __pyx_tp_new_5_cdec___pyx_scope_struct_6___iter__, /*tp_new*/
   0, /*tp_free*/
   0, /*tp_is_gc*/
   0, /*tp_bases*/
@@ -7625,52 +11232,60 @@ static PyTypeObject __pyx_type_5_cdec___pyx_scope_struct_3_kbest_tree = {
   #endif
 };
 
-static PyObject *__pyx_tp_new_5_cdec___pyx_scope_struct_4_sample(PyTypeObject *t, PyObject *a, PyObject *k) {
-  struct __pyx_obj_5_cdec___pyx_scope_struct_4_sample *p;
+static PyObject *__pyx_tp_new_5_cdec___pyx_scope_struct_7___iter__(PyTypeObject *t, PyObject *a, PyObject *k) {
+  struct __pyx_obj_5_cdec___pyx_scope_struct_7___iter__ *p;
   PyObject *o = (*t->tp_alloc)(t, 0);
   if (!o) return 0;
-  p = ((struct __pyx_obj_5_cdec___pyx_scope_struct_4_sample *)o);
+  p = ((struct __pyx_obj_5_cdec___pyx_scope_struct_7___iter__ *)o);
+  p->__pyx_v_i = 0;
   p->__pyx_v_self = 0;
-  p->__pyx_v_sentence = 0;
+  p->__pyx_t_1 = 0;
   return o;
 }
 
-static void __pyx_tp_dealloc_5_cdec___pyx_scope_struct_4_sample(PyObject *o) {
-  struct __pyx_obj_5_cdec___pyx_scope_struct_4_sample *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_4_sample *)o;
+static void __pyx_tp_dealloc_5_cdec___pyx_scope_struct_7___iter__(PyObject *o) {
+  struct __pyx_obj_5_cdec___pyx_scope_struct_7___iter__ *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_7___iter__ *)o;
+  Py_XDECREF(p->__pyx_v_i);
   Py_XDECREF(((PyObject *)p->__pyx_v_self));
-  Py_XDECREF(((PyObject *)p->__pyx_v_sentence));
+  Py_XDECREF(p->__pyx_t_1);
   (*Py_TYPE(o)->tp_free)(o);
 }
 
-static int __pyx_tp_traverse_5_cdec___pyx_scope_struct_4_sample(PyObject *o, visitproc v, void *a) {
+static int __pyx_tp_traverse_5_cdec___pyx_scope_struct_7___iter__(PyObject *o, visitproc v, void *a) {
   int e;
-  struct __pyx_obj_5_cdec___pyx_scope_struct_4_sample *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_4_sample *)o;
+  struct __pyx_obj_5_cdec___pyx_scope_struct_7___iter__ *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_7___iter__ *)o;
+  if (p->__pyx_v_i) {
+    e = (*v)(p->__pyx_v_i, a); if (e) return e;
+  }
   if (p->__pyx_v_self) {
     e = (*v)(((PyObject*)p->__pyx_v_self), a); if (e) return e;
   }
-  if (p->__pyx_v_sentence) {
-    e = (*v)(p->__pyx_v_sentence, a); if (e) return e;
+  if (p->__pyx_t_1) {
+    e = (*v)(p->__pyx_t_1, a); if (e) return e;
   }
   return 0;
 }
 
-static int __pyx_tp_clear_5_cdec___pyx_scope_struct_4_sample(PyObject *o) {
-  struct __pyx_obj_5_cdec___pyx_scope_struct_4_sample *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_4_sample *)o;
+static int __pyx_tp_clear_5_cdec___pyx_scope_struct_7___iter__(PyObject *o) {
+  struct __pyx_obj_5_cdec___pyx_scope_struct_7___iter__ *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_7___iter__ *)o;
   PyObject* tmp;
+  tmp = ((PyObject*)p->__pyx_v_i);
+  p->__pyx_v_i = Py_None; Py_INCREF(Py_None);
+  Py_XDECREF(tmp);
   tmp = ((PyObject*)p->__pyx_v_self);
-  p->__pyx_v_self = ((struct __pyx_obj_5_cdec_Hypergraph *)Py_None); Py_INCREF(Py_None);
+  p->__pyx_v_self = ((struct __pyx_obj_5_cdec_SufficientStats *)Py_None); Py_INCREF(Py_None);
   Py_XDECREF(tmp);
-  tmp = ((PyObject*)p->__pyx_v_sentence);
-  p->__pyx_v_sentence = ((PyObject*)Py_None); Py_INCREF(Py_None);
+  tmp = ((PyObject*)p->__pyx_t_1);
+  p->__pyx_t_1 = Py_None; Py_INCREF(Py_None);
   Py_XDECREF(tmp);
   return 0;
 }
 
-static PyMethodDef __pyx_methods_5_cdec___pyx_scope_struct_4_sample[] = {
+static PyMethodDef __pyx_methods_5_cdec___pyx_scope_struct_7___iter__[] = {
   {0, 0, 0, 0}
 };
 
-static PyNumberMethods __pyx_tp_as_number___pyx_scope_struct_4_sample = {
+static PyNumberMethods __pyx_tp_as_number___pyx_scope_struct_7___iter__ = {
   0, /*nb_add*/
   0, /*nb_subtract*/
   0, /*nb_multiply*/
@@ -7728,7 +11343,7 @@ static PyNumberMethods __pyx_tp_as_number___pyx_scope_struct_4_sample = {
   #endif
 };
 
-static PySequenceMethods __pyx_tp_as_sequence___pyx_scope_struct_4_sample = {
+static PySequenceMethods __pyx_tp_as_sequence___pyx_scope_struct_7___iter__ = {
   0, /*sq_length*/
   0, /*sq_concat*/
   0, /*sq_repeat*/
@@ -7741,13 +11356,13 @@ static PySequenceMethods __pyx_tp_as_sequence___pyx_scope_struct_4_sample = {
   0, /*sq_inplace_repeat*/
 };
 
-static PyMappingMethods __pyx_tp_as_mapping___pyx_scope_struct_4_sample = {
+static PyMappingMethods __pyx_tp_as_mapping___pyx_scope_struct_7___iter__ = {
   0, /*mp_length*/
   0, /*mp_subscript*/
   0, /*mp_ass_subscript*/
 };
 
-static PyBufferProcs __pyx_tp_as_buffer___pyx_scope_struct_4_sample = {
+static PyBufferProcs __pyx_tp_as_buffer___pyx_scope_struct_7___iter__ = {
   #if PY_MAJOR_VERSION < 3
   0, /*bf_getreadbuffer*/
   #endif
@@ -7768,12 +11383,12 @@ static PyBufferProcs __pyx_tp_as_buffer___pyx_scope_struct_4_sample = {
   #endif
 };
 
-static PyTypeObject __pyx_type_5_cdec___pyx_scope_struct_4_sample = {
+static PyTypeObject __pyx_type_5_cdec___pyx_scope_struct_7___iter__ = {
   PyVarObject_HEAD_INIT(0, 0)
-  __Pyx_NAMESTR("_cdec.__pyx_scope_struct_4_sample"), /*tp_name*/
-  sizeof(struct __pyx_obj_5_cdec___pyx_scope_struct_4_sample), /*tp_basicsize*/
+  __Pyx_NAMESTR("_cdec.__pyx_scope_struct_7___iter__"), /*tp_name*/
+  sizeof(struct __pyx_obj_5_cdec___pyx_scope_struct_7___iter__), /*tp_basicsize*/
   0, /*tp_itemsize*/
-  __pyx_tp_dealloc_5_cdec___pyx_scope_struct_4_sample, /*tp_dealloc*/
+  __pyx_tp_dealloc_5_cdec___pyx_scope_struct_7___iter__, /*tp_dealloc*/
   0, /*tp_print*/
   0, /*tp_getattr*/
   0, /*tp_setattr*/
@@ -7783,24 +11398,24 @@ static PyTypeObject __pyx_type_5_cdec___pyx_scope_struct_4_sample = {
   0, /*reserved*/
   #endif
   0, /*tp_repr*/
-  &__pyx_tp_as_number___pyx_scope_struct_4_sample, /*tp_as_number*/
-  &__pyx_tp_as_sequence___pyx_scope_struct_4_sample, /*tp_as_sequence*/
-  &__pyx_tp_as_mapping___pyx_scope_struct_4_sample, /*tp_as_mapping*/
+  &__pyx_tp_as_number___pyx_scope_struct_7___iter__, /*tp_as_number*/
+  &__pyx_tp_as_sequence___pyx_scope_struct_7___iter__, /*tp_as_sequence*/
+  &__pyx_tp_as_mapping___pyx_scope_struct_7___iter__, /*tp_as_mapping*/
   0, /*tp_hash*/
   0, /*tp_call*/
   0, /*tp_str*/
   0, /*tp_getattro*/
   0, /*tp_setattro*/
-  &__pyx_tp_as_buffer___pyx_scope_struct_4_sample, /*tp_as_buffer*/
+  &__pyx_tp_as_buffer___pyx_scope_struct_7___iter__, /*tp_as_buffer*/
   Py_TPFLAGS_DEFAULT|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_HAVE_GC, /*tp_flags*/
   0, /*tp_doc*/
-  __pyx_tp_traverse_5_cdec___pyx_scope_struct_4_sample, /*tp_traverse*/
-  __pyx_tp_clear_5_cdec___pyx_scope_struct_4_sample, /*tp_clear*/
+  __pyx_tp_traverse_5_cdec___pyx_scope_struct_7___iter__, /*tp_traverse*/
+  __pyx_tp_clear_5_cdec___pyx_scope_struct_7___iter__, /*tp_clear*/
   0, /*tp_richcompare*/
   0, /*tp_weaklistoffset*/
   0, /*tp_iter*/
   0, /*tp_iternext*/
-  __pyx_methods_5_cdec___pyx_scope_struct_4_sample, /*tp_methods*/
+  __pyx_methods_5_cdec___pyx_scope_struct_7___iter__, /*tp_methods*/
   0, /*tp_members*/
   0, /*tp_getset*/
   0, /*tp_base*/
@@ -7810,7 +11425,7 @@ static PyTypeObject __pyx_type_5_cdec___pyx_scope_struct_4_sample = {
   0, /*tp_dictoffset*/
   0, /*tp_init*/
   0, /*tp_alloc*/
-  __pyx_tp_new_5_cdec___pyx_scope_struct_4_sample, /*tp_new*/
+  __pyx_tp_new_5_cdec___pyx_scope_struct_7___iter__, /*tp_new*/
   0, /*tp_free*/
   0, /*tp_is_gc*/
   0, /*tp_bases*/
@@ -7824,44 +11439,60 @@ static PyTypeObject __pyx_type_5_cdec___pyx_scope_struct_4_sample = {
   #endif
 };
 
-static PyObject *__pyx_tp_new_5_cdec___pyx_scope_struct_5___iter__(PyTypeObject *t, PyObject *a, PyObject *k) {
-  struct __pyx_obj_5_cdec___pyx_scope_struct_5___iter__ *p;
+static PyObject *__pyx_tp_new_5_cdec___pyx_scope_struct_8_candidate_set(PyTypeObject *t, PyObject *a, PyObject *k) {
+  struct __pyx_obj_5_cdec___pyx_scope_struct_8_candidate_set *p;
   PyObject *o = (*t->tp_alloc)(t, 0);
   if (!o) return 0;
-  p = ((struct __pyx_obj_5_cdec___pyx_scope_struct_5___iter__ *)o);
+  p = ((struct __pyx_obj_5_cdec___pyx_scope_struct_8_candidate_set *)o);
+  p->__pyx_v_candidate = 0;
+  p->__pyx_v_hypergraph = 0;
   p->__pyx_v_self = 0;
   return o;
 }
 
-static void __pyx_tp_dealloc_5_cdec___pyx_scope_struct_5___iter__(PyObject *o) {
-  struct __pyx_obj_5_cdec___pyx_scope_struct_5___iter__ *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_5___iter__ *)o;
+static void __pyx_tp_dealloc_5_cdec___pyx_scope_struct_8_candidate_set(PyObject *o) {
+  struct __pyx_obj_5_cdec___pyx_scope_struct_8_candidate_set *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_8_candidate_set *)o;
+  Py_XDECREF(((PyObject *)p->__pyx_v_candidate));
+  Py_XDECREF(((PyObject *)p->__pyx_v_hypergraph));
   Py_XDECREF(((PyObject *)p->__pyx_v_self));
   (*Py_TYPE(o)->tp_free)(o);
 }
 
-static int __pyx_tp_traverse_5_cdec___pyx_scope_struct_5___iter__(PyObject *o, visitproc v, void *a) {
+static int __pyx_tp_traverse_5_cdec___pyx_scope_struct_8_candidate_set(PyObject *o, visitproc v, void *a) {
   int e;
-  struct __pyx_obj_5_cdec___pyx_scope_struct_5___iter__ *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_5___iter__ *)o;
+  struct __pyx_obj_5_cdec___pyx_scope_struct_8_candidate_set *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_8_candidate_set *)o;
+  if (p->__pyx_v_candidate) {
+    e = (*v)(((PyObject*)p->__pyx_v_candidate), a); if (e) return e;
+  }
+  if (p->__pyx_v_hypergraph) {
+    e = (*v)(((PyObject*)p->__pyx_v_hypergraph), a); if (e) return e;
+  }
   if (p->__pyx_v_self) {
     e = (*v)(((PyObject*)p->__pyx_v_self), a); if (e) return e;
   }
   return 0;
 }
 
-static int __pyx_tp_clear_5_cdec___pyx_scope_struct_5___iter__(PyObject *o) {
-  struct __pyx_obj_5_cdec___pyx_scope_struct_5___iter__ *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_5___iter__ *)o;
+static int __pyx_tp_clear_5_cdec___pyx_scope_struct_8_candidate_set(PyObject *o) {
+  struct __pyx_obj_5_cdec___pyx_scope_struct_8_candidate_set *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_8_candidate_set *)o;
   PyObject* tmp;
+  tmp = ((PyObject*)p->__pyx_v_candidate);
+  p->__pyx_v_candidate = ((struct __pyx_obj_5_cdec_Candidate *)Py_None); Py_INCREF(Py_None);
+  Py_XDECREF(tmp);
+  tmp = ((PyObject*)p->__pyx_v_hypergraph);
+  p->__pyx_v_hypergraph = ((struct __pyx_obj_5_cdec_Hypergraph *)Py_None); Py_INCREF(Py_None);
+  Py_XDECREF(tmp);
   tmp = ((PyObject*)p->__pyx_v_self);
-  p->__pyx_v_self = ((struct __pyx_obj_5_cdec_Lattice *)Py_None); Py_INCREF(Py_None);
+  p->__pyx_v_self = ((struct __pyx_obj_5_cdec_SegmentEvaluator *)Py_None); Py_INCREF(Py_None);
   Py_XDECREF(tmp);
   return 0;
 }
 
-static PyMethodDef __pyx_methods_5_cdec___pyx_scope_struct_5___iter__[] = {
+static PyMethodDef __pyx_methods_5_cdec___pyx_scope_struct_8_candidate_set[] = {
   {0, 0, 0, 0}
 };
 
-static PyNumberMethods __pyx_tp_as_number___pyx_scope_struct_5___iter__ = {
+static PyNumberMethods __pyx_tp_as_number___pyx_scope_struct_8_candidate_set = {
   0, /*nb_add*/
   0, /*nb_subtract*/
   0, /*nb_multiply*/
@@ -7919,7 +11550,7 @@ static PyNumberMethods __pyx_tp_as_number___pyx_scope_struct_5___iter__ = {
   #endif
 };
 
-static PySequenceMethods __pyx_tp_as_sequence___pyx_scope_struct_5___iter__ = {
+static PySequenceMethods __pyx_tp_as_sequence___pyx_scope_struct_8_candidate_set = {
   0, /*sq_length*/
   0, /*sq_concat*/
   0, /*sq_repeat*/
@@ -7932,13 +11563,13 @@ static PySequenceMethods __pyx_tp_as_sequence___pyx_scope_struct_5___iter__ = {
   0, /*sq_inplace_repeat*/
 };
 
-static PyMappingMethods __pyx_tp_as_mapping___pyx_scope_struct_5___iter__ = {
+static PyMappingMethods __pyx_tp_as_mapping___pyx_scope_struct_8_candidate_set = {
   0, /*mp_length*/
   0, /*mp_subscript*/
   0, /*mp_ass_subscript*/
 };
 
-static PyBufferProcs __pyx_tp_as_buffer___pyx_scope_struct_5___iter__ = {
+static PyBufferProcs __pyx_tp_as_buffer___pyx_scope_struct_8_candidate_set = {
   #if PY_MAJOR_VERSION < 3
   0, /*bf_getreadbuffer*/
   #endif
@@ -7959,12 +11590,12 @@ static PyBufferProcs __pyx_tp_as_buffer___pyx_scope_struct_5___iter__ = {
   #endif
 };
 
-static PyTypeObject __pyx_type_5_cdec___pyx_scope_struct_5___iter__ = {
+static PyTypeObject __pyx_type_5_cdec___pyx_scope_struct_8_candidate_set = {
   PyVarObject_HEAD_INIT(0, 0)
-  __Pyx_NAMESTR("_cdec.__pyx_scope_struct_5___iter__"), /*tp_name*/
-  sizeof(struct __pyx_obj_5_cdec___pyx_scope_struct_5___iter__), /*tp_basicsize*/
+  __Pyx_NAMESTR("_cdec.__pyx_scope_struct_8_candidate_set"), /*tp_name*/
+  sizeof(struct __pyx_obj_5_cdec___pyx_scope_struct_8_candidate_set), /*tp_basicsize*/
   0, /*tp_itemsize*/
-  __pyx_tp_dealloc_5_cdec___pyx_scope_struct_5___iter__, /*tp_dealloc*/
+  __pyx_tp_dealloc_5_cdec___pyx_scope_struct_8_candidate_set, /*tp_dealloc*/
   0, /*tp_print*/
   0, /*tp_getattr*/
   0, /*tp_setattr*/
@@ -7974,24 +11605,24 @@ static PyTypeObject __pyx_type_5_cdec___pyx_scope_struct_5___iter__ = {
   0, /*reserved*/
   #endif
   0, /*tp_repr*/
-  &__pyx_tp_as_number___pyx_scope_struct_5___iter__, /*tp_as_number*/
-  &__pyx_tp_as_sequence___pyx_scope_struct_5___iter__, /*tp_as_sequence*/
-  &__pyx_tp_as_mapping___pyx_scope_struct_5___iter__, /*tp_as_mapping*/
+  &__pyx_tp_as_number___pyx_scope_struct_8_candidate_set, /*tp_as_number*/
+  &__pyx_tp_as_sequence___pyx_scope_struct_8_candidate_set, /*tp_as_sequence*/
+  &__pyx_tp_as_mapping___pyx_scope_struct_8_candidate_set, /*tp_as_mapping*/
   0, /*tp_hash*/
   0, /*tp_call*/
   0, /*tp_str*/
   0, /*tp_getattro*/
   0, /*tp_setattro*/
-  &__pyx_tp_as_buffer___pyx_scope_struct_5___iter__, /*tp_as_buffer*/
+  &__pyx_tp_as_buffer___pyx_scope_struct_8_candidate_set, /*tp_as_buffer*/
   Py_TPFLAGS_DEFAULT|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_HAVE_GC, /*tp_flags*/
   0, /*tp_doc*/
-  __pyx_tp_traverse_5_cdec___pyx_scope_struct_5___iter__, /*tp_traverse*/
-  __pyx_tp_clear_5_cdec___pyx_scope_struct_5___iter__, /*tp_clear*/
+  __pyx_tp_traverse_5_cdec___pyx_scope_struct_8_candidate_set, /*tp_traverse*/
+  __pyx_tp_clear_5_cdec___pyx_scope_struct_8_candidate_set, /*tp_clear*/
   0, /*tp_richcompare*/
   0, /*tp_weaklistoffset*/
   0, /*tp_iter*/
   0, /*tp_iternext*/
-  __pyx_methods_5_cdec___pyx_scope_struct_5___iter__, /*tp_methods*/
+  __pyx_methods_5_cdec___pyx_scope_struct_8_candidate_set, /*tp_methods*/
   0, /*tp_members*/
   0, /*tp_getset*/
   0, /*tp_base*/
@@ -8001,7 +11632,7 @@ static PyTypeObject __pyx_type_5_cdec___pyx_scope_struct_5___iter__ = {
   0, /*tp_dictoffset*/
   0, /*tp_init*/
   0, /*tp_alloc*/
-  __pyx_tp_new_5_cdec___pyx_scope_struct_5___iter__, /*tp_new*/
+  __pyx_tp_new_5_cdec___pyx_scope_struct_8_candidate_set, /*tp_new*/
   0, /*tp_free*/
   0, /*tp_is_gc*/
   0, /*tp_bases*/
@@ -8039,15 +11670,18 @@ static __Pyx_StringTabEntry __pyx_string_tab[] = {
   {&__pyx_kp_s_11, __pyx_k_11, sizeof(__pyx_k_11), 0, 0, 1, 0},
   {&__pyx_kp_s_13, __pyx_k_13, sizeof(__pyx_k_13), 0, 0, 1, 0},
   {&__pyx_kp_s_14, __pyx_k_14, sizeof(__pyx_k_14), 0, 0, 1, 0},
+  {&__pyx_kp_s_19, __pyx_k_19, sizeof(__pyx_k_19), 0, 0, 1, 0},
   {&__pyx_kp_s_2, __pyx_k_2, sizeof(__pyx_k_2), 0, 0, 1, 0},
-  {&__pyx_kp_s_21, __pyx_k_21, sizeof(__pyx_k_21), 0, 0, 1, 0},
+  {&__pyx_kp_s_23, __pyx_k_23, sizeof(__pyx_k_23), 0, 0, 1, 0},
+  {&__pyx_n_s__BLEU, __pyx_k__BLEU, sizeof(__pyx_k__BLEU), 0, 0, 1, 1},
   {&__pyx_n_s__Exception, __pyx_k__Exception, sizeof(__pyx_k__Exception), 0, 0, 1, 1},
+  {&__pyx_n_s__IBM_BLEU, __pyx_k__IBM_BLEU, sizeof(__pyx_k__IBM_BLEU), 0, 0, 1, 1},
   {&__pyx_n_s__IndexError, __pyx_k__IndexError, sizeof(__pyx_k__IndexError), 0, 0, 1, 1},
   {&__pyx_n_s__KeyError, __pyx_k__KeyError, sizeof(__pyx_k__KeyError), 0, 0, 1, 1},
   {&__pyx_n_s__NotImplemented, __pyx_k__NotImplemented, sizeof(__pyx_k__NotImplemented), 0, 0, 1, 1},
   {&__pyx_n_s__ParseFailed, __pyx_k__ParseFailed, sizeof(__pyx_k__ParseFailed), 0, 0, 1, 1},
+  {&__pyx_n_s__TER, __pyx_k__TER, sizeof(__pyx_k__TER), 0, 0, 1, 1},
   {&__pyx_n_s__TypeError, __pyx_k__TypeError, sizeof(__pyx_k__TypeError), 0, 0, 1, 1},
-  {&__pyx_n_s__ValueError, __pyx_k__ValueError, sizeof(__pyx_k__ValueError), 0, 0, 1, 1},
   {&__pyx_n_s____enter__, __pyx_k____enter__, sizeof(__pyx_k____enter__), 0, 0, 1, 1},
   {&__pyx_n_s____exit__, __pyx_k____exit__, sizeof(__pyx_k____exit__), 0, 0, 1, 1},
   {&__pyx_n_s____main__, __pyx_k____main__, sizeof(__pyx_k____main__), 0, 0, 1, 1},
@@ -8059,13 +11693,18 @@ static __Pyx_StringTabEntry __pyx_string_tab[] = {
   {&__pyx_n_s__density, __pyx_k__density, sizeof(__pyx_k__density), 0, 0, 1, 1},
   {&__pyx_n_s__dot, __pyx_k__dot, sizeof(__pyx_k__dot), 0, 0, 1, 1},
   {&__pyx_n_s__encode, __pyx_k__encode, sizeof(__pyx_k__encode), 0, 0, 1, 1},
+  {&__pyx_n_s__encoding, __pyx_k__encoding, sizeof(__pyx_k__encoding), 0, 0, 1, 1},
   {&__pyx_n_s__enumerate, __pyx_k__enumerate, sizeof(__pyx_k__enumerate), 0, 0, 1, 1},
   {&__pyx_n_s__eval, __pyx_k__eval, sizeof(__pyx_k__eval), 0, 0, 1, 1},
   {&__pyx_n_s__grammar, __pyx_k__grammar, sizeof(__pyx_k__grammar), 0, 0, 1, 1},
+  {&__pyx_n_s__hypergraph, __pyx_k__hypergraph, sizeof(__pyx_k__hypergraph), 0, 0, 1, 1},
   {&__pyx_n_s__inp, __pyx_k__inp, sizeof(__pyx_k__inp), 0, 0, 1, 1},
+  {&__pyx_n_s__k, __pyx_k__k, sizeof(__pyx_k__k), 0, 0, 1, 1},
+  {&__pyx_n_s__name, __pyx_k__name, sizeof(__pyx_k__name), 0, 0, 1, 1},
   {&__pyx_n_s__open, __pyx_k__open, sizeof(__pyx_k__open), 0, 0, 1, 1},
   {&__pyx_n_s__plf, __pyx_k__plf, sizeof(__pyx_k__plf), 0, 0, 1, 1},
   {&__pyx_n_s__range, __pyx_k__range, sizeof(__pyx_k__range), 0, 0, 1, 1},
+  {&__pyx_n_s__refs, __pyx_k__refs, sizeof(__pyx_k__refs), 0, 0, 1, 1},
   {&__pyx_n_s__self, __pyx_k__self, sizeof(__pyx_k__self), 0, 0, 1, 1},
   {&__pyx_n_s__sentence, __pyx_k__sentence, sizeof(__pyx_k__sentence), 0, 0, 1, 1},
   {&__pyx_n_s__split, __pyx_k__split, sizeof(__pyx_k__split), 0, 0, 1, 1},
@@ -8074,14 +11713,13 @@ static __Pyx_StringTabEntry __pyx_string_tab[] = {
   {0, 0, 0, 0, 0, 0, 0}
 };
 static int __Pyx_InitCachedBuiltins(void) {
-  __pyx_builtin_Exception = __Pyx_GetName(__pyx_b, __pyx_n_s__Exception); if (!__pyx_builtin_Exception) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 12; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_builtin_Exception = __Pyx_GetName(__pyx_b, __pyx_n_s__Exception); if (!__pyx_builtin_Exception) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 13; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __pyx_builtin_KeyError = __Pyx_GetName(__pyx_b, __pyx_n_s__KeyError); if (!__pyx_builtin_KeyError) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 10; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __pyx_builtin_range = __Pyx_GetName(__pyx_b, __pyx_n_s__range); if (!__pyx_builtin_range) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 20; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __pyx_builtin_ValueError = __Pyx_GetName(__pyx_b, __pyx_n_s__ValueError); if (!__pyx_builtin_ValueError) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 56; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_builtin_TypeError = __Pyx_GetName(__pyx_b, __pyx_n_s__TypeError); if (!__pyx_builtin_TypeError) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 56; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __pyx_builtin_NotImplemented = __Pyx_GetName(__pyx_b, __pyx_n_s__NotImplemented); if (!__pyx_builtin_NotImplemented) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 69; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __pyx_builtin_eval = __Pyx_GetName(__pyx_b, __pyx_n_s__eval); if (!__pyx_builtin_eval) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 82; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_builtin_eval = __Pyx_GetName(__pyx_b, __pyx_n_s__eval); if (!__pyx_builtin_eval) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 95; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __pyx_builtin_enumerate = __Pyx_GetName(__pyx_b, __pyx_n_s__enumerate); if (!__pyx_builtin_enumerate) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 9; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __pyx_builtin_TypeError = __Pyx_GetName(__pyx_b, __pyx_n_s__TypeError); if (!__pyx_builtin_TypeError) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 15; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __pyx_builtin_IndexError = __Pyx_GetName(__pyx_b, __pyx_n_s__IndexError); if (!__pyx_builtin_IndexError) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 21; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __pyx_builtin_open = __Pyx_GetName(__pyx_b, __pyx_n_s__open); if (!__pyx_builtin_open) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 31; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   return 0;
@@ -8095,7 +11733,7 @@ static int __Pyx_InitCachedConstants(void) {
 
   /* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":69
  *         elif op == 3: # !=
- *             return not (self == other)
+ *             return not (x == y)
  *         raise NotImplemented('comparison not implemented for SparseVector')             # <<<<<<<<<<<<<<
  * 
  *     def __len__(self):
@@ -8177,14 +11815,14 @@ static int __Pyx_InitCachedConstants(void) {
   __Pyx_GIVEREF(((PyObject *)__pyx_n_s__utf8));
   __Pyx_GIVEREF(((PyObject *)__pyx_k_tuple_8));
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":65
+  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":78
  *         for k in range(hypos.size()):
  *             sentence = GetString(hypos[0][k].words).c_str()
  *             yield sentence.decode('utf8')             # <<<<<<<<<<<<<<
  *         del hypos
  * 
  */
-  __pyx_k_tuple_9 = PyTuple_New(1); if (unlikely(!__pyx_k_tuple_9)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 65; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_k_tuple_9 = PyTuple_New(1); if (unlikely(!__pyx_k_tuple_9)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 78; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __Pyx_GOTREF(__pyx_k_tuple_9);
   __Pyx_INCREF(((PyObject *)__pyx_n_s__utf8));
   PyTuple_SET_ITEM(__pyx_k_tuple_9, 0, ((PyObject *)__pyx_n_s__utf8));
@@ -8261,6 +11899,20 @@ static int __Pyx_InitCachedConstants(void) {
   __Pyx_GIVEREF(((PyObject *)__pyx_n_s__utf8));
   __Pyx_GIVEREF(((PyObject *)__pyx_k_tuple_18));
 
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":6
+ *     cdef bytes ret
+ *     if isinstance(sentence, unicode):
+ *         ret = sentence.encode('utf8')             # <<<<<<<<<<<<<<
+ *     elif isinstance(sentence, str):
+ *         ret = sentence
+ */
+  __pyx_k_tuple_20 = PyTuple_New(1); if (unlikely(!__pyx_k_tuple_20)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 6; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_k_tuple_20);
+  __Pyx_INCREF(((PyObject *)__pyx_n_s__utf8));
+  PyTuple_SET_ITEM(__pyx_k_tuple_20, 0, ((PyObject *)__pyx_n_s__utf8));
+  __Pyx_GIVEREF(((PyObject *)__pyx_n_s__utf8));
+  __Pyx_GIVEREF(((PyObject *)__pyx_k_tuple_20));
+
   /* "_cdec.pyx":31
  * 
  *     def read_weights(self, cfg):
@@ -8268,18 +11920,18 @@ static int __Pyx_InitCachedConstants(void) {
  *             for line in fp:
  *                 fname, value = line.split()
  */
-  __pyx_k_tuple_19 = PyTuple_New(3); if (unlikely(!__pyx_k_tuple_19)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 31; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __Pyx_GOTREF(__pyx_k_tuple_19);
+  __pyx_k_tuple_21 = PyTuple_New(3); if (unlikely(!__pyx_k_tuple_21)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 31; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_k_tuple_21);
   __Pyx_INCREF(Py_None);
-  PyTuple_SET_ITEM(__pyx_k_tuple_19, 0, Py_None);
+  PyTuple_SET_ITEM(__pyx_k_tuple_21, 0, Py_None);
   __Pyx_GIVEREF(Py_None);
   __Pyx_INCREF(Py_None);
-  PyTuple_SET_ITEM(__pyx_k_tuple_19, 1, Py_None);
+  PyTuple_SET_ITEM(__pyx_k_tuple_21, 1, Py_None);
   __Pyx_GIVEREF(Py_None);
   __Pyx_INCREF(Py_None);
-  PyTuple_SET_ITEM(__pyx_k_tuple_19, 2, Py_None);
+  PyTuple_SET_ITEM(__pyx_k_tuple_21, 2, Py_None);
   __Pyx_GIVEREF(Py_None);
-  __Pyx_GIVEREF(((PyObject *)__pyx_k_tuple_19));
+  __Pyx_GIVEREF(((PyObject *)__pyx_k_tuple_21));
 
   /* "_cdec.pyx":38
  *     def translate(self, sentence, grammar=None):
@@ -8288,12 +11940,37 @@ static int __Pyx_InitCachedConstants(void) {
  *         elif isinstance(sentence, str):
  *             inp = sentence.strip()
  */
-  __pyx_k_tuple_20 = PyTuple_New(1); if (unlikely(!__pyx_k_tuple_20)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 38; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __Pyx_GOTREF(__pyx_k_tuple_20);
+  __pyx_k_tuple_22 = PyTuple_New(1); if (unlikely(!__pyx_k_tuple_22)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 38; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_k_tuple_22);
   __Pyx_INCREF(((PyObject *)__pyx_n_s__utf8));
-  PyTuple_SET_ITEM(__pyx_k_tuple_20, 0, ((PyObject *)__pyx_n_s__utf8));
+  PyTuple_SET_ITEM(__pyx_k_tuple_22, 0, ((PyObject *)__pyx_n_s__utf8));
   __Pyx_GIVEREF(((PyObject *)__pyx_n_s__utf8));
-  __Pyx_GIVEREF(((PyObject *)__pyx_k_tuple_20));
+  __Pyx_GIVEREF(((PyObject *)__pyx_k_tuple_22));
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":115
+ *         return self.name.c_str()
+ * 
+ * BLEU = Scorer('IBM_BLEU')             # <<<<<<<<<<<<<<
+ * TER = Scorer('TER')
+ */
+  __pyx_k_tuple_24 = PyTuple_New(1); if (unlikely(!__pyx_k_tuple_24)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 115; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_k_tuple_24);
+  __Pyx_INCREF(((PyObject *)__pyx_n_s__IBM_BLEU));
+  PyTuple_SET_ITEM(__pyx_k_tuple_24, 0, ((PyObject *)__pyx_n_s__IBM_BLEU));
+  __Pyx_GIVEREF(((PyObject *)__pyx_n_s__IBM_BLEU));
+  __Pyx_GIVEREF(((PyObject *)__pyx_k_tuple_24));
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":116
+ * 
+ * BLEU = Scorer('IBM_BLEU')
+ * TER = Scorer('TER')             # <<<<<<<<<<<<<<
+ */
+  __pyx_k_tuple_25 = PyTuple_New(1); if (unlikely(!__pyx_k_tuple_25)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 116; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_k_tuple_25);
+  __Pyx_INCREF(((PyObject *)__pyx_n_s__TER));
+  PyTuple_SET_ITEM(__pyx_k_tuple_25, 0, ((PyObject *)__pyx_n_s__TER));
+  __Pyx_GIVEREF(((PyObject *)__pyx_n_s__TER));
+  __Pyx_GIVEREF(((PyObject *)__pyx_k_tuple_25));
   __Pyx_RefNannyFinishContext();
   return 0;
   __pyx_L1_error:;
@@ -8389,6 +12066,18 @@ PyMODINIT_FUNC PyInit__cdec(void)
   if (PyType_Ready(&__pyx_type_5_cdec_Lattice) < 0) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 3; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   if (__Pyx_SetAttrString(__pyx_m, "Lattice", (PyObject *)&__pyx_type_5_cdec_Lattice) < 0) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 3; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __pyx_ptype_5_cdec_Lattice = &__pyx_type_5_cdec_Lattice;
+  if (PyType_Ready(&__pyx_type_5_cdec_Candidate) < 0) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 13; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (__Pyx_SetAttrString(__pyx_m, "Candidate", (PyObject *)&__pyx_type_5_cdec_Candidate) < 0) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 13; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_ptype_5_cdec_Candidate = &__pyx_type_5_cdec_Candidate;
+  if (PyType_Ready(&__pyx_type_5_cdec_SufficientStats) < 0) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 27; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (__Pyx_SetAttrString(__pyx_m, "SufficientStats", (PyObject *)&__pyx_type_5_cdec_SufficientStats) < 0) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 27; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_ptype_5_cdec_SufficientStats = &__pyx_type_5_cdec_SufficientStats;
+  if (PyType_Ready(&__pyx_type_5_cdec_SegmentEvaluator) < 0) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 59; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (__Pyx_SetAttrString(__pyx_m, "SegmentEvaluator", (PyObject *)&__pyx_type_5_cdec_SegmentEvaluator) < 0) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 59; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_ptype_5_cdec_SegmentEvaluator = &__pyx_type_5_cdec_SegmentEvaluator;
+  if (PyType_Ready(&__pyx_type_5_cdec_Scorer) < 0) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 87; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (__Pyx_SetAttrString(__pyx_m, "Scorer", (PyObject *)&__pyx_type_5_cdec_Scorer) < 0) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 87; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_ptype_5_cdec_Scorer = &__pyx_type_5_cdec_Scorer;
   if (PyType_Ready(&__pyx_type_5_cdec_Decoder) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 15; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   if (__Pyx_SetAttrString(__pyx_m, "Decoder", (PyObject *)&__pyx_type_5_cdec_Decoder) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 15; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __pyx_ptype_5_cdec_Decoder = &__pyx_type_5_cdec_Decoder;
@@ -8400,42 +12089,69 @@ PyMODINIT_FUNC PyInit__cdec(void)
   __pyx_ptype_5_cdec___pyx_scope_struct_2_kbest = &__pyx_type_5_cdec___pyx_scope_struct_2_kbest;
   if (PyType_Ready(&__pyx_type_5_cdec___pyx_scope_struct_3_kbest_tree) < 0) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 44; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __pyx_ptype_5_cdec___pyx_scope_struct_3_kbest_tree = &__pyx_type_5_cdec___pyx_scope_struct_3_kbest_tree;
-  if (PyType_Ready(&__pyx_type_5_cdec___pyx_scope_struct_4_sample) < 0) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 56; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __pyx_ptype_5_cdec___pyx_scope_struct_4_sample = &__pyx_type_5_cdec___pyx_scope_struct_4_sample;
-  if (PyType_Ready(&__pyx_type_5_cdec___pyx_scope_struct_5___iter__) < 0) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 50; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __pyx_ptype_5_cdec___pyx_scope_struct_5___iter__ = &__pyx_type_5_cdec___pyx_scope_struct_5___iter__;
+  if (PyType_Ready(&__pyx_type_5_cdec___pyx_scope_struct_4_kbest_features) < 0) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 56; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_ptype_5_cdec___pyx_scope_struct_4_kbest_features = &__pyx_type_5_cdec___pyx_scope_struct_4_kbest_features;
+  if (PyType_Ready(&__pyx_type_5_cdec___pyx_scope_struct_5_sample) < 0) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 69; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_ptype_5_cdec___pyx_scope_struct_5_sample = &__pyx_type_5_cdec___pyx_scope_struct_5_sample;
+  if (PyType_Ready(&__pyx_type_5_cdec___pyx_scope_struct_6___iter__) < 0) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 50; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_ptype_5_cdec___pyx_scope_struct_6___iter__ = &__pyx_type_5_cdec___pyx_scope_struct_6___iter__;
+  if (PyType_Ready(&__pyx_type_5_cdec___pyx_scope_struct_7___iter__) < 0) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 45; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_ptype_5_cdec___pyx_scope_struct_7___iter__ = &__pyx_type_5_cdec___pyx_scope_struct_7___iter__;
+  if (PyType_Ready(&__pyx_type_5_cdec___pyx_scope_struct_8_candidate_set) < 0) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 75; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_ptype_5_cdec___pyx_scope_struct_8_candidate_set = &__pyx_type_5_cdec___pyx_scope_struct_8_candidate_set;
   /*--- Type import code ---*/
   /*--- Variable import code ---*/
   /*--- Function import code ---*/
   /*--- Execution code ---*/
 
-  /* "_cdec.pyx":10
- * include "lattice.pxi"
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":115
+ *         return self.name.c_str()
+ * 
+ * BLEU = Scorer('IBM_BLEU')             # <<<<<<<<<<<<<<
+ * TER = Scorer('TER')
+ */
+  __pyx_t_1 = PyObject_Call(((PyObject *)((PyObject*)__pyx_ptype_5_cdec_Scorer)), ((PyObject *)__pyx_k_tuple_24), NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 115; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_1);
+  if (PyObject_SetAttr(__pyx_m, __pyx_n_s__BLEU, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 115; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":116
+ * 
+ * BLEU = Scorer('IBM_BLEU')
+ * TER = Scorer('TER')             # <<<<<<<<<<<<<<
+ */
+  __pyx_t_1 = PyObject_Call(((PyObject *)((PyObject*)__pyx_ptype_5_cdec_Scorer)), ((PyObject *)__pyx_k_tuple_25), NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 116; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_1);
+  if (PyObject_SetAttr(__pyx_m, __pyx_n_s__TER, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 116; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+
+  /* "_cdec.pyx":11
+ * include "mteval.pxi"
  * 
  * SetSilent(True)             # <<<<<<<<<<<<<<
  * 
- * class ParseFailed(Exception):
+ * class ParseFailed(Exception): pass
  */
   SetSilent(1);
 
-  /* "_cdec.pyx":12
+  /* "_cdec.pyx":13
  * SetSilent(True)
  * 
- * class ParseFailed(Exception):             # <<<<<<<<<<<<<<
- *     pass
+ * class ParseFailed(Exception): pass             # <<<<<<<<<<<<<<
  * 
+ * cdef class Decoder:
  */
-  __pyx_t_1 = PyDict_New(); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 12; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_1 = PyDict_New(); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 13; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __Pyx_GOTREF(((PyObject *)__pyx_t_1));
-  __pyx_t_2 = PyTuple_New(1); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 12; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_2 = PyTuple_New(1); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 13; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __Pyx_GOTREF(__pyx_t_2);
   __Pyx_INCREF(__pyx_builtin_Exception);
   PyTuple_SET_ITEM(__pyx_t_2, 0, __pyx_builtin_Exception);
   __Pyx_GIVEREF(__pyx_builtin_Exception);
-  __pyx_t_3 = __Pyx_CreateClass(((PyObject *)__pyx_t_2), ((PyObject *)__pyx_t_1), __pyx_n_s__ParseFailed, __pyx_n_s___cdec); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 12; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_3 = __Pyx_CreateClass(((PyObject *)__pyx_t_2), ((PyObject *)__pyx_t_1), __pyx_n_s__ParseFailed, __pyx_n_s___cdec); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 13; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __Pyx_GOTREF(__pyx_t_3);
   __Pyx_DECREF(((PyObject *)__pyx_t_2)); __pyx_t_2 = 0;
-  if (PyObject_SetAttr(__pyx_m, __pyx_n_s__ParseFailed, __pyx_t_3) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 12; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (PyObject_SetAttr(__pyx_m, __pyx_n_s__ParseFailed, __pyx_t_3) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 13; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
   __Pyx_DECREF(((PyObject *)__pyx_t_1)); __pyx_t_1 = 0;
 
@@ -8673,6 +12389,18 @@ static int __Pyx_ArgTypeTest(PyObject *obj, PyTypeObject *type, int none_allowed
     return 0;
 }
 
+static CYTHON_INLINE int __Pyx_TypeTest(PyObject *obj, PyTypeObject *type) {
+    if (unlikely(!type)) {
+        PyErr_Format(PyExc_SystemError, "Missing type object");
+        return 0;
+    }
+    if (likely(PyObject_TypeCheck(obj, type)))
+        return 1;
+    PyErr_Format(PyExc_TypeError, "Cannot convert %.200s to %.200s",
+                 Py_TYPE(obj)->tp_name, type->tp_name);
+    return 0;
+}
+
 static void __Pyx_RaiseDoubleKeywordsError(
     const char* func_name,
     PyObject* kw_name)
@@ -8889,18 +12617,6 @@ bad:
     return -1;
 }
 
-static CYTHON_INLINE int __Pyx_TypeTest(PyObject *obj, PyTypeObject *type) {
-    if (unlikely(!type)) {
-        PyErr_Format(PyExc_SystemError, "Missing type object");
-        return 0;
-    }
-    if (likely(PyObject_TypeCheck(obj, type)))
-        return 1;
-    PyErr_Format(PyExc_TypeError, "Cannot convert %.200s to %.200s",
-                 Py_TYPE(obj)->tp_name, type->tp_name);
-    return 0;
-}
-
 static CYTHON_INLINE void __Pyx_ExceptionSave(PyObject **type, PyObject **value, PyObject **tb) {
     PyThreadState *tstate = PyThreadState_GET();
     *type = tstate->exc_type;
@@ -9693,6 +13409,25 @@ static int __pyx_Generator_init(void)
     return PyType_Ready(&__pyx_GeneratorType);
 }
 
+static void __Pyx_WriteUnraisable(const char *name, int clineno,
+                                  int lineno, const char *filename) {
+    PyObject *old_exc, *old_val, *old_tb;
+    PyObject *ctx;
+    __Pyx_ErrFetch(&old_exc, &old_val, &old_tb);
+    #if PY_MAJOR_VERSION < 3
+    ctx = PyString_FromString(name);
+    #else
+    ctx = PyUnicode_FromString(name);
+    #endif
+    __Pyx_ErrRestore(old_exc, old_val, old_tb);
+    if (!ctx) {
+        PyErr_WriteUnraisable(Py_None);
+    } else {
+        PyErr_WriteUnraisable(ctx);
+        Py_DECREF(ctx);
+    }
+}
+
 static int __Pyx_check_binary_version(void) {
     char ctversion[4], rtversion[4];
     PyOS_snprintf(ctversion, 4, "%d.%d", PY_MAJOR_VERSION, PY_MINOR_VERSION);
diff --git a/python/src/_cdec.pyx b/python/src/_cdec.pyx
index 698a66f6..6fafbbc0 100644
--- a/python/src/_cdec.pyx
+++ b/python/src/_cdec.pyx
@@ -6,11 +6,11 @@ cimport decoder
 include "vectors.pxi"
 include "hypergraph.pxi"
 include "lattice.pxi"
+include "mteval.pxi"
 
 SetSilent(True)
 
-class ParseFailed(Exception):
-    pass
+class ParseFailed(Exception): pass
 
 cdef class Decoder:
     cdef decoder.Decoder* dec
diff --git a/python/src/hypergraph.pxi b/python/src/hypergraph.pxi
index c226d105..ce78b729 100644
--- a/python/src/hypergraph.pxi
+++ b/python/src/hypergraph.pxi
@@ -53,6 +53,19 @@ cdef class Hypergraph:
             yield tree.decode('utf8')
         del derivations
 
+    def kbest_features(self, size):
+        cdef kb.KBestDerivations[FastSparseVector[weight_t], kb.FeatureVectorTraversal]* derivations = new kb.KBestDerivations[FastSparseVector[weight_t], kb.FeatureVectorTraversal](self.hg[0], size)
+        cdef kb.KBestDerivations[FastSparseVector[weight_t], kb.FeatureVectorTraversal].Derivation* derivation
+        cdef SparseVector fmap
+        cdef unsigned k
+        for k in range(size):
+            derivation = derivations.LazyKthBest(self.hg.nodes_.size() - 1, k)
+            if not derivation: break
+            fmap = SparseVector()
+            fmap.vector = new FastSparseVector[weight_t](derivation._yield)
+            yield fmap
+        del derivations
+
     def sample(self, unsigned n):
         cdef vector[hypergraph.Hypothesis]* hypos = new vector[hypergraph.Hypothesis]()
         if self.rng == NULL:
@@ -87,6 +100,6 @@ cdef class Hypergraph:
         elif isinstance(weights, DenseVector):
             self.hg.Reweight((<DenseVector> weights).vector[0])
         else:
-            raise ValueError('cannot reweight hypergraph with %s' % type(weights))
+            raise TypeError('cannot reweight hypergraph with %s' % type(weights))
 
     # TODO get feature expectations, get partition function ("inside" score)
diff --git a/python/src/kbest.pxd b/python/src/kbest.pxd
index f34ac5ed..cef42bd3 100644
--- a/python/src/kbest.pxd
+++ b/python/src/kbest.pxd
@@ -9,6 +9,8 @@ cdef extern from "decoder/viterbi.h":
         pass
     cdef cppclass FTreeTraversal:
         pass
+    cdef cppclass FeatureVectorTraversal:
+        pass
 
 cdef extern from "decoder/kbest.h" namespace "KBest":
     cdef cppclass KBestDerivations[T, Traversal]:
diff --git a/python/src/mteval.pxd b/python/src/mteval.pxd
new file mode 100644
index 00000000..52af6297
--- /dev/null
+++ b/python/src/mteval.pxd
@@ -0,0 +1,47 @@
+from libcpp.vector cimport vector
+from libcpp.string cimport string
+from utils cimport *
+from hypergraph cimport Hypergraph
+
+cdef extern from "mteval/ns.h":
+    cdef cppclass SufficientStats:
+        SufficientStats()
+        SufficientStats(SufficientStats&)
+        unsigned size()
+        float operator[](unsigned i)
+        void swap(SufficientStats& other)
+
+    SufficientStats add "operator+" (SufficientStats&, SufficientStats&)
+
+    cdef cppclass SegmentEvaluator:
+        void Evaluate(vector[WordID]& hyp, SufficientStats* out)
+
+    cdef cppclass EvaluationMetric:
+        string& MetricId()
+        bint IsErrorMetric()
+        float ComputeScore(SufficientStats& stats)
+        string DetailedScore(SufficientStats& stats)
+        shared_ptr[SegmentEvaluator] CreateSegmentEvaluator(vector[vector[WordID]]& refs)
+        ComputeSufficientStatistics(vector[WordID]& hyp,
+                                    vector[WordID]& refs,
+                                    SufficientStats* out)
+
+cdef extern from "mteval/ns.h" namespace "EvaluationMetric":
+    EvaluationMetric* Instance(string& metric_id)
+    EvaluationMetric* Instance() # IBM_BLEU
+
+cdef extern from "training/candidate_set.h" namespace "training":
+    cdef cppclass Candidate "const training::Candidate":
+        vector[WordID] ewords
+        FastSparseVector[weight_t] fmap
+        SufficientStats eval_feats
+
+    cdef cppclass CandidateSet:
+        CandidateSet()
+        unsigned size()
+        Candidate& operator[](unsigned i)
+        void ReadFromFile(string& file)
+        void WriteToFile(string& file)
+        void AddKBestCandidates(Hypergraph& hg,
+                unsigned kbest_size,
+                SegmentEvaluator* scorer)
diff --git a/python/src/mteval.pxi b/python/src/mteval.pxi
new file mode 100644
index 00000000..dabdf927
--- /dev/null
+++ b/python/src/mteval.pxi
@@ -0,0 +1,116 @@
+cimport mteval
+
+cdef char* as_str(sentence, error_msg='Cannot convert type %s to str'):
+    cdef bytes ret
+    if isinstance(sentence, unicode):
+        ret = sentence.encode('utf8')
+    elif isinstance(sentence, str):
+        ret = sentence
+    else:
+        raise TypeError(error_msg % type(sentence))
+    return ret
+
+cdef class Candidate:
+    cdef mteval.Candidate* candidate
+    cdef public float score
+
+    property words:
+        def __get__(self):
+            return unicode(GetString(self.candidate.ewords).c_str(), encoding='utf8')
+
+    property fmap:
+        def __get__(self):
+            cdef SparseVector fmap = SparseVector()
+            fmap.vector = new FastSparseVector[weight_t](self.candidate.fmap)
+            return fmap
+
+cdef class SufficientStats:
+    cdef mteval.SufficientStats* stats
+    cdef mteval.EvaluationMetric* metric
+
+    def __dealloc__(self):
+        del self.stats
+
+    property score:
+        def __get__(self):
+            return self.metric.ComputeScore(self.stats[0])
+
+    property detail:
+        def __get__(self):
+            return self.metric.DetailedScore(self.stats[0]).c_str()
+
+    def __len__(self):
+        return self.stats.size()
+
+    def __iter__(self):
+        for i in range(len(self)):
+            yield self.stats[0][i]
+
+    def __iadd__(SufficientStats self, SufficientStats other):
+        self.stats[0] += other.stats[0]
+        return self
+
+    def __add__(SufficientStats x, SufficientStats y):
+        cdef SufficientStats result = SufficientStats()
+        result.stats = new mteval.SufficientStats(mteval.add(x.stats[0], y.stats[0]))
+        result.metric = x.metric
+        return result
+
+cdef class SegmentEvaluator:
+    cdef shared_ptr[mteval.SegmentEvaluator]* scorer
+    cdef mteval.EvaluationMetric* metric
+    
+    def __dealloc__(self):
+        del self.scorer
+
+    def evaluate(self, sentence):
+        cdef vector[WordID] hyp
+        cdef SufficientStats sf = SufficientStats()
+        sf.metric = self.metric
+        sf.stats = new mteval.SufficientStats()
+        ConvertSentence(string(as_str(sentence.strip())), &hyp)
+        self.scorer.get().Evaluate(hyp, sf.stats)
+        return sf
+
+    def candidate_set(self, Hypergraph hypergraph, unsigned k):
+        cdef mteval.CandidateSet* cs = new mteval.CandidateSet()
+        cs.AddKBestCandidates(hypergraph.hg[0], k, self.scorer.get())
+        cdef Candidate candidate
+        cdef unsigned i
+        for i in range(cs.size()):
+            candidate = Candidate()
+            candidate.candidate = &cs[0][i]
+            candidate.score = self.metric.ComputeScore(cs[0][i].eval_feats)
+            yield candidate
+        del cs
+
+cdef class Scorer:
+    cdef string* name
+
+    def __cinit__(self, char* name):
+        self.name = new string(name)
+    
+    def __call__(self, refs):
+        cdef mteval.EvaluationMetric* metric = mteval.Instance(self.name[0])
+        if isinstance(refs, unicode) or isinstance(refs, str):
+            refs = [refs]
+        cdef vector[vector[WordID]]* refsv = new vector[vector[WordID]]()
+        cdef vector[WordID]* refv
+        cdef bytes ref_str
+        for ref in refs:
+            refv = new vector[WordID]()
+            ConvertSentence(string(as_str(ref.strip())), refv)
+            refsv.push_back(refv[0])
+            del refv
+        cdef unsigned i
+        cdef SegmentEvaluator evaluator = SegmentEvaluator()
+        evaluator.metric = metric
+        evaluator.scorer = new shared_ptr[mteval.SegmentEvaluator](metric.CreateSegmentEvaluator(refsv[0]))
+        del refsv # in theory should not delete but store in SegmentEvaluator
+        return evaluator
+
+    def __str__(self):
+        return self.name.c_str()
+
+BLEU = Scorer('IBM_BLEU')
+TER = Scorer('TER')
diff --git a/python/src/utils.pxd b/python/src/utils.pxd
index 3d518524..94fab5ef 100644
--- a/python/src/utils.pxd
+++ b/python/src/utils.pxd
@@ -50,16 +50,19 @@ cdef extern from "utils/sparse_vector.h":
 
     FastSparseVector[weight_t] operator+(FastSparseVector[weight_t]&, FastSparseVector[weight_t]&)
     FastSparseVector[weight_t] operator-(FastSparseVector[weight_t]&, FastSparseVector[weight_t]&)
+    FastSparseVector[weight_t] operator*(FastSparseVector[weight_t]&, double&)
+    FastSparseVector[weight_t] operator/(FastSparseVector[weight_t]&, double&)
     ostream operator<<(ostream& out, FastSparseVector[weight_t]& v)
 
 cdef extern from "utils/weights.h" namespace "Weights":
     void InitSparseVector(vector[weight_t]& dv, FastSparseVector[weight_t]* sv)
 
-cdef extern from "utils/tdict.cc" namespace "TD":
+cdef extern from "utils/tdict.h" namespace "TD":
     string GetString(vector[WordID]& st)
     unsigned NumWords()
     WordID TDConvert "TD::Convert" (char*)
     char* TDConvert "TD::Convert" (WordID)
+    void ConvertSentence(string& sent, vector[WordID]* ids)
 
 cdef extern from "utils/verbose.h":
     void SetSilent(bint)
@@ -76,3 +79,8 @@ cdef extern from "utils/filelib.h":
 cdef extern from "utils/sampler.h":
     cdef cppclass MT19937:
         pass
+
+cdef extern from "<boost/shared_ptr.hpp>" namespace "boost":
+    cdef cppclass shared_ptr[T]:
+        shared_ptr(shared_ptr& r)
+        T* get()
diff --git a/python/src/vectors.pxi b/python/src/vectors.pxi
index 74d3a0bd..233c9530 100644
--- a/python/src/vectors.pxi
+++ b/python/src/vectors.pxi
@@ -53,7 +53,7 @@ cdef class SparseVector:
             return self.vector.dot((<DenseVector> other).vector[0])
         elif isinstance(other, SparseVector):
             return self.vector.dot((<SparseVector> other).vector[0])
-        raise ValueError('cannot take the dot product of %s and SparseVector' % type(other))
+        raise TypeError('cannot take the dot product of %s and SparseVector' % type(other))
 
     def todense(self):
         cdef DenseVector dense = DenseVector()
@@ -61,11 +61,11 @@ cdef class SparseVector:
         self.vector.init_vector(dense.vector)
         return dense
     
-    def __richcmp__(SparseVector self, SparseVector other, int op):
+    def __richcmp__(SparseVector x, SparseVector y, int op):
         if op == 2: # ==
-            return self.vector[0] == other.vector[0]
+            return x.vector[0] == y.vector[0]
         elif op == 3: # !=
-            return not (self == other)
+            return not (x == y)
         raise NotImplemented('comparison not implemented for SparseVector')
 
     def __len__(self):
@@ -90,12 +90,30 @@ cdef class SparseVector:
         self.vector[0] /= scalar
         return self
 
-    def __add__(SparseVector self, SparseVector other):
+    def __add__(SparseVector x, SparseVector y):
         cdef SparseVector result = SparseVector()
-        result.vector = new FastSparseVector[weight_t](self.vector[0] + other.vector[0])
+        result.vector = new FastSparseVector[weight_t](x.vector[0] + y.vector[0])
         return result
 
-    def __sub__(SparseVector self, SparseVector other):
+    def __sub__(SparseVector x, SparseVector y):
         cdef SparseVector result = SparseVector()
-        result.vector = new FastSparseVector[weight_t](self.vector[0] - other.vector[0])
+        result.vector = new FastSparseVector[weight_t](x.vector[0] - y.vector[0])
+        return result
+
+    def __mul__(x, y):
+        cdef SparseVector vector
+        cdef float scalar
+        if isinstance(x, SparseVector): vector, scalar = x, y
+        else: vector, scalar = y, x
+        cdef SparseVector result = SparseVector()
+        result.vector = new FastSparseVector[weight_t](vector.vector[0] * scalar)
+        return result
+
+    def __div__(x, y):
+        cdef SparseVector vector
+        cdef float scalar
+        if isinstance(x, SparseVector): vector, scalar = x, y
+        else: vector, scalar = y, x
+        cdef SparseVector result = SparseVector()
+        result.vector = new FastSparseVector[weight_t](vector.vector[0] / scalar)
         return result
diff --git a/python/test.py b/python/test.py
index 92403298..b3900eef 100644
--- a/python/test.py
+++ b/python/test.py
@@ -31,9 +31,11 @@ print ' FTree[0]:', forest.viterbi_source_tree().encode('utf8')
 print 'LgProb[0]:', forest.viterbi_features().dot(decoder.weights)
 
 # Get k-best translations
-for i, (sentence, tree) in enumerate(zip(forest.kbest(5), forest.kbest_tree(5)), 1):
+kbest = zip(forest.kbest(5), forest.kbest_tree(5), forest.kbest_features(5))
+for i, (sentence, tree, features) in enumerate(kbest, 1):
     print 'Output[%d]:' % i, sentence.encode('utf8')
     print '  Tree[%d]:' % i, tree.encode('utf8')
+    print ' FVect[%d]:' % i, dict(features)
 
 # Sample translations from the forest
 for sentence in forest.sample(5):
-- 
cgit v1.2.3


From 06f90d83a1feafad301d365a4a437e44f68be45b Mon Sep 17 00:00:00 2001
From: Victor Chahuneau <vchahune@cs.cmu.edu>
Date: Sat, 21 Jul 2012 01:22:53 -0400
Subject: [python] Support for grammars

- Translation rules can now be create programatically
- Grammars = list of translation rules can be used for translation
- Feature expectations on the hypergraph (inside_outside)
---
 python/cdec/__init__.py       |     3 +-
 python/cdec/scfg/extractor.py |    20 +-
 python/setup.py               |    34 +-
 python/src/_cdec.cpp          | 23051 +++++++++++++++++++++++-----------------
 python/src/_cdec.pyx          |    29 +-
 python/src/decoder.pxd        |     7 +-
 python/src/grammar.pxd        |    43 +
 python/src/grammar.pxi        |   176 +
 python/src/hypergraph.pxd     |    15 +-
 python/src/hypergraph.pxi     |    28 +-
 python/src/lattice.pxi        |     2 +-
 python/src/trule.pxi          |    55 -
 python/src/utils.pxd          |     2 +
 python/src/vectors.pxi        |     1 +
 python/test.py                |     3 +
 15 files changed, 13863 insertions(+), 9606 deletions(-)
 create mode 100644 python/src/grammar.pxd
 create mode 100644 python/src/grammar.pxi
 delete mode 100644 python/src/trule.pxi

(limited to 'python/cdec/__init__.py')

diff --git a/python/cdec/__init__.py b/python/cdec/__init__.py
index 0d7b8782..89c323ba 100644
--- a/python/cdec/__init__.py
+++ b/python/cdec/__init__.py
@@ -1,2 +1 @@
-from _cdec import Decoder, Lattice
-import score
+from _cdec import Decoder, Lattice, TRule, NT, NTRef
diff --git a/python/cdec/scfg/extractor.py b/python/cdec/scfg/extractor.py
index 0a45ddb8..1dfa2421 100644
--- a/python/cdec/scfg/extractor.py
+++ b/python/cdec/scfg/extractor.py
@@ -1,3 +1,5 @@
+import sys, os
+import re
 import StringIO
 from itertools import chain
 
@@ -32,7 +34,16 @@ class PhonyGrammar:
         pass
 
 class GrammarExtractor:
-    def __init__(self, config):
+    def __init__(self, cfg):
+        if isinstance(cfg, dict):
+            config = cfg
+        elif isinstance(cfg, str):
+            cfg_file = os.path.basename(cfg)
+            if not re.match(r'^\w+\.py$', cfg_file):
+                raise ValueError('Config must be a *.py file')
+            sys.path.append(os.path.dirname(cfg))
+            config =  __import__(cfg_file.replace('.py', '')).__dict__
+            sys.path.pop()
         alignment = calignment.Alignment(config['a_file'], from_binary=True)
         self.factory = rulefactory.HieroCachingRuleFactory(
                 # compiled alignment object (REQUIRED)
@@ -99,13 +110,10 @@ class GrammarExtractor:
         return str(out)
 
 def main(config):
-    sys.path.append(os.path.dirname(config))
-    module =  __import__(os.path.basename(config).replace('.py', ''))
-    extractor = GrammarExtractor(module.__dict__)
-    print extractor.grammar(next(sys.stdin))
+    extractor = GrammarExtractor(config)
+    sys.stdout.write(extractor.grammar(next(sys.stdin)))
 
 if __name__ == '__main__':
-    import sys, os
     if len(sys.argv) != 2 or not sys.argv[1].endswith('.py'):
         sys.stderr.write('Usage: %s config.py\n' % sys.argv[0])
         sys.exit(1)
diff --git a/python/setup.py b/python/setup.py
index cc8b289d..701841a4 100644
--- a/python/setup.py
+++ b/python/setup.py
@@ -1,30 +1,50 @@
 from distutils.core import setup
 from distutils.extension import Extension
-from Cython.Distutils import build_ext
+import sys
 import os
+import glob
 
 INC = ['..', 'src/', '../decoder', '../utils', '../mteval']
 LIB = ['../decoder', '../utils', '../mteval', '../training', '../klm/lm', '../klm/util']
+LINK_ARGS = []
 
+# Detect Boost
 BOOST_ROOT = os.getenv('BOOST_ROOT')
 if BOOST_ROOT:
-    INC.append(os.path.join(BOOST_ROOT, 'include/'))
-    LIB.append(os.path.join(BOOST_ROOT, 'lib/'))
+    BOOST_INC = os.path.join(BOOST_ROOT, 'include')
+    BOOST_LIB = os.path.join(BOOST_ROOT, 'lib')
+    if not os.path.exists(BOOST_INC):
+        sys.stderr.write('Error: could not find Boost headers in <%s>\n' % BOOST_INC)
+        sys.exit(1)
+    if not os.path.exists(BOOST_LIB):
+        sys.stderr.write('Error: could not find Boost libraries in <%s>\n' % BOOST_LIB)
+        sys.exit(1)
+    INC.append(BOOST_INC)
+    LIB.append(BOOST_LIB)
+    LINK_ARGS += ['-Wl,-rpath', '-Wl,'+BOOST_LIB]
+else:
+    BOOST_LIB = '/usr/local/lib'
+
+# Detect -mt
+if glob.glob(os.path.join(BOOST_LIB, 'libboost_program_options-mt.*')):
+    BOOST_PROGRAM_OPTIONS = 'boost_program_options-mt'
+else:
+    BOOST_PROGRAM_OPTIONS = 'boost_program_options'
 
 ext_modules = [
     Extension(name='_cdec',
-        sources=['src/_cdec.pyx'],
+        sources=['src/_cdec.cpp'],
         language='C++', 
         include_dirs=INC,
         library_dirs=LIB,
-        libraries=['boost_program_options-mt', 'z',
+        libraries=[BOOST_PROGRAM_OPTIONS, 'z',
                    'cdec', 'utils', 'mteval', 'training', 'klm', 'klm_util'],
-        extra_compile_args=['-DHAVE_CONFIG_H']),
+        extra_compile_args=['-DHAVE_CONFIG_H'],
+        extra_link_args=LINK_ARGS),
 ]
 
 setup(
     name='cdec',
-    cmdclass={'build_ext': build_ext},
     ext_modules=ext_modules,
     packages=['cdec', 'cdec.scfg']
 )
diff --git a/python/src/_cdec.cpp b/python/src/_cdec.cpp
index e86dcf7b..3c95ca50 100644
--- a/python/src/_cdec.cpp
+++ b/python/src/_cdec.cpp
@@ -1,4 +1,4 @@
-/* Generated by Cython 0.16 on Wed Jul 11 16:05:22 2012 */
+/* Generated by Cython 0.16 on Fri Jul 20 18:16:48 2012 */
 
 #define PY_SSIZE_T_CLEAN
 #include "Python.h"
@@ -286,14 +286,16 @@
 #include "utils/sampler.h"
 #include <boost/shared_ptr.hpp>
 #include <boost/program_options.hpp>
-#include "decoder/lattice.h"
 #include "decoder/trule.h"
+#include "decoder/grammar.h"
+#include "decoder/lattice.h"
 #include "decoder/hg.h"
 #include "decoder/viterbi.h"
 #include "decoder/hg_io.h"
 #include "decoder/hg_intersect.h"
 #include "decoder/hg_sampler.h"
 #include "decoder/csplit.h"
+#include "decoder/inside_outside.h"
 #include "decoder/ff_register.h"
 #include "decoder/decoder.h"
 #include "observer.h"
@@ -384,57 +386,64 @@ static const char *__pyx_filename;
 static const char *__pyx_f[] = {
   "_cdec.pyx",
   "vectors.pxi",
+  "grammar.pxi",
   "hypergraph.pxi",
   "lattice.pxi",
-  "trule.pxi",
   "mteval.pxi",
 };
 
 /*--- Type declarations ---*/
 struct __pyx_obj_5_cdec_Scorer;
-struct __pyx_obj_5_cdec___pyx_scope_struct_20__make_config;
-struct __pyx_obj_5_cdec___pyx_scope_struct_22_genexpr;
-struct __pyx_obj_5_cdec___pyx_scope_struct_9_genexpr;
-struct __pyx_obj_5_cdec___pyx_scope_struct_10___str__;
+struct __pyx_obj_5_cdec_NTRef;
+struct __pyx_obj_5_cdec___pyx_scope_struct_23___cinit__;
+struct __pyx_obj_5_cdec___pyx_scope_struct_24_genexpr;
+struct __pyx_obj_5_cdec_Grammar;
 struct __pyx_obj_5_cdec___pyx_scope_struct_13___get__;
-struct __pyx_obj_5_cdec___pyx_scope_struct_15___iter__;
-struct __pyx_obj_5_cdec___pyx_scope_struct_7___get__;
+struct __pyx_obj_5_cdec___pyx_scope_struct_18_todot;
+struct __pyx_obj_5_cdec___pyx_scope_struct_2__phrase;
 struct __pyx_obj_5_cdec_CandidateSet;
 struct __pyx_obj_5_cdec___pyx_scope_struct_14___get__;
+struct __pyx_obj_5_cdec_BaseTRule;
 struct __pyx_obj_5_cdec_TRule;
-struct __pyx_obj_5_cdec___pyx_scope_struct_3_kbest_trees;
+struct __pyx_obj_5_cdec___pyx_scope_struct_3_genexpr;
 struct __pyx_obj_5_cdec_SegmentEvaluator;
-struct __pyx_obj_5_cdec___pyx_scope_struct_4_kbest_features;
-struct __pyx_obj_5_cdec___pyx_scope_struct_5_sample;
+struct __pyx_obj_5_cdec___pyx_scope_struct_20___iter__;
 struct __pyx_obj_5_cdec_Candidate;
-struct __pyx_obj_5_cdec___pyx_scope_struct_6___get__;
+struct __pyx_obj_5_cdec___pyx_scope_struct_6_genexpr;
+struct __pyx_obj_5_cdec_NT;
 struct __pyx_obj_5_cdec_HypergraphEdge;
 struct __pyx_obj_5_cdec___pyx_scope_struct_1___iter__;
-struct __pyx_obj_5_cdec___pyx_scope_struct_18___iter__;
+struct __pyx_obj_5_cdec___pyx_scope_struct_16___get__;
+struct __pyx_obj_5_cdec___pyx_scope_struct_4___get__;
 struct __pyx_obj_5_cdec_Decoder;
 struct __pyx_obj_5_cdec_HypergraphNode;
 struct __pyx_obj_5_cdec_SparseVector;
-struct __pyx_obj_5_cdec___pyx_scope_struct_11_genexpr;
+struct __pyx_obj_5_cdec___pyx_scope_struct_17___iter__;
 struct __pyx_obj_5_cdec___pyx_scope_struct_12___get__;
-struct __pyx_obj_5_cdec___pyx_scope_struct____iter__;
-struct __pyx_obj_5_cdec___pyx_scope_struct_2_kbest;
+struct __pyx_obj_5_cdec___pyx_scope_struct_21___iter__;
 struct __pyx_obj_5_cdec_DenseVector;
-struct __pyx_obj_5_cdec___pyx_scope_struct_17_lines;
+struct __pyx_obj_5_cdec___pyx_scope_struct_7___iter__;
 struct __pyx_obj_5_cdec_SufficientStats;
-struct __pyx_obj_5_cdec___pyx_scope_struct_16_todot;
+struct __pyx_obj_5_cdec___pyx_scope_struct_8_kbest;
+struct __pyx_obj_5_cdec___pyx_scope_struct_10_kbest_features;
+struct __pyx_obj_5_cdec___pyx_scope_struct_15___get__;
+struct __pyx_obj_5_cdec___pyx_scope_struct_5___str__;
+struct __pyx_obj_5_cdec___pyx_scope_struct_9_kbest_trees;
 struct __pyx_obj_5_cdec_Hypergraph;
 struct __pyx_obj_5_cdec_Lattice;
-struct __pyx_obj_5_cdec___pyx_scope_struct_8__phrase;
-struct __pyx_obj_5_cdec___pyx_scope_struct_21___cinit__;
-struct __pyx_obj_5_cdec___pyx_scope_struct_19___iter__;
+struct __pyx_obj_5_cdec___pyx_scope_struct_11_sample;
+struct __pyx_obj_5_cdec___pyx_scope_struct____iter__;
+struct __pyx_obj_5_cdec___pyx_scope_struct_22__make_config;
+struct __pyx_obj_5_cdec_TextGrammar;
+struct __pyx_obj_5_cdec___pyx_scope_struct_19_lines;
 struct __pyx_opt_args_5_cdec_as_str;
 
 /* "_cdec.pyx":6
  * cimport decoder
  * 
- * cdef char* as_str(sentence, error_msg='Cannot convert type %s to str'):             # <<<<<<<<<<<<<<
+ * cdef char* as_str(data, error_msg='Cannot convert type %s to str'):             # <<<<<<<<<<<<<<
  *     cdef bytes ret
- *     if isinstance(sentence, unicode):
+ *     if isinstance(data, unicode):
  */
 struct __pyx_opt_args_5_cdec_as_str {
   int __pyx_n;
@@ -454,39 +463,42 @@ struct __pyx_obj_5_cdec_Scorer {
 };
 
 
-/* "_cdec.pyx":27
- * class ParseFailed(Exception): pass
+/* "/Users/vchahun/Sandbox/cdec/python/src/grammar.pxi":18
+ *         return '[%s]' % self.cat
  * 
- * def _make_config(config):             # <<<<<<<<<<<<<<
- *     for key, value in config.items():
- *         if isinstance(value, dict):
+ * cdef class NTRef:             # <<<<<<<<<<<<<<
+ *     cdef public unsigned ref
+ *     def __init__(self, ref):
+ */
+struct __pyx_obj_5_cdec_NTRef {
+  PyObject_HEAD
+  unsigned int ref;
+};
+
+
+/* "_cdec.pyx":43
+ *     cdef DenseVector weights
+ * 
+ *     def __cinit__(self, config_str=None, **config):             # <<<<<<<<<<<<<<
+ *         """ Configuration can be given as a string:
+ *                 Decoder('formalism = scfg')
  */
-struct __pyx_obj_5_cdec___pyx_scope_struct_20__make_config {
+struct __pyx_obj_5_cdec___pyx_scope_struct_23___cinit__ {
   PyObject_HEAD
   PyObject *__pyx_v_config;
-  PyObject *__pyx_v_info;
-  PyObject *__pyx_v_key;
-  PyObject *__pyx_v_name;
-  PyObject *__pyx_v_value;
-  PyObject *__pyx_t_0;
-  PyObject *__pyx_t_1;
-  Py_ssize_t __pyx_t_2;
-  PyObject *(*__pyx_t_3)(PyObject *);
-  Py_ssize_t __pyx_t_4;
-  PyObject *(*__pyx_t_5)(PyObject *);
 };
 
 
-/* "_cdec.pyx":53
+/* "_cdec.pyx":54
  *                     'csplit', 'tagger', 'lexalign'):
  *                 raise InvalidConfig('formalism "%s" unknown' % formalism)
  *             config_str = '\n'.join('%s = %s' % kv for kv in _make_config(config))             # <<<<<<<<<<<<<<
  *         cdef istringstream* config_stream = new istringstream(config_str)
  *         self.dec = new decoder.Decoder(config_stream)
  */
-struct __pyx_obj_5_cdec___pyx_scope_struct_22_genexpr {
+struct __pyx_obj_5_cdec___pyx_scope_struct_24_genexpr {
   PyObject_HEAD
-  struct __pyx_obj_5_cdec___pyx_scope_struct_21___cinit__ *__pyx_outer_scope;
+  struct __pyx_obj_5_cdec___pyx_scope_struct_23___cinit__ *__pyx_outer_scope;
   PyObject *__pyx_v_kv;
   PyObject *__pyx_t_0;
   Py_ssize_t __pyx_t_1;
@@ -494,80 +506,58 @@ struct __pyx_obj_5_cdec___pyx_scope_struct_22_genexpr {
 };
 
 
-/* "/Users/vchahun/Sandbox/cdec/python/src/trule.pxi":2
- * def _phrase(phrase):
- *     return ' '.join('[%s,%d]' % w if isinstance(w, tuple) else w.encode('utf8') for w in phrase)             # <<<<<<<<<<<<<<
+/* "/Users/vchahun/Sandbox/cdec/python/src/grammar.pxi":146
+ *         self.rule.get().ComputeArity()
  * 
- * cdef class TRule:
- */
-struct __pyx_obj_5_cdec___pyx_scope_struct_9_genexpr {
-  PyObject_HEAD
-  struct __pyx_obj_5_cdec___pyx_scope_struct_8__phrase *__pyx_outer_scope;
-  PyObject *__pyx_v_w;
-  PyObject *__pyx_t_0;
-  Py_ssize_t __pyx_t_1;
-  PyObject *(*__pyx_t_2)(PyObject *);
-};
-
-
-/* "/Users/vchahun/Sandbox/cdec/python/src/trule.pxi":53
- *             return TDConvert(-self.rule.lhs_)
+ * cdef class Grammar:             # <<<<<<<<<<<<<<
+ *     cdef shared_ptr[grammar.Grammar]* grammar
  * 
- *     def __str__(self):             # <<<<<<<<<<<<<<
- *         scores = ' '.join('%s=%s' % feat for feat in self.scores)
- *         return '[%s] ||| %s ||| %s ||| %s' % (self.lhs, _phrase(self.f), _phrase(self.e), scores)
  */
-struct __pyx_obj_5_cdec___pyx_scope_struct_10___str__ {
+struct __pyx_obj_5_cdec_Grammar {
   PyObject_HEAD
-  struct __pyx_obj_5_cdec_TRule *__pyx_v_self;
+  boost::shared_ptr<Grammar> *grammar;
 };
 
 
-/* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":189
+/* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":119
  * 
- *     property in_edges:
+ *     property nodes:
  *         def __get__(self):             # <<<<<<<<<<<<<<
  *             cdef unsigned i
- *             for i in range(self.node.in_edges_.size()):
+ *             for i in range(self.hg.nodes_.size()):
  */
 struct __pyx_obj_5_cdec___pyx_scope_struct_13___get__ {
   PyObject_HEAD
   unsigned int __pyx_v_i;
-  struct __pyx_obj_5_cdec_HypergraphNode *__pyx_v_self;
+  struct __pyx_obj_5_cdec_Hypergraph *__pyx_v_self;
   size_t __pyx_t_0;
   unsigned int __pyx_t_1;
 };
 
 
-/* "/Users/vchahun/Sandbox/cdec/python/src/lattice.pxi":49
- *         return hypergraph.AsPLF(self.lattice[0], True).c_str()
+/* "/Users/vchahun/Sandbox/cdec/python/src/lattice.pxi":57
+ *         del self.lattice
  * 
- *     def __iter__(self):             # <<<<<<<<<<<<<<
- *         cdef unsigned i
- *         for i in range(len(self)):
+ *     def todot(self):             # <<<<<<<<<<<<<<
+ *         def lines():
+ *             yield 'digraph lattice {'
  */
-struct __pyx_obj_5_cdec___pyx_scope_struct_15___iter__ {
+struct __pyx_obj_5_cdec___pyx_scope_struct_18_todot {
   PyObject_HEAD
-  unsigned int __pyx_v_i;
   struct __pyx_obj_5_cdec_Lattice *__pyx_v_self;
-  Py_ssize_t __pyx_t_0;
-  unsigned int __pyx_t_1;
 };
 
 
-/* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":121
+/* "/Users/vchahun/Sandbox/cdec/python/src/grammar.pxi":3
+ * cimport grammar
+ * 
+ * def _phrase(phrase):             # <<<<<<<<<<<<<<
+ *     return ' '.join(w.encode('utf8') if isinstance(w, unicode) else str(w) for w in phrase)
  * 
- *     property nodes:
- *         def __get__(self):             # <<<<<<<<<<<<<<
- *             cdef unsigned i
- *             for i in range(self.hg.nodes_.size()):
  */
-struct __pyx_obj_5_cdec___pyx_scope_struct_7___get__ {
+struct __pyx_obj_5_cdec___pyx_scope_struct_2__phrase {
   PyObject_HEAD
-  unsigned int __pyx_v_i;
-  struct __pyx_obj_5_cdec_Hypergraph *__pyx_v_self;
-  size_t __pyx_t_0;
-  unsigned int __pyx_t_1;
+  PyObject *__pyx_v_phrase;
 };
 
 
@@ -586,55 +576,61 @@ struct __pyx_obj_5_cdec_CandidateSet {
 };
 
 
-/* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":195
+/* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":167
  * 
- *     property out_edges:
+ *     property tail_nodes:
  *         def __get__(self):             # <<<<<<<<<<<<<<
  *             cdef unsigned i
- *             for i in range(self.node.out_edges_.size()):
+ *             for i in range(self.edge.tail_nodes_.size()):
  */
 struct __pyx_obj_5_cdec___pyx_scope_struct_14___get__ {
   PyObject_HEAD
   unsigned int __pyx_v_i;
-  struct __pyx_obj_5_cdec_HypergraphNode *__pyx_v_self;
-  size_t __pyx_t_0;
+  struct __pyx_obj_5_cdec_HypergraphEdge *__pyx_v_self;
+  unsigned int __pyx_t_0;
   unsigned int __pyx_t_1;
 };
 
 
-/* "/Users/vchahun/Sandbox/cdec/python/src/trule.pxi":4
- *     return ' '.join('[%s,%d]' % w if isinstance(w, tuple) else w.encode('utf8') for w in phrase)
+/* "/Users/vchahun/Sandbox/cdec/python/src/grammar.pxi":26
+ *         return '[%d]' % self.ref
  * 
- * cdef class TRule:             # <<<<<<<<<<<<<<
- *     cdef hypergraph.TRule* rule
+ * cdef class BaseTRule:             # <<<<<<<<<<<<<<
+ *     cdef shared_ptr[grammar.TRule]* rule
  * 
  */
-struct __pyx_obj_5_cdec_TRule {
+struct __pyx_obj_5_cdec_BaseTRule {
   PyObject_HEAD
-  TRule *rule;
+  boost::shared_ptr<TRule> *rule;
 };
 
 
-/* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":43
- *             del derivations
+/* "/Users/vchahun/Sandbox/cdec/python/src/grammar.pxi":135
+ *                 _phrase(self.f), _phrase(self.e), scores)
  * 
- *     def kbest_trees(self, size):             # <<<<<<<<<<<<<<
- *         cdef kbest.KBestDerivations[vector[WordID], kbest.FTreeTraversal]* f_derivations = new kbest.KBestDerivations[vector[WordID], kbest.FTreeTraversal](self.hg[0], size)
- *         cdef kbest.KBestDerivations[vector[WordID], kbest.FTreeTraversal].Derivation* f_derivation
+ * cdef class TRule(BaseTRule):             # <<<<<<<<<<<<<<
+ *     def __cinit__(self, lhs, f, e, scores, a=None):
+ *         self.rule = new shared_ptr[grammar.TRule](new grammar.TRule())
+ */
+struct __pyx_obj_5_cdec_TRule {
+  struct __pyx_obj_5_cdec_BaseTRule __pyx_base;
+};
+
+
+/* "/Users/vchahun/Sandbox/cdec/python/src/grammar.pxi":4
+ * 
+ * def _phrase(phrase):
+ *     return ' '.join(w.encode('utf8') if isinstance(w, unicode) else str(w) for w in phrase)             # <<<<<<<<<<<<<<
+ * 
+ * cdef class NT:
  */
-struct __pyx_obj_5_cdec___pyx_scope_struct_3_kbest_trees {
+struct __pyx_obj_5_cdec___pyx_scope_struct_3_genexpr {
   PyObject_HEAD
-  KBest::KBestDerivations<std::vector<WordID>,ETreeTraversal>::Derivation *__pyx_v_e_derivation;
-  KBest::KBestDerivations<std::vector<WordID>,ETreeTraversal> *__pyx_v_e_derivations;
-  PyObject *__pyx_v_e_tree;
-  KBest::KBestDerivations<std::vector<WordID>,FTreeTraversal>::Derivation *__pyx_v_f_derivation;
-  KBest::KBestDerivations<std::vector<WordID>,FTreeTraversal> *__pyx_v_f_derivations;
-  PyObject *__pyx_v_f_tree;
-  unsigned int __pyx_v_k;
-  struct __pyx_obj_5_cdec_Hypergraph *__pyx_v_self;
-  PyObject *__pyx_v_size;
-  unsigned int __pyx_t_0;
-  long __pyx_t_1;
+  struct __pyx_obj_5_cdec___pyx_scope_struct_2__phrase *__pyx_outer_scope;
+  PyObject *__pyx_v_w;
+  PyObject *__pyx_t_0;
+  Py_ssize_t __pyx_t_1;
+  PyObject *(*__pyx_t_2)(PyObject *);
 };
 
 
@@ -652,41 +648,20 @@ struct __pyx_obj_5_cdec_SegmentEvaluator {
 };
 
 
-/* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":61
- *             del e_derivations
- * 
- *     def kbest_features(self, size):             # <<<<<<<<<<<<<<
- *         cdef kbest.KBestDerivations[FastSparseVector[weight_t], kbest.FeatureVectorTraversal]* derivations = new kbest.KBestDerivations[FastSparseVector[weight_t], kbest.FeatureVectorTraversal](self.hg[0], size)
- *         cdef kbest.KBestDerivations[FastSparseVector[weight_t], kbest.FeatureVectorTraversal].Derivation* derivation
- */
-struct __pyx_obj_5_cdec___pyx_scope_struct_4_kbest_features {
-  PyObject_HEAD
-  KBest::KBestDerivations<FastSparseVector<weight_t>,FeatureVectorTraversal>::Derivation *__pyx_v_derivation;
-  KBest::KBestDerivations<FastSparseVector<weight_t>,FeatureVectorTraversal> *__pyx_v_derivations;
-  struct __pyx_obj_5_cdec_SparseVector *__pyx_v_fmap;
-  unsigned int __pyx_v_k;
-  struct __pyx_obj_5_cdec_Hypergraph *__pyx_v_self;
-  PyObject *__pyx_v_size;
-  unsigned int __pyx_t_0;
-  long __pyx_t_1;
-};
-
-
-/* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":76
- *             del derivations
+/* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":44
+ *         return self.stats.size()
  * 
- *     def sample(self, unsigned n):             # <<<<<<<<<<<<<<
- *         cdef vector[hypergraph.Hypothesis]* hypos = new vector[hypergraph.Hypothesis]()
- *         if self.rng == NULL:
+ *     def __iter__(self):             # <<<<<<<<<<<<<<
+ *         for i in range(len(self)):
+ *             yield self.stats[0][i]
  */
-struct __pyx_obj_5_cdec___pyx_scope_struct_5_sample {
+struct __pyx_obj_5_cdec___pyx_scope_struct_20___iter__ {
   PyObject_HEAD
-  std::vector<HypergraphSampler::Hypothesis> *__pyx_v_hypos;
-  unsigned int __pyx_v_k;
-  unsigned int __pyx_v_n;
-  struct __pyx_obj_5_cdec_Hypergraph *__pyx_v_self;
-  size_t __pyx_t_0;
-  unsigned int __pyx_t_1;
+  PyObject *__pyx_v_i;
+  struct __pyx_obj_5_cdec_SufficientStats *__pyx_v_self;
+  Py_ssize_t __pyx_t_0;
+  PyObject *__pyx_t_1;
+  PyObject *(*__pyx_t_2)(PyObject *);
 };
 
 
@@ -704,24 +679,39 @@ struct __pyx_obj_5_cdec_Candidate {
 };
 
 
-/* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":115
+/* "/Users/vchahun/Sandbox/cdec/python/src/grammar.pxi":131
  * 
- *     property edges:
- *         def __get__(self):             # <<<<<<<<<<<<<<
- *             cdef unsigned i
- *             for i in range(self.hg.edges_.size()):
+ *     def __str__(self):
+ *         scores = ' '.join('%s=%s' % feat for feat in self.scores)             # <<<<<<<<<<<<<<
+ *         return '%s ||| %s ||| %s ||| %s' % (self.lhs,
+ *                 _phrase(self.f), _phrase(self.e), scores)
  */
-struct __pyx_obj_5_cdec___pyx_scope_struct_6___get__ {
+struct __pyx_obj_5_cdec___pyx_scope_struct_6_genexpr {
   PyObject_HEAD
-  unsigned int __pyx_v_i;
-  struct __pyx_obj_5_cdec_Hypergraph *__pyx_v_self;
-  size_t __pyx_t_0;
-  unsigned int __pyx_t_1;
+  struct __pyx_obj_5_cdec___pyx_scope_struct_5___str__ *__pyx_outer_scope;
+  PyObject *__pyx_v_feat;
+  PyObject *__pyx_t_0;
+  Py_ssize_t __pyx_t_1;
+  PyObject *(*__pyx_t_2)(PyObject *);
+};
+
+
+/* "/Users/vchahun/Sandbox/cdec/python/src/grammar.pxi":6
+ *     return ' '.join(w.encode('utf8') if isinstance(w, unicode) else str(w) for w in phrase)
+ * 
+ * cdef class NT:             # <<<<<<<<<<<<<<
+ *     cdef public char* cat
+ *     cdef public unsigned ref
+ */
+struct __pyx_obj_5_cdec_NT {
+  PyObject_HEAD
+  char *cat;
+  unsigned int ref;
 };
 
 
-/* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":133
- * include "trule.pxi"
+/* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":147
+ *         return vector
  * 
  * cdef class HypergraphEdge:             # <<<<<<<<<<<<<<
  *     cdef hypergraph.Hypergraph* hg
@@ -732,7 +722,7 @@ struct __pyx_obj_5_cdec_HypergraphEdge {
   struct __pyx_vtabstruct_5_cdec_HypergraphEdge *__pyx_vtab;
   Hypergraph *hg;
   const Hypergraph::Edge *edge;
-  struct __pyx_obj_5_cdec_TRule *trule;
+  struct __pyx_obj_5_cdec_BaseTRule *trule;
 };
 
 
@@ -741,36 +731,52 @@ struct __pyx_obj_5_cdec_HypergraphEdge {
  * 
  *     def __iter__(self):             # <<<<<<<<<<<<<<
  *         cdef FastSparseVector[weight_t].const_iterator* it = new FastSparseVector[weight_t].const_iterator(self.vector[0], False)
- *         try:
+ *         cdef unsigned i
  */
 struct __pyx_obj_5_cdec___pyx_scope_struct_1___iter__ {
   PyObject_HEAD
-  size_t __pyx_v_i;
+  unsigned int __pyx_v_i;
   FastSparseVector<weight_t>::const_iterator *__pyx_v_it;
   struct __pyx_obj_5_cdec_SparseVector *__pyx_v_self;
   size_t __pyx_t_0;
-  size_t __pyx_t_1;
+  unsigned int __pyx_t_1;
 };
 
 
-/* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":44
- *         return self.stats.size()
+/* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":209
  * 
- *     def __iter__(self):             # <<<<<<<<<<<<<<
- *         for i in range(len(self)):
- *             yield self.stats[0][i]
+ *     property out_edges:
+ *         def __get__(self):             # <<<<<<<<<<<<<<
+ *             cdef unsigned i
+ *             for i in range(self.node.out_edges_.size()):
  */
-struct __pyx_obj_5_cdec___pyx_scope_struct_18___iter__ {
+struct __pyx_obj_5_cdec___pyx_scope_struct_16___get__ {
   PyObject_HEAD
-  PyObject *__pyx_v_i;
-  struct __pyx_obj_5_cdec_SufficientStats *__pyx_v_self;
-  Py_ssize_t __pyx_t_0;
-  PyObject *__pyx_t_1;
-  PyObject *(*__pyx_t_2)(PyObject *);
+  unsigned int __pyx_v_i;
+  struct __pyx_obj_5_cdec_HypergraphNode *__pyx_v_self;
+  size_t __pyx_t_0;
+  unsigned int __pyx_t_1;
+};
+
+
+/* "/Users/vchahun/Sandbox/cdec/python/src/grammar.pxi":90
+ * 
+ *     property a:
+ *         def __get__(self):             # <<<<<<<<<<<<<<
+ *             cdef unsigned i
+ *             cdef vector[grammar.AlignmentPoint]* a = &self.rule.get().a_
+ */
+struct __pyx_obj_5_cdec___pyx_scope_struct_4___get__ {
+  PyObject_HEAD
+  std::vector<AlignmentPoint> *__pyx_v_a;
+  unsigned int __pyx_v_i;
+  struct __pyx_obj_5_cdec_BaseTRule *__pyx_v_self;
+  size_t __pyx_t_0;
+  unsigned int __pyx_t_1;
 };
 
 
-/* "_cdec.pyx":38
+/* "_cdec.pyx":39
  *             yield key, bytes(value)
  * 
  * cdef class Decoder:             # <<<<<<<<<<<<<<
@@ -784,7 +790,7 @@ struct __pyx_obj_5_cdec_Decoder {
 };
 
 
-/* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":179
+/* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":193
  *         raise NotImplemented('comparison not implemented for HypergraphEdge')
  * 
  * cdef class HypergraphNode:             # <<<<<<<<<<<<<<
@@ -812,106 +818,83 @@ struct __pyx_obj_5_cdec_SparseVector {
 };
 
 
-/* "/Users/vchahun/Sandbox/cdec/python/src/trule.pxi":54
+/* "/Users/vchahun/Sandbox/cdec/python/src/lattice.pxi":49
+ *         return hypergraph.AsPLF(self.lattice[0], True).c_str()
  * 
- *     def __str__(self):
- *         scores = ' '.join('%s=%s' % feat for feat in self.scores)             # <<<<<<<<<<<<<<
- *         return '[%s] ||| %s ||| %s ||| %s' % (self.lhs, _phrase(self.f), _phrase(self.e), scores)
+ *     def __iter__(self):             # <<<<<<<<<<<<<<
+ *         cdef unsigned i
+ *         for i in range(len(self)):
  */
-struct __pyx_obj_5_cdec___pyx_scope_struct_11_genexpr {
+struct __pyx_obj_5_cdec___pyx_scope_struct_17___iter__ {
   PyObject_HEAD
-  struct __pyx_obj_5_cdec___pyx_scope_struct_10___str__ *__pyx_outer_scope;
-  PyObject *__pyx_v_feat;
-  PyObject *__pyx_t_0;
-  Py_ssize_t __pyx_t_1;
-  PyObject *(*__pyx_t_2)(PyObject *);
+  unsigned int __pyx_v_i;
+  struct __pyx_obj_5_cdec_Lattice *__pyx_v_self;
+  Py_ssize_t __pyx_t_0;
+  unsigned int __pyx_t_1;
 };
 
 
-/* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":153
+/* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":113
  * 
- *     property tail_nodes:
+ *     property edges:
  *         def __get__(self):             # <<<<<<<<<<<<<<
  *             cdef unsigned i
- *             for i in range(self.edge.tail_nodes_.size()):
+ *             for i in range(self.hg.edges_.size()):
  */
 struct __pyx_obj_5_cdec___pyx_scope_struct_12___get__ {
   PyObject_HEAD
   unsigned int __pyx_v_i;
-  struct __pyx_obj_5_cdec_HypergraphEdge *__pyx_v_self;
-  unsigned int __pyx_t_0;
+  struct __pyx_obj_5_cdec_Hypergraph *__pyx_v_self;
+  size_t __pyx_t_0;
   unsigned int __pyx_t_1;
 };
 
 
-/* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":22
- *         self.vector[0][fid] = value
+/* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":85
+ *         return candidate
  * 
  *     def __iter__(self):             # <<<<<<<<<<<<<<
- *         cdef unsigned fid
- *         for fid in range(1, self.vector.size()):
+ *         cdef unsigned i
+ *         for i in range(len(self)):
  */
-struct __pyx_obj_5_cdec___pyx_scope_struct____iter__ {
+struct __pyx_obj_5_cdec___pyx_scope_struct_21___iter__ {
   PyObject_HEAD
-  unsigned int __pyx_v_fid;
-  struct __pyx_obj_5_cdec_DenseVector *__pyx_v_self;
-  size_t __pyx_t_0;
+  unsigned int __pyx_v_i;
+  struct __pyx_obj_5_cdec_CandidateSet *__pyx_v_self;
+  Py_ssize_t __pyx_t_0;
   unsigned int __pyx_t_1;
 };
 
 
-/* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":31
- *         return unicode(hypergraph.JoshuaVisualizationString(self.hg[0]).c_str(), 'utf8')
+/* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":3
+ * from cython.operator cimport preincrement as pinc
+ * 
+ * cdef class DenseVector:             # <<<<<<<<<<<<<<
+ *     cdef vector[weight_t]* vector # Not owned by DenseVector
  * 
- *     def kbest(self, size):             # <<<<<<<<<<<<<<
- *         cdef kbest.KBestDerivations[vector[WordID], kbest.ESentenceTraversal]* derivations = new kbest.KBestDerivations[vector[WordID], kbest.ESentenceTraversal](self.hg[0], size)
- *         cdef kbest.KBestDerivations[vector[WordID], kbest.ESentenceTraversal].Derivation* derivation
  */
-struct __pyx_obj_5_cdec___pyx_scope_struct_2_kbest {
-  PyObject_HEAD
-  KBest::KBestDerivations<std::vector<WordID>,ESentenceTraversal>::Derivation *__pyx_v_derivation;
-  KBest::KBestDerivations<std::vector<WordID>,ESentenceTraversal> *__pyx_v_derivations;
-  unsigned int __pyx_v_k;
-  struct __pyx_obj_5_cdec_Hypergraph *__pyx_v_self;
-  PyObject *__pyx_v_size;
-  unsigned int __pyx_t_0;
-  long __pyx_t_1;
-};
-
-
-/* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":3
- * from cython.operator cimport preincrement as pinc
- * 
- * cdef class DenseVector:             # <<<<<<<<<<<<<<
- *     cdef vector[weight_t]* vector # Not owned by DenseVector
- * 
- */
-struct __pyx_obj_5_cdec_DenseVector {
+struct __pyx_obj_5_cdec_DenseVector {
   PyObject_HEAD
   std::vector<weight_t> *vector;
 };
 
 
-/* "/Users/vchahun/Sandbox/cdec/python/src/lattice.pxi":58
+/* "/Users/vchahun/Sandbox/cdec/python/src/grammar.pxi":152
+ *         del self.grammar
  * 
- *     def todot(self):
- *         def lines():             # <<<<<<<<<<<<<<
- *             yield 'digraph lattice {'
- *             yield 'rankdir = LR;'
+ *     def __iter__(self):             # <<<<<<<<<<<<<<
+ *         cdef grammar.GrammarIter* root = self.grammar.get().GetRoot()
+ *         cdef grammar.RuleBin* rbin = root.GetRules()
  */
-struct __pyx_obj_5_cdec___pyx_scope_struct_17_lines {
+struct __pyx_obj_5_cdec___pyx_scope_struct_7___iter__ {
   PyObject_HEAD
-  struct __pyx_obj_5_cdec___pyx_scope_struct_16_todot *__pyx_outer_scope;
-  PyObject *__pyx_v_delta;
-  PyObject *__pyx_v_i;
-  PyObject *__pyx_v_label;
-  PyObject *__pyx_v_weight;
-  Py_ssize_t __pyx_t_0;
-  PyObject *__pyx_t_1;
-  PyObject *(*__pyx_t_2)(PyObject *);
-  PyObject *__pyx_t_3;
-  Py_ssize_t __pyx_t_4;
-  PyObject *(*__pyx_t_5)(PyObject *);
+  unsigned int __pyx_v_i;
+  const RuleBin *__pyx_v_rbin;
+  const GrammarIter *__pyx_v_root;
+  struct __pyx_obj_5_cdec_Grammar *__pyx_v_self;
+  struct __pyx_obj_5_cdec_TRule *__pyx_v_trule;
+  int __pyx_t_0;
+  unsigned int __pyx_t_1;
 };
 
 
@@ -929,16 +912,94 @@ struct __pyx_obj_5_cdec_SufficientStats {
 };
 
 
-/* "/Users/vchahun/Sandbox/cdec/python/src/lattice.pxi":57
- *         del self.lattice
+/* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":31
+ *         return unicode(hypergraph.JoshuaVisualizationString(self.hg[0]).c_str(), 'utf8')
  * 
- *     def todot(self):             # <<<<<<<<<<<<<<
- *         def lines():
- *             yield 'digraph lattice {'
+ *     def kbest(self, size):             # <<<<<<<<<<<<<<
+ *         cdef kbest.KBestDerivations[vector[WordID], kbest.ESentenceTraversal]* derivations = new kbest.KBestDerivations[vector[WordID], kbest.ESentenceTraversal](self.hg[0], size)
+ *         cdef kbest.KBestDerivations[vector[WordID], kbest.ESentenceTraversal].Derivation* derivation
  */
-struct __pyx_obj_5_cdec___pyx_scope_struct_16_todot {
+struct __pyx_obj_5_cdec___pyx_scope_struct_8_kbest {
   PyObject_HEAD
-  struct __pyx_obj_5_cdec_Lattice *__pyx_v_self;
+  KBest::KBestDerivations<std::vector<WordID>,ESentenceTraversal>::Derivation *__pyx_v_derivation;
+  KBest::KBestDerivations<std::vector<WordID>,ESentenceTraversal> *__pyx_v_derivations;
+  unsigned int __pyx_v_k;
+  struct __pyx_obj_5_cdec_Hypergraph *__pyx_v_self;
+  PyObject *__pyx_v_size;
+  unsigned int __pyx_t_0;
+  long __pyx_t_1;
+};
+
+
+/* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":61
+ *             del e_derivations
+ * 
+ *     def kbest_features(self, size):             # <<<<<<<<<<<<<<
+ *         cdef kbest.KBestDerivations[FastSparseVector[weight_t], kbest.FeatureVectorTraversal]* derivations = new kbest.KBestDerivations[FastSparseVector[weight_t], kbest.FeatureVectorTraversal](self.hg[0], size)
+ *         cdef kbest.KBestDerivations[FastSparseVector[weight_t], kbest.FeatureVectorTraversal].Derivation* derivation
+ */
+struct __pyx_obj_5_cdec___pyx_scope_struct_10_kbest_features {
+  PyObject_HEAD
+  KBest::KBestDerivations<FastSparseVector<weight_t>,FeatureVectorTraversal>::Derivation *__pyx_v_derivation;
+  KBest::KBestDerivations<FastSparseVector<weight_t>,FeatureVectorTraversal> *__pyx_v_derivations;
+  struct __pyx_obj_5_cdec_SparseVector *__pyx_v_fmap;
+  unsigned int __pyx_v_k;
+  struct __pyx_obj_5_cdec_Hypergraph *__pyx_v_self;
+  PyObject *__pyx_v_size;
+  unsigned int __pyx_t_0;
+  long __pyx_t_1;
+};
+
+
+/* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":203
+ * 
+ *     property in_edges:
+ *         def __get__(self):             # <<<<<<<<<<<<<<
+ *             cdef unsigned i
+ *             for i in range(self.node.in_edges_.size()):
+ */
+struct __pyx_obj_5_cdec___pyx_scope_struct_15___get__ {
+  PyObject_HEAD
+  unsigned int __pyx_v_i;
+  struct __pyx_obj_5_cdec_HypergraphNode *__pyx_v_self;
+  size_t __pyx_t_0;
+  unsigned int __pyx_t_1;
+};
+
+
+/* "/Users/vchahun/Sandbox/cdec/python/src/grammar.pxi":130
+ *             self.rule.get().lhs_ = -TDConvert(<char *>lhs.cat)
+ * 
+ *     def __str__(self):             # <<<<<<<<<<<<<<
+ *         scores = ' '.join('%s=%s' % feat for feat in self.scores)
+ *         return '%s ||| %s ||| %s ||| %s' % (self.lhs,
+ */
+struct __pyx_obj_5_cdec___pyx_scope_struct_5___str__ {
+  PyObject_HEAD
+  struct __pyx_obj_5_cdec_BaseTRule *__pyx_v_self;
+};
+
+
+/* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":43
+ *             del derivations
+ * 
+ *     def kbest_trees(self, size):             # <<<<<<<<<<<<<<
+ *         cdef kbest.KBestDerivations[vector[WordID], kbest.FTreeTraversal]* f_derivations = new kbest.KBestDerivations[vector[WordID], kbest.FTreeTraversal](self.hg[0], size)
+ *         cdef kbest.KBestDerivations[vector[WordID], kbest.FTreeTraversal].Derivation* f_derivation
+ */
+struct __pyx_obj_5_cdec___pyx_scope_struct_9_kbest_trees {
+  PyObject_HEAD
+  KBest::KBestDerivations<std::vector<WordID>,ETreeTraversal>::Derivation *__pyx_v_e_derivation;
+  KBest::KBestDerivations<std::vector<WordID>,ETreeTraversal> *__pyx_v_e_derivations;
+  PyObject *__pyx_v_e_tree;
+  KBest::KBestDerivations<std::vector<WordID>,FTreeTraversal>::Derivation *__pyx_v_f_derivation;
+  KBest::KBestDerivations<std::vector<WordID>,FTreeTraversal> *__pyx_v_f_derivations;
+  PyObject *__pyx_v_f_tree;
+  unsigned int __pyx_v_k;
+  struct __pyx_obj_5_cdec_Hypergraph *__pyx_v_self;
+  PyObject *__pyx_v_size;
+  unsigned int __pyx_t_0;
+  long __pyx_t_1;
 };
 
 
@@ -969,48 +1030,100 @@ struct __pyx_obj_5_cdec_Lattice {
 };
 
 
-/* "/Users/vchahun/Sandbox/cdec/python/src/trule.pxi":1
- * def _phrase(phrase):             # <<<<<<<<<<<<<<
- *     return ' '.join('[%s,%d]' % w if isinstance(w, tuple) else w.encode('utf8') for w in phrase)
+/* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":76
+ *             del derivations
  * 
+ *     def sample(self, unsigned n):             # <<<<<<<<<<<<<<
+ *         cdef vector[hypergraph.Hypothesis]* hypos = new vector[hypergraph.Hypothesis]()
+ *         if self.rng == NULL:
  */
-struct __pyx_obj_5_cdec___pyx_scope_struct_8__phrase {
+struct __pyx_obj_5_cdec___pyx_scope_struct_11_sample {
   PyObject_HEAD
-  PyObject *__pyx_v_phrase;
+  std::vector<HypergraphSampler::Hypothesis> *__pyx_v_hypos;
+  unsigned int __pyx_v_k;
+  unsigned int __pyx_v_n;
+  struct __pyx_obj_5_cdec_Hypergraph *__pyx_v_self;
+  size_t __pyx_t_0;
+  unsigned int __pyx_t_1;
 };
 
 
-/* "_cdec.pyx":42
- *     cdef DenseVector weights
+/* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":22
+ *         self.vector[0][fid] = value
  * 
- *     def __cinit__(self, config_str=None, **config):             # <<<<<<<<<<<<<<
- *         """ Configuration can be given as a string:
- *                 Decoder('formalism = scfg')
+ *     def __iter__(self):             # <<<<<<<<<<<<<<
+ *         cdef unsigned fid
+ *         for fid in range(1, self.vector.size()):
+ */
+struct __pyx_obj_5_cdec___pyx_scope_struct____iter__ {
+  PyObject_HEAD
+  unsigned int __pyx_v_fid;
+  struct __pyx_obj_5_cdec_DenseVector *__pyx_v_self;
+  size_t __pyx_t_0;
+  unsigned int __pyx_t_1;
+};
+
+
+/* "_cdec.pyx":28
+ * class ParseFailed(Exception): pass
+ * 
+ * def _make_config(config):             # <<<<<<<<<<<<<<
+ *     for key, value in config.items():
+ *         if isinstance(value, dict):
  */
-struct __pyx_obj_5_cdec___pyx_scope_struct_21___cinit__ {
+struct __pyx_obj_5_cdec___pyx_scope_struct_22__make_config {
   PyObject_HEAD
   PyObject *__pyx_v_config;
+  PyObject *__pyx_v_info;
+  PyObject *__pyx_v_key;
+  PyObject *__pyx_v_name;
+  PyObject *__pyx_v_value;
+  PyObject *__pyx_t_0;
+  PyObject *__pyx_t_1;
+  Py_ssize_t __pyx_t_2;
+  PyObject *(*__pyx_t_3)(PyObject *);
+  Py_ssize_t __pyx_t_4;
+  PyObject *(*__pyx_t_5)(PyObject *);
 };
 
 
-/* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":85
- *         return candidate
+/* "/Users/vchahun/Sandbox/cdec/python/src/grammar.pxi":169
+ *             self.grammar.get().SetGrammarName(string(<char *>name))
  * 
- *     def __iter__(self):             # <<<<<<<<<<<<<<
- *         cdef unsigned i
- *         for i in range(len(self)):
+ * cdef class TextGrammar(Grammar):             # <<<<<<<<<<<<<<
+ *     def __cinit__(self, rules):
+ *         self.grammar = new shared_ptr[grammar.Grammar](new grammar.TextGrammar())
+ */
+struct __pyx_obj_5_cdec_TextGrammar {
+  struct __pyx_obj_5_cdec_Grammar __pyx_base;
+};
+
+
+/* "/Users/vchahun/Sandbox/cdec/python/src/lattice.pxi":58
+ * 
+ *     def todot(self):
+ *         def lines():             # <<<<<<<<<<<<<<
+ *             yield 'digraph lattice {'
+ *             yield 'rankdir = LR;'
  */
-struct __pyx_obj_5_cdec___pyx_scope_struct_19___iter__ {
+struct __pyx_obj_5_cdec___pyx_scope_struct_19_lines {
   PyObject_HEAD
-  unsigned int __pyx_v_i;
-  struct __pyx_obj_5_cdec_CandidateSet *__pyx_v_self;
+  struct __pyx_obj_5_cdec___pyx_scope_struct_18_todot *__pyx_outer_scope;
+  PyObject *__pyx_v_delta;
+  PyObject *__pyx_v_i;
+  PyObject *__pyx_v_label;
+  PyObject *__pyx_v_weight;
   Py_ssize_t __pyx_t_0;
-  unsigned int __pyx_t_1;
+  PyObject *__pyx_t_1;
+  PyObject *(*__pyx_t_2)(PyObject *);
+  PyObject *__pyx_t_3;
+  Py_ssize_t __pyx_t_4;
+  PyObject *(*__pyx_t_5)(PyObject *);
 };
 
 
 
-/* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":179
+/* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":193
  *         raise NotImplemented('comparison not implemented for HypergraphEdge')
  * 
  * cdef class HypergraphNode:             # <<<<<<<<<<<<<<
@@ -1024,8 +1137,8 @@ struct __pyx_vtabstruct_5_cdec_HypergraphNode {
 static struct __pyx_vtabstruct_5_cdec_HypergraphNode *__pyx_vtabptr_5_cdec_HypergraphNode;
 
 
-/* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":133
- * include "trule.pxi"
+/* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":147
+ *         return vector
  * 
  * cdef class HypergraphEdge:             # <<<<<<<<<<<<<<
  *     cdef hypergraph.Hypergraph* hg
@@ -1102,6 +1215,8 @@ static int __Pyx_ArgTypeTest(PyObject *obj, PyTypeObject *type, int none_allowed
 
 static CYTHON_INLINE int __Pyx_TypeTest(PyObject *obj, PyTypeObject *type); /*proto*/
 
+static CYTHON_INLINE void __Pyx_RaiseClosureNameError(const char *varname);
+
 static void __Pyx_RaiseDoubleKeywordsError(const char* func_name, PyObject* kw_name); /*proto*/
 
 static int __Pyx_ParseOptionalKeywords(PyObject *kwds, PyObject **argnames[], \
@@ -1111,15 +1226,6 @@ static int __Pyx_ParseOptionalKeywords(PyObject *kwds, PyObject **argnames[], \
 static void __Pyx_RaiseArgtupleInvalid(const char* func_name, int exact,
     Py_ssize_t num_min, Py_ssize_t num_max, Py_ssize_t num_found); /*proto*/
 
-static CYTHON_INLINE int __Pyx_NegateNonNeg(int b) {
-    return unlikely(b < 0) ? b : !b;
-}
-static CYTHON_INLINE PyObject* __Pyx_PyBoolOrNull_FromLong(long b) {
-    return unlikely(b < 0) ? NULL : __Pyx_PyBool_FromLong(b);
-}
-
-static CYTHON_INLINE void __Pyx_RaiseClosureNameError(const char *varname);
-
 static CYTHON_INLINE PyObject* __Pyx_PyObject_Append(PyObject* L, PyObject* x) {
     if (likely(PyList_CheckExact(L))) {
         if (PyList_Append(L, x) < 0) return NULL;
@@ -1136,15 +1242,6 @@ static CYTHON_INLINE PyObject* __Pyx_PyObject_Append(PyObject* L, PyObject* x) {
     }
 }
 
-#define __Pyx_PyIter_Next(obj) __Pyx_PyIter_Next2(obj, NULL);
-static CYTHON_INLINE PyObject *__Pyx_PyIter_Next2(PyObject *, PyObject *); /*proto*/
-
-static CYTHON_INLINE void __Pyx_RaiseNeedMoreValuesError(Py_ssize_t index);
-
-static CYTHON_INLINE void __Pyx_RaiseTooManyValuesError(Py_ssize_t expected);
-
-static int __Pyx_IternextUnpackEndCheck(PyObject *retval, Py_ssize_t expected); /*proto*/
-
 static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Generic(PyObject *o, PyObject* j) {
     PyObject *r;
     if (!j) return NULL;
@@ -1217,6 +1314,22 @@ static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Fast(PyObject *o, Py_ssize_t i)
     return __Pyx_GetItemInt_Generic(o, PyInt_FromSsize_t(i));
 }
 
+static CYTHON_INLINE void __Pyx_RaiseNeedMoreValuesError(Py_ssize_t index);
+
+static CYTHON_INLINE void __Pyx_RaiseTooManyValuesError(Py_ssize_t expected);
+
+static int __Pyx_IternextUnpackEndCheck(PyObject *retval, Py_ssize_t expected); /*proto*/
+
+static CYTHON_INLINE int __Pyx_NegateNonNeg(int b) {
+    return unlikely(b < 0) ? b : !b;
+}
+static CYTHON_INLINE PyObject* __Pyx_PyBoolOrNull_FromLong(long b) {
+    return unlikely(b < 0) ? NULL : __Pyx_PyBool_FromLong(b);
+}
+
+#define __Pyx_PyIter_Next(obj) __Pyx_PyIter_Next2(obj, NULL);
+static CYTHON_INLINE PyObject *__Pyx_PyIter_Next2(PyObject *, PyObject *); /*proto*/
+
 static double __Pyx__PyObject_AsDouble(PyObject* obj); /* proto */
 #define __Pyx_PyObject_AsDouble(obj) \
 ((likely(PyFloat_CheckExact(obj))) ? \
@@ -1232,6 +1345,8 @@ static PyObject *__Pyx_FindPy2Metaclass(PyObject *bases); /*proto*/
 static PyObject *__Pyx_CreateClass(PyObject *bases, PyObject *dict, PyObject *name,
                                    PyObject *modname); /*proto*/
 
+static CYTHON_INLINE WordID __Pyx_PyInt_from_py_WordID(PyObject *);
+
 static PyObject* __Pyx_Globals(void); /*proto*/
 
 #define __Pyx_CyFunction_USED 1
@@ -1378,6 +1493,8 @@ static int __Pyx_InitStrings(__Pyx_StringTabEntry *t); /*proto*/
 
 /* Module declarations from 'utils' */
 
+/* Module declarations from 'grammar' */
+
 /* Module declarations from 'lattice' */
 
 /* Module declarations from 'hypergraph' */
@@ -1391,8 +1508,13 @@ static int __Pyx_InitStrings(__Pyx_StringTabEntry *t); /*proto*/
 /* Module declarations from '_cdec' */
 static PyTypeObject *__pyx_ptype_5_cdec_DenseVector = 0;
 static PyTypeObject *__pyx_ptype_5_cdec_SparseVector = 0;
-static PyTypeObject *__pyx_ptype_5_cdec_Hypergraph = 0;
+static PyTypeObject *__pyx_ptype_5_cdec_NT = 0;
+static PyTypeObject *__pyx_ptype_5_cdec_NTRef = 0;
+static PyTypeObject *__pyx_ptype_5_cdec_BaseTRule = 0;
 static PyTypeObject *__pyx_ptype_5_cdec_TRule = 0;
+static PyTypeObject *__pyx_ptype_5_cdec_Grammar = 0;
+static PyTypeObject *__pyx_ptype_5_cdec_TextGrammar = 0;
+static PyTypeObject *__pyx_ptype_5_cdec_Hypergraph = 0;
 static PyTypeObject *__pyx_ptype_5_cdec_HypergraphEdge = 0;
 static PyTypeObject *__pyx_ptype_5_cdec_HypergraphNode = 0;
 static PyTypeObject *__pyx_ptype_5_cdec_Lattice = 0;
@@ -1404,27 +1526,29 @@ static PyTypeObject *__pyx_ptype_5_cdec_Scorer = 0;
 static PyTypeObject *__pyx_ptype_5_cdec_Decoder = 0;
 static PyTypeObject *__pyx_ptype_5_cdec___pyx_scope_struct____iter__ = 0;
 static PyTypeObject *__pyx_ptype_5_cdec___pyx_scope_struct_1___iter__ = 0;
-static PyTypeObject *__pyx_ptype_5_cdec___pyx_scope_struct_2_kbest = 0;
-static PyTypeObject *__pyx_ptype_5_cdec___pyx_scope_struct_3_kbest_trees = 0;
-static PyTypeObject *__pyx_ptype_5_cdec___pyx_scope_struct_4_kbest_features = 0;
-static PyTypeObject *__pyx_ptype_5_cdec___pyx_scope_struct_5_sample = 0;
-static PyTypeObject *__pyx_ptype_5_cdec___pyx_scope_struct_6___get__ = 0;
-static PyTypeObject *__pyx_ptype_5_cdec___pyx_scope_struct_7___get__ = 0;
-static PyTypeObject *__pyx_ptype_5_cdec___pyx_scope_struct_8__phrase = 0;
-static PyTypeObject *__pyx_ptype_5_cdec___pyx_scope_struct_9_genexpr = 0;
-static PyTypeObject *__pyx_ptype_5_cdec___pyx_scope_struct_10___str__ = 0;
-static PyTypeObject *__pyx_ptype_5_cdec___pyx_scope_struct_11_genexpr = 0;
+static PyTypeObject *__pyx_ptype_5_cdec___pyx_scope_struct_2__phrase = 0;
+static PyTypeObject *__pyx_ptype_5_cdec___pyx_scope_struct_3_genexpr = 0;
+static PyTypeObject *__pyx_ptype_5_cdec___pyx_scope_struct_4___get__ = 0;
+static PyTypeObject *__pyx_ptype_5_cdec___pyx_scope_struct_5___str__ = 0;
+static PyTypeObject *__pyx_ptype_5_cdec___pyx_scope_struct_6_genexpr = 0;
+static PyTypeObject *__pyx_ptype_5_cdec___pyx_scope_struct_7___iter__ = 0;
+static PyTypeObject *__pyx_ptype_5_cdec___pyx_scope_struct_8_kbest = 0;
+static PyTypeObject *__pyx_ptype_5_cdec___pyx_scope_struct_9_kbest_trees = 0;
+static PyTypeObject *__pyx_ptype_5_cdec___pyx_scope_struct_10_kbest_features = 0;
+static PyTypeObject *__pyx_ptype_5_cdec___pyx_scope_struct_11_sample = 0;
 static PyTypeObject *__pyx_ptype_5_cdec___pyx_scope_struct_12___get__ = 0;
 static PyTypeObject *__pyx_ptype_5_cdec___pyx_scope_struct_13___get__ = 0;
 static PyTypeObject *__pyx_ptype_5_cdec___pyx_scope_struct_14___get__ = 0;
-static PyTypeObject *__pyx_ptype_5_cdec___pyx_scope_struct_15___iter__ = 0;
-static PyTypeObject *__pyx_ptype_5_cdec___pyx_scope_struct_16_todot = 0;
-static PyTypeObject *__pyx_ptype_5_cdec___pyx_scope_struct_17_lines = 0;
-static PyTypeObject *__pyx_ptype_5_cdec___pyx_scope_struct_18___iter__ = 0;
-static PyTypeObject *__pyx_ptype_5_cdec___pyx_scope_struct_19___iter__ = 0;
-static PyTypeObject *__pyx_ptype_5_cdec___pyx_scope_struct_20__make_config = 0;
-static PyTypeObject *__pyx_ptype_5_cdec___pyx_scope_struct_21___cinit__ = 0;
-static PyTypeObject *__pyx_ptype_5_cdec___pyx_scope_struct_22_genexpr = 0;
+static PyTypeObject *__pyx_ptype_5_cdec___pyx_scope_struct_15___get__ = 0;
+static PyTypeObject *__pyx_ptype_5_cdec___pyx_scope_struct_16___get__ = 0;
+static PyTypeObject *__pyx_ptype_5_cdec___pyx_scope_struct_17___iter__ = 0;
+static PyTypeObject *__pyx_ptype_5_cdec___pyx_scope_struct_18_todot = 0;
+static PyTypeObject *__pyx_ptype_5_cdec___pyx_scope_struct_19_lines = 0;
+static PyTypeObject *__pyx_ptype_5_cdec___pyx_scope_struct_20___iter__ = 0;
+static PyTypeObject *__pyx_ptype_5_cdec___pyx_scope_struct_21___iter__ = 0;
+static PyTypeObject *__pyx_ptype_5_cdec___pyx_scope_struct_22__make_config = 0;
+static PyTypeObject *__pyx_ptype_5_cdec___pyx_scope_struct_23___cinit__ = 0;
+static PyTypeObject *__pyx_ptype_5_cdec___pyx_scope_struct_24_genexpr = 0;
 static char *__pyx_f_5_cdec_as_str(PyObject *, struct __pyx_opt_args_5_cdec_as_str *__pyx_optional_args); /*proto*/
 static struct __pyx_obj_5_cdec_SufficientStats *__pyx_f_5_cdec_as_stats(PyObject *, PyObject *); /*proto*/
 #define __Pyx_MODULE_NAME "_cdec"
@@ -1436,6 +1560,7 @@ static PyObject *__pyx_builtin_TypeError;
 static PyObject *__pyx_builtin_KeyError;
 static PyObject *__pyx_builtin_range;
 static PyObject *__pyx_builtin_NotImplemented;
+static PyObject *__pyx_builtin_ValueError;
 static PyObject *__pyx_builtin_eval;
 static PyObject *__pyx_builtin_enumerate;
 static PyObject *__pyx_builtin_IndexError;
@@ -1468,6 +1593,38 @@ static PyObject *__pyx_pf_5_cdec_12SparseVector_33__mul__(PyObject *__pyx_v_x, P
 #if PY_MAJOR_VERSION < 3
 static PyObject *__pyx_pf_5_cdec_12SparseVector_35__div__(PyObject *__pyx_v_x, PyObject *__pyx_v_y); /* proto */
 #endif
+static PyObject *__pyx_pf_5_cdec_7_phrase_genexpr(PyObject *__pyx_self); /* proto */
+static PyObject *__pyx_pf_5_cdec__phrase(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_phrase); /* proto */
+static int __pyx_pf_5_cdec_2NT___init__(struct __pyx_obj_5_cdec_NT *__pyx_v_self, PyObject *__pyx_v_cat, PyObject *__pyx_v_ref); /* proto */
+static PyObject *__pyx_pf_5_cdec_2NT_2__str__(struct __pyx_obj_5_cdec_NT *__pyx_v_self); /* proto */
+static PyObject *__pyx_pf_5_cdec_2NT_3cat___get__(struct __pyx_obj_5_cdec_NT *__pyx_v_self); /* proto */
+static int __pyx_pf_5_cdec_2NT_3cat_2__set__(struct __pyx_obj_5_cdec_NT *__pyx_v_self, PyObject *__pyx_v_value); /* proto */
+static PyObject *__pyx_pf_5_cdec_2NT_3ref___get__(struct __pyx_obj_5_cdec_NT *__pyx_v_self); /* proto */
+static int __pyx_pf_5_cdec_2NT_3ref_2__set__(struct __pyx_obj_5_cdec_NT *__pyx_v_self, PyObject *__pyx_v_value); /* proto */
+static int __pyx_pf_5_cdec_5NTRef___init__(struct __pyx_obj_5_cdec_NTRef *__pyx_v_self, PyObject *__pyx_v_ref); /* proto */
+static PyObject *__pyx_pf_5_cdec_5NTRef_2__str__(struct __pyx_obj_5_cdec_NTRef *__pyx_v_self); /* proto */
+static PyObject *__pyx_pf_5_cdec_5NTRef_3ref___get__(struct __pyx_obj_5_cdec_NTRef *__pyx_v_self); /* proto */
+static int __pyx_pf_5_cdec_5NTRef_3ref_2__set__(struct __pyx_obj_5_cdec_NTRef *__pyx_v_self, PyObject *__pyx_v_value); /* proto */
+static void __pyx_pf_5_cdec_9BaseTRule___dealloc__(CYTHON_UNUSED struct __pyx_obj_5_cdec_BaseTRule *__pyx_v_self); /* proto */
+static PyObject *__pyx_pf_5_cdec_9BaseTRule_5arity___get__(struct __pyx_obj_5_cdec_BaseTRule *__pyx_v_self); /* proto */
+static PyObject *__pyx_pf_5_cdec_9BaseTRule_1f___get__(struct __pyx_obj_5_cdec_BaseTRule *__pyx_v_self); /* proto */
+static int __pyx_pf_5_cdec_9BaseTRule_1f_2__set__(struct __pyx_obj_5_cdec_BaseTRule *__pyx_v_self, PyObject *__pyx_v_f); /* proto */
+static PyObject *__pyx_pf_5_cdec_9BaseTRule_1e___get__(struct __pyx_obj_5_cdec_BaseTRule *__pyx_v_self); /* proto */
+static int __pyx_pf_5_cdec_9BaseTRule_1e_2__set__(struct __pyx_obj_5_cdec_BaseTRule *__pyx_v_self, PyObject *__pyx_v_e); /* proto */
+static PyObject *__pyx_pf_5_cdec_9BaseTRule_1a___get__(struct __pyx_obj_5_cdec_BaseTRule *__pyx_v_self); /* proto */
+static int __pyx_pf_5_cdec_9BaseTRule_1a_3__set__(struct __pyx_obj_5_cdec_BaseTRule *__pyx_v_self, PyObject *__pyx_v_a); /* proto */
+static PyObject *__pyx_pf_5_cdec_9BaseTRule_6scores___get__(struct __pyx_obj_5_cdec_BaseTRule *__pyx_v_self); /* proto */
+static int __pyx_pf_5_cdec_9BaseTRule_6scores_2__set__(struct __pyx_obj_5_cdec_BaseTRule *__pyx_v_self, PyObject *__pyx_v_scores); /* proto */
+static PyObject *__pyx_pf_5_cdec_9BaseTRule_3lhs___get__(struct __pyx_obj_5_cdec_BaseTRule *__pyx_v_self); /* proto */
+static int __pyx_pf_5_cdec_9BaseTRule_3lhs_2__set__(struct __pyx_obj_5_cdec_BaseTRule *__pyx_v_self, PyObject *__pyx_v_lhs); /* proto */
+static PyObject *__pyx_pf_5_cdec_9BaseTRule_7__str___genexpr(PyObject *__pyx_self); /* proto */
+static PyObject *__pyx_pf_5_cdec_9BaseTRule_2__str__(struct __pyx_obj_5_cdec_BaseTRule *__pyx_v_self); /* proto */
+static int __pyx_pf_5_cdec_5TRule___cinit__(struct __pyx_obj_5_cdec_TRule *__pyx_v_self, PyObject *__pyx_v_lhs, PyObject *__pyx_v_f, PyObject *__pyx_v_e, PyObject *__pyx_v_scores, PyObject *__pyx_v_a); /* proto */
+static void __pyx_pf_5_cdec_7Grammar___dealloc__(CYTHON_UNUSED struct __pyx_obj_5_cdec_Grammar *__pyx_v_self); /* proto */
+static PyObject *__pyx_pf_5_cdec_7Grammar_2__iter__(struct __pyx_obj_5_cdec_Grammar *__pyx_v_self); /* proto */
+static PyObject *__pyx_pf_5_cdec_7Grammar_4name___get__(struct __pyx_obj_5_cdec_Grammar *__pyx_v_self); /* proto */
+static int __pyx_pf_5_cdec_7Grammar_4name_2__set__(struct __pyx_obj_5_cdec_Grammar *__pyx_v_self, PyObject *__pyx_v_name); /* proto */
+static int __pyx_pf_5_cdec_11TextGrammar___cinit__(struct __pyx_obj_5_cdec_TextGrammar *__pyx_v_self, PyObject *__pyx_v_rules); /* proto */
 static void __pyx_pf_5_cdec_10Hypergraph___dealloc__(struct __pyx_obj_5_cdec_Hypergraph *__pyx_v_self); /* proto */
 static PyObject *__pyx_pf_5_cdec_10Hypergraph_2viterbi(struct __pyx_obj_5_cdec_Hypergraph *__pyx_v_self); /* proto */
 static PyObject *__pyx_pf_5_cdec_10Hypergraph_4viterbi_trees(struct __pyx_obj_5_cdec_Hypergraph *__pyx_v_self); /* proto */
@@ -1484,15 +1641,8 @@ static PyObject *__pyx_pf_5_cdec_10Hypergraph_28reweight(struct __pyx_obj_5_cdec
 static PyObject *__pyx_pf_5_cdec_10Hypergraph_5edges___get__(struct __pyx_obj_5_cdec_Hypergraph *__pyx_v_self); /* proto */
 static PyObject *__pyx_pf_5_cdec_10Hypergraph_5nodes___get__(struct __pyx_obj_5_cdec_Hypergraph *__pyx_v_self); /* proto */
 static PyObject *__pyx_pf_5_cdec_10Hypergraph_4goal___get__(struct __pyx_obj_5_cdec_Hypergraph *__pyx_v_self); /* proto */
-static PyObject *__pyx_pf_5_cdec_7_phrase_genexpr(PyObject *__pyx_self); /* proto */
-static PyObject *__pyx_pf_5_cdec__phrase(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_phrase); /* proto */
-static PyObject *__pyx_pf_5_cdec_5TRule_5arity___get__(struct __pyx_obj_5_cdec_TRule *__pyx_v_self); /* proto */
-static PyObject *__pyx_pf_5_cdec_5TRule_1f___get__(struct __pyx_obj_5_cdec_TRule *__pyx_v_self); /* proto */
-static PyObject *__pyx_pf_5_cdec_5TRule_1e___get__(struct __pyx_obj_5_cdec_TRule *__pyx_v_self); /* proto */
-static PyObject *__pyx_pf_5_cdec_5TRule_6scores___get__(struct __pyx_obj_5_cdec_TRule *__pyx_v_self); /* proto */
-static PyObject *__pyx_pf_5_cdec_5TRule_3lhs___get__(struct __pyx_obj_5_cdec_TRule *__pyx_v_self); /* proto */
-static PyObject *__pyx_pf_5_cdec_5TRule_7__str___genexpr(PyObject *__pyx_self); /* proto */
-static PyObject *__pyx_pf_5_cdec_5TRule___str__(struct __pyx_obj_5_cdec_TRule *__pyx_v_self); /* proto */
+static PyObject *__pyx_pf_5_cdec_10Hypergraph_6npaths___get__(struct __pyx_obj_5_cdec_Hypergraph *__pyx_v_self); /* proto */
+static PyObject *__pyx_pf_5_cdec_10Hypergraph_30inside_outside(struct __pyx_obj_5_cdec_Hypergraph *__pyx_v_self); /* proto */
 static Py_ssize_t __pyx_pf_5_cdec_14HypergraphEdge___len__(struct __pyx_obj_5_cdec_HypergraphEdge *__pyx_v_self); /* proto */
 static PyObject *__pyx_pf_5_cdec_14HypergraphEdge_9head_node___get__(struct __pyx_obj_5_cdec_HypergraphEdge *__pyx_v_self); /* proto */
 static PyObject *__pyx_pf_5_cdec_14HypergraphEdge_10tail_nodes___get__(struct __pyx_obj_5_cdec_HypergraphEdge *__pyx_v_self); /* proto */
@@ -1508,7 +1658,7 @@ static PyObject *__pyx_pf_5_cdec_14HypergraphNode_9out_edges___get__(struct __py
 static PyObject *__pyx_pf_5_cdec_14HypergraphNode_4span___get__(struct __pyx_obj_5_cdec_HypergraphNode *__pyx_v_self); /* proto */
 static PyObject *__pyx_pf_5_cdec_14HypergraphNode_3cat___get__(struct __pyx_obj_5_cdec_HypergraphNode *__pyx_v_self); /* proto */
 static PyObject *__pyx_pf_5_cdec_14HypergraphNode___richcmp__(struct __pyx_obj_5_cdec_HypergraphNode *__pyx_v_x, struct __pyx_obj_5_cdec_HypergraphNode *__pyx_v_y, int __pyx_v_op); /* proto */
-static int __pyx_pf_5_cdec_7Lattice___init__(struct __pyx_obj_5_cdec_Lattice *__pyx_v_self, PyObject *__pyx_v_inp); /* proto */
+static int __pyx_pf_5_cdec_7Lattice___cinit__(struct __pyx_obj_5_cdec_Lattice *__pyx_v_self, PyObject *__pyx_v_inp); /* proto */
 static PyObject *__pyx_pf_5_cdec_7Lattice_2__getitem__(struct __pyx_obj_5_cdec_Lattice *__pyx_v_self, int __pyx_v_index); /* proto */
 static int __pyx_pf_5_cdec_7Lattice_4__setitem__(struct __pyx_obj_5_cdec_Lattice *__pyx_v_self, int __pyx_v_index, PyObject *__pyx_v_arcs); /* proto */
 static Py_ssize_t __pyx_pf_5_cdec_7Lattice_6__len__(struct __pyx_obj_5_cdec_Lattice *__pyx_v_self); /* proto */
@@ -1553,41 +1703,46 @@ static PyObject *__pyx_pf_5_cdec_7Decoder_6translate(struct __pyx_obj_5_cdec_Dec
 static char __pyx_k_1[] = "Cannot convert type %s to str";
 static char __pyx_k_3[] = "cannot take the dot product of %s and SparseVector";
 static char __pyx_k_4[] = "comparison not implemented for SparseVector";
-static char __pyx_k_6[] = "csplit_preserve_full_word";
-static char __pyx_k_7[] = "cannot reweight hypergraph with %s";
+static char __pyx_k_7[] = " ";
 static char __pyx_k_8[] = "[%s,%d]";
-static char __pyx_k_10[] = " ";
+static char __pyx_k_9[] = "[%s]";
+static char __pyx_k_10[] = "[%d]";
 static char __pyx_k_11[] = "%s=%s";
-static char __pyx_k_12[] = "[%s] ||| %s ||| %s ||| %s";
-static char __pyx_k_13[] = "comparison not implemented for HypergraphEdge";
-static char __pyx_k_15[] = "comparison not implemented for HypergraphNode";
-static char __pyx_k_18[] = "Cannot create lattice from %s";
-static char __pyx_k_19[] = "lattice index out of range";
-static char __pyx_k_23[] = "digraph lattice {";
-  static char __pyx_k_24[] = "rankdir = LR;";
-  static char __pyx_k_25[] = "node [shape=circle];";
-  static char __pyx_k_26[] = "%d -> %d [label=\"%s\"];";
-  static char __pyx_k_27[] = "\"";
-  static char __pyx_k_28[] = "\\\"";
-  static char __pyx_k_30[] = "%d [shape=doublecircle]";
-static char __pyx_k_31[] = "}";
-static char __pyx_k_34[] = "/Users/vchahun/Sandbox/cdec/python/src/lattice.pxi";
-static char __pyx_k_35[] = "\n";
-static char __pyx_k_37[] = "candidate set index out of range";
-static char __pyx_k_39[] = "%s %s";
-static char __pyx_k_40[] = "%s = %s";
-static char __pyx_k_42[] = "formalism \"%s\" unknown";
-static char __pyx_k_43[] = "cannot initialize weights with %s";
-static char __pyx_k_44[] = "#";
-static char __pyx_k_48[] = "Cannot translate input type %s";
-static char __pyx_k_51[] = "/Users/vchahun/Sandbox/cdec/python/src/trule.pxi";
-static char __pyx_k_56[] = "/Users/vchahun/Sandbox/cdec/python/src/_cdec.pyx";
+static char __pyx_k_12[] = "%s ||| %s ||| %s ||| %s";
+static char __pyx_k_13[] = "the grammar should contain TRule objects";
+static char __pyx_k_15[] = "csplit_preserve_full_word";
+static char __pyx_k_16[] = "cannot reweight hypergraph with %s";
+static char __pyx_k_17[] = "comparison not implemented for HypergraphEdge";
+static char __pyx_k_19[] = "comparison not implemented for HypergraphNode";
+static char __pyx_k_22[] = "Cannot create lattice from %s";
+static char __pyx_k_23[] = "lattice index out of range";
+static char __pyx_k_27[] = "digraph lattice {";
+  static char __pyx_k_28[] = "rankdir = LR;";
+  static char __pyx_k_29[] = "node [shape=circle];";
+  static char __pyx_k_30[] = "%d -> %d [label=\"%s\"];";
+  static char __pyx_k_31[] = "\"";
+  static char __pyx_k_32[] = "\\\"";
+  static char __pyx_k_34[] = "%d [shape=doublecircle]";
+static char __pyx_k_35[] = "}";
+static char __pyx_k_38[] = "/Users/vchahun/Sandbox/cdec/python/src/lattice.pxi";
+static char __pyx_k_39[] = "\n";
+static char __pyx_k_41[] = "candidate set index out of range";
+static char __pyx_k_43[] = "%s %s";
+static char __pyx_k_44[] = "%s = %s";
+static char __pyx_k_46[] = "formalism \"%s\" unknown";
+static char __pyx_k_47[] = "cannot initialize weights with %s";
+static char __pyx_k_48[] = "#";
+static char __pyx_k_51[] = "Cannot translate input type %s";
+static char __pyx_k_54[] = "/Users/vchahun/Sandbox/cdec/python/src/grammar.pxi";
+static char __pyx_k_59[] = "/Users/vchahun/Sandbox/cdec/python/src/_cdec.pyx";
+static char __pyx_k__a[] = "a";
 static char __pyx_k__e[] = "e";
 static char __pyx_k__f[] = "f";
 static char __pyx_k__i[] = "i";
 static char __pyx_k__k[] = "k";
 static char __pyx_k__pb[] = "pb";
 static char __pyx_k__TER[] = "TER";
+static char __pyx_k__cat[] = "cat";
 static char __pyx_k__dot[] = "dot";
 static char __pyx_k__fst[] = "fst";
 static char __pyx_k__get[] = "get";
@@ -1595,6 +1750,7 @@ static char __pyx_k__inp[] = "inp";
 static char __pyx_k__key[] = "key";
 static char __pyx_k__lhs[] = "lhs";
 static char __pyx_k__plf[] = "plf";
+static char __pyx_k__ref[] = "ref";
 static char __pyx_k__BLEU[] = "BLEU";
 static char __pyx_k__eval[] = "eval";
 static char __pyx_k__info[] = "info";
@@ -1612,6 +1768,7 @@ static char __pyx_k__items[] = "items";
 static char __pyx_k__label[] = "label";
 static char __pyx_k__lines[] = "lines";
 static char __pyx_k__range[] = "range";
+static char __pyx_k__rules[] = "rules";
 static char __pyx_k__split[] = "split";
 static char __pyx_k__strip[] = "strip";
 static char __pyx_k__value[] = "value";
@@ -1644,6 +1801,7 @@ static char __pyx_k__enumerate[] = "enumerate";
 static char __pyx_k__evaluator[] = "evaluator";
 static char __pyx_k__formalism[] = "formalism";
 static char __pyx_k__IndexError[] = "IndexError";
+static char __pyx_k__ValueError[] = "ValueError";
 static char __pyx_k__beam_alpha[] = "beam_alpha";
 static char __pyx_k__config_str[] = "config_str";
 static char __pyx_k__hypergraph[] = "hypergraph";
@@ -1657,33 +1815,36 @@ static PyObject *__pyx_kp_s_10;
 static PyObject *__pyx_kp_s_11;
 static PyObject *__pyx_kp_s_12;
 static PyObject *__pyx_kp_s_13;
-static PyObject *__pyx_kp_s_15;
-static PyObject *__pyx_kp_s_18;
+static PyObject *__pyx_n_s_15;
+static PyObject *__pyx_kp_s_16;
+static PyObject *__pyx_kp_s_17;
 static PyObject *__pyx_kp_s_19;
+static PyObject *__pyx_kp_s_22;
 static PyObject *__pyx_kp_s_23;
-static PyObject *__pyx_kp_s_24;
-static PyObject *__pyx_kp_s_25;
-static PyObject *__pyx_kp_s_26;
 static PyObject *__pyx_kp_s_27;
 static PyObject *__pyx_kp_s_28;
+static PyObject *__pyx_kp_s_29;
 static PyObject *__pyx_kp_s_3;
 static PyObject *__pyx_kp_s_30;
 static PyObject *__pyx_kp_s_31;
+static PyObject *__pyx_kp_s_32;
 static PyObject *__pyx_kp_s_34;
 static PyObject *__pyx_kp_s_35;
-static PyObject *__pyx_kp_s_37;
+static PyObject *__pyx_kp_s_38;
 static PyObject *__pyx_kp_s_39;
 static PyObject *__pyx_kp_s_4;
-static PyObject *__pyx_kp_s_40;
-static PyObject *__pyx_kp_s_42;
+static PyObject *__pyx_kp_s_41;
 static PyObject *__pyx_kp_s_43;
 static PyObject *__pyx_kp_s_44;
+static PyObject *__pyx_kp_s_46;
+static PyObject *__pyx_kp_s_47;
 static PyObject *__pyx_kp_s_48;
 static PyObject *__pyx_kp_s_51;
-static PyObject *__pyx_kp_s_56;
-static PyObject *__pyx_n_s_6;
+static PyObject *__pyx_kp_s_54;
+static PyObject *__pyx_kp_s_59;
 static PyObject *__pyx_kp_s_7;
 static PyObject *__pyx_kp_s_8;
+static PyObject *__pyx_kp_s_9;
 static PyObject *__pyx_n_s__BLEU;
 static PyObject *__pyx_n_s__Exception;
 static PyObject *__pyx_n_s__IBM_BLEU;
@@ -1694,6 +1855,7 @@ static PyObject *__pyx_n_s__NotImplemented;
 static PyObject *__pyx_n_s__ParseFailed;
 static PyObject *__pyx_n_s__TER;
 static PyObject *__pyx_n_s__TypeError;
+static PyObject *__pyx_n_s__ValueError;
 static PyObject *__pyx_n_s____enter__;
 static PyObject *__pyx_n_s____exit__;
 static PyObject *__pyx_n_s____main__;
@@ -1701,7 +1863,9 @@ static PyObject *__pyx_n_s____test__;
 static PyObject *__pyx_n_s___cdec;
 static PyObject *__pyx_n_s___make_config;
 static PyObject *__pyx_n_s___phrase;
+static PyObject *__pyx_n_s__a;
 static PyObject *__pyx_n_s__beam_alpha;
+static PyObject *__pyx_n_s__cat;
 static PyObject *__pyx_n_s__config;
 static PyObject *__pyx_n_s__config_str;
 static PyObject *__pyx_n_s__csplit;
@@ -1740,8 +1904,10 @@ static PyObject *__pyx_n_s__pb;
 static PyObject *__pyx_n_s__phrase;
 static PyObject *__pyx_n_s__plf;
 static PyObject *__pyx_n_s__range;
+static PyObject *__pyx_n_s__ref;
 static PyObject *__pyx_n_s__refs;
 static PyObject *__pyx_n_s__replace;
+static PyObject *__pyx_n_s__rules;
 static PyObject *__pyx_n_s__scfg;
 static PyObject *__pyx_n_s__scores;
 static PyObject *__pyx_n_s__self;
@@ -1758,38 +1924,38 @@ static PyObject *__pyx_int_0;
 static PyObject *__pyx_int_1;
 static PyObject *__pyx_k_tuple_2;
 static PyObject *__pyx_k_tuple_5;
-static PyObject *__pyx_k_tuple_9;
+static PyObject *__pyx_k_tuple_6;
 static PyObject *__pyx_k_tuple_14;
-static PyObject *__pyx_k_tuple_16;
-static PyObject *__pyx_k_tuple_17;
+static PyObject *__pyx_k_tuple_18;
 static PyObject *__pyx_k_tuple_20;
 static PyObject *__pyx_k_tuple_21;
-static PyObject *__pyx_k_tuple_22;
-static PyObject *__pyx_k_tuple_29;
-static PyObject *__pyx_k_tuple_32;
+static PyObject *__pyx_k_tuple_24;
+static PyObject *__pyx_k_tuple_25;
+static PyObject *__pyx_k_tuple_26;
+static PyObject *__pyx_k_tuple_33;
 static PyObject *__pyx_k_tuple_36;
-static PyObject *__pyx_k_tuple_38;
-static PyObject *__pyx_k_tuple_41;
+static PyObject *__pyx_k_tuple_40;
+static PyObject *__pyx_k_tuple_42;
 static PyObject *__pyx_k_tuple_45;
-static PyObject *__pyx_k_tuple_46;
-static PyObject *__pyx_k_tuple_47;
 static PyObject *__pyx_k_tuple_49;
+static PyObject *__pyx_k_tuple_50;
 static PyObject *__pyx_k_tuple_52;
-static PyObject *__pyx_k_tuple_53;
-static PyObject *__pyx_k_tuple_54;
-static PyObject *__pyx_k_codeobj_33;
-static PyObject *__pyx_k_codeobj_50;
-static PyObject *__pyx_k_codeobj_55;
+static PyObject *__pyx_k_tuple_55;
+static PyObject *__pyx_k_tuple_56;
+static PyObject *__pyx_k_tuple_57;
+static PyObject *__pyx_k_codeobj_37;
+static PyObject *__pyx_k_codeobj_53;
+static PyObject *__pyx_k_codeobj_58;
 
 /* "_cdec.pyx":6
  * cimport decoder
  * 
- * cdef char* as_str(sentence, error_msg='Cannot convert type %s to str'):             # <<<<<<<<<<<<<<
+ * cdef char* as_str(data, error_msg='Cannot convert type %s to str'):             # <<<<<<<<<<<<<<
  *     cdef bytes ret
- *     if isinstance(sentence, unicode):
+ *     if isinstance(data, unicode):
  */
 
-static char *__pyx_f_5_cdec_as_str(PyObject *__pyx_v_sentence, struct __pyx_opt_args_5_cdec_as_str *__pyx_optional_args) {
+static char *__pyx_f_5_cdec_as_str(PyObject *__pyx_v_data, struct __pyx_opt_args_5_cdec_as_str *__pyx_optional_args) {
   PyObject *__pyx_v_error_msg = ((PyObject *)__pyx_kp_s_1);
   PyObject *__pyx_v_ret = 0;
   char *__pyx_r;
@@ -1809,26 +1975,26 @@ static char *__pyx_f_5_cdec_as_str(PyObject *__pyx_v_sentence, struct __pyx_opt_
   }
 
   /* "_cdec.pyx":8
- * cdef char* as_str(sentence, error_msg='Cannot convert type %s to str'):
+ * cdef char* as_str(data, error_msg='Cannot convert type %s to str'):
  *     cdef bytes ret
- *     if isinstance(sentence, unicode):             # <<<<<<<<<<<<<<
- *         ret = sentence.encode('utf8')
- *     elif isinstance(sentence, str):
+ *     if isinstance(data, unicode):             # <<<<<<<<<<<<<<
+ *         ret = data.encode('utf8')
+ *     elif isinstance(data, str):
  */
   __pyx_t_1 = ((PyObject *)((PyObject*)(&PyUnicode_Type)));
   __Pyx_INCREF(__pyx_t_1);
-  __pyx_t_2 = __Pyx_TypeCheck(__pyx_v_sentence, __pyx_t_1); 
+  __pyx_t_2 = __Pyx_TypeCheck(__pyx_v_data, __pyx_t_1); 
   __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
   if (__pyx_t_2) {
 
     /* "_cdec.pyx":9
  *     cdef bytes ret
- *     if isinstance(sentence, unicode):
- *         ret = sentence.encode('utf8')             # <<<<<<<<<<<<<<
- *     elif isinstance(sentence, str):
- *         ret = sentence
+ *     if isinstance(data, unicode):
+ *         ret = data.encode('utf8')             # <<<<<<<<<<<<<<
+ *     elif isinstance(data, str):
+ *         ret = data
  */
-    __pyx_t_1 = PyObject_GetAttr(__pyx_v_sentence, __pyx_n_s__encode); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 9; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_t_1 = PyObject_GetAttr(__pyx_v_data, __pyx_n_s__encode); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 9; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
     __Pyx_GOTREF(__pyx_t_1);
     __pyx_t_3 = PyObject_Call(__pyx_t_1, ((PyObject *)__pyx_k_tuple_2), NULL); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 9; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
     __Pyx_GOTREF(__pyx_t_3);
@@ -1840,40 +2006,40 @@ static char *__pyx_f_5_cdec_as_str(PyObject *__pyx_v_sentence, struct __pyx_opt_
   }
 
   /* "_cdec.pyx":10
- *     if isinstance(sentence, unicode):
- *         ret = sentence.encode('utf8')
- *     elif isinstance(sentence, str):             # <<<<<<<<<<<<<<
- *         ret = sentence
+ *     if isinstance(data, unicode):
+ *         ret = data.encode('utf8')
+ *     elif isinstance(data, str):             # <<<<<<<<<<<<<<
+ *         ret = data
  *     else:
  */
   __pyx_t_3 = ((PyObject *)((PyObject*)(&PyString_Type)));
   __Pyx_INCREF(__pyx_t_3);
-  __pyx_t_2 = __Pyx_TypeCheck(__pyx_v_sentence, __pyx_t_3); 
+  __pyx_t_2 = __Pyx_TypeCheck(__pyx_v_data, __pyx_t_3); 
   __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
   if (__pyx_t_2) {
 
     /* "_cdec.pyx":11
- *         ret = sentence.encode('utf8')
- *     elif isinstance(sentence, str):
- *         ret = sentence             # <<<<<<<<<<<<<<
+ *         ret = data.encode('utf8')
+ *     elif isinstance(data, str):
+ *         ret = data             # <<<<<<<<<<<<<<
  *     else:
- *         raise TypeError(error_msg % type(sentence))
+ *         raise TypeError(error_msg % type(data))
  */
-    if (!(likely(PyBytes_CheckExact(__pyx_v_sentence))||((__pyx_v_sentence) == Py_None)||(PyErr_Format(PyExc_TypeError, "Expected bytes, got %.200s", Py_TYPE(__pyx_v_sentence)->tp_name), 0))) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 11; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-    __Pyx_INCREF(__pyx_v_sentence);
-    __pyx_v_ret = ((PyObject*)__pyx_v_sentence);
+    if (!(likely(PyBytes_CheckExact(__pyx_v_data))||((__pyx_v_data) == Py_None)||(PyErr_Format(PyExc_TypeError, "Expected bytes, got %.200s", Py_TYPE(__pyx_v_data)->tp_name), 0))) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 11; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_INCREF(__pyx_v_data);
+    __pyx_v_ret = ((PyObject*)__pyx_v_data);
     goto __pyx_L3;
   }
   /*else*/ {
 
     /* "_cdec.pyx":13
- *         ret = sentence
+ *         ret = data
  *     else:
- *         raise TypeError(error_msg % type(sentence))             # <<<<<<<<<<<<<<
+ *         raise TypeError(error_msg % type(data))             # <<<<<<<<<<<<<<
  *     return ret
  * 
  */
-    __pyx_t_3 = PyNumber_Remainder(__pyx_v_error_msg, ((PyObject *)Py_TYPE(__pyx_v_sentence))); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 13; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_t_3 = PyNumber_Remainder(__pyx_v_error_msg, ((PyObject *)Py_TYPE(__pyx_v_data))); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 13; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
     __Pyx_GOTREF(__pyx_t_3);
     __pyx_t_1 = PyTuple_New(1); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 13; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
     __Pyx_GOTREF(__pyx_t_1);
@@ -1891,7 +2057,7 @@ static char *__pyx_f_5_cdec_as_str(PyObject *__pyx_v_sentence, struct __pyx_opt_
 
   /* "_cdec.pyx":14
  *     else:
- *         raise TypeError(error_msg % type(sentence))
+ *         raise TypeError(error_msg % type(data))
  *     return ret             # <<<<<<<<<<<<<<
  * 
  * include "vectors.pxi"
@@ -2789,7 +2955,7 @@ static PyObject *__pyx_pw_5_cdec_12SparseVector_9__iter__(PyObject *__pyx_v_self
  * 
  *     def __iter__(self):             # <<<<<<<<<<<<<<
  *         cdef FastSparseVector[weight_t].const_iterator* it = new FastSparseVector[weight_t].const_iterator(self.vector[0], False)
- *         try:
+ *         cdef unsigned i
  */
 
 static PyObject *__pyx_pf_5_cdec_12SparseVector_8__iter__(struct __pyx_obj_5_cdec_SparseVector *__pyx_v_self) {
@@ -2833,7 +2999,7 @@ static PyObject *__pyx_gb_5_cdec_12SparseVector_10generator1(__pyx_GeneratorObje
   struct __pyx_obj_5_cdec___pyx_scope_struct_1___iter__ *__pyx_cur_scope = ((struct __pyx_obj_5_cdec___pyx_scope_struct_1___iter__ *)__pyx_generator->closure);
   PyObject *__pyx_r = NULL;
   size_t __pyx_t_1;
-  size_t __pyx_t_2;
+  unsigned int __pyx_t_2;
   PyObject *__pyx_t_3 = NULL;
   PyObject *__pyx_t_4 = NULL;
   PyObject *__pyx_t_5 = NULL;
@@ -2853,22 +3019,22 @@ static PyObject *__pyx_gb_5_cdec_12SparseVector_10generator1(__pyx_GeneratorObje
  * 
  *     def __iter__(self):
  *         cdef FastSparseVector[weight_t].const_iterator* it = new FastSparseVector[weight_t].const_iterator(self.vector[0], False)             # <<<<<<<<<<<<<<
+ *         cdef unsigned i
  *         try:
- *             for i in range(self.vector.size()):
  */
   __pyx_cur_scope->__pyx_v_it = new FastSparseVector<weight_t>::const_iterator((__pyx_cur_scope->__pyx_v_self->vector[0]), 0);
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":57
- *     def __iter__(self):
+  /* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":58
  *         cdef FastSparseVector[weight_t].const_iterator* it = new FastSparseVector[weight_t].const_iterator(self.vector[0], False)
+ *         cdef unsigned i
  *         try:             # <<<<<<<<<<<<<<
  *             for i in range(self.vector.size()):
  *                 yield (FDConvert(it[0].ptr().first).c_str(), it[0].ptr().second)
  */
   /*try:*/ {
 
-    /* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":58
- *         cdef FastSparseVector[weight_t].const_iterator* it = new FastSparseVector[weight_t].const_iterator(self.vector[0], False)
+    /* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":59
+ *         cdef unsigned i
  *         try:
  *             for i in range(self.vector.size()):             # <<<<<<<<<<<<<<
  *                 yield (FDConvert(it[0].ptr().first).c_str(), it[0].ptr().second)
@@ -2878,18 +3044,18 @@ static PyObject *__pyx_gb_5_cdec_12SparseVector_10generator1(__pyx_GeneratorObje
     for (__pyx_t_2 = 0; __pyx_t_2 < __pyx_t_1; __pyx_t_2+=1) {
       __pyx_cur_scope->__pyx_v_i = __pyx_t_2;
 
-      /* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":59
+      /* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":60
  *         try:
  *             for i in range(self.vector.size()):
  *                 yield (FDConvert(it[0].ptr().first).c_str(), it[0].ptr().second)             # <<<<<<<<<<<<<<
  *                 pinc(it[0]) # ++it
  *         finally:
  */
-      __pyx_t_3 = PyBytes_FromString(FD::Convert((__pyx_cur_scope->__pyx_v_it[0]).operator->()->first).c_str()); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 59; __pyx_clineno = __LINE__; goto __pyx_L5;}
+      __pyx_t_3 = PyBytes_FromString(FD::Convert((__pyx_cur_scope->__pyx_v_it[0]).operator->()->first).c_str()); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 60; __pyx_clineno = __LINE__; goto __pyx_L5;}
       __Pyx_GOTREF(((PyObject *)__pyx_t_3));
-      __pyx_t_4 = PyFloat_FromDouble((__pyx_cur_scope->__pyx_v_it[0]).operator->()->second); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 59; __pyx_clineno = __LINE__; goto __pyx_L5;}
+      __pyx_t_4 = PyFloat_FromDouble((__pyx_cur_scope->__pyx_v_it[0]).operator->()->second); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 60; __pyx_clineno = __LINE__; goto __pyx_L5;}
       __Pyx_GOTREF(__pyx_t_4);
-      __pyx_t_5 = PyTuple_New(2); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 59; __pyx_clineno = __LINE__; goto __pyx_L5;}
+      __pyx_t_5 = PyTuple_New(2); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 60; __pyx_clineno = __LINE__; goto __pyx_L5;}
       __Pyx_GOTREF(__pyx_t_5);
       PyTuple_SET_ITEM(__pyx_t_5, 0, ((PyObject *)__pyx_t_3));
       __Pyx_GIVEREF(((PyObject *)__pyx_t_3));
@@ -2909,9 +3075,9 @@ static PyObject *__pyx_gb_5_cdec_12SparseVector_10generator1(__pyx_GeneratorObje
       __pyx_L9_resume_from_yield:;
       __pyx_t_1 = __pyx_cur_scope->__pyx_t_0;
       __pyx_t_2 = __pyx_cur_scope->__pyx_t_1;
-      if (unlikely(!__pyx_sent_value)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 59; __pyx_clineno = __LINE__; goto __pyx_L5;}
+      if (unlikely(!__pyx_sent_value)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 60; __pyx_clineno = __LINE__; goto __pyx_L5;}
 
-      /* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":60
+      /* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":61
  *             for i in range(self.vector.size()):
  *                 yield (FDConvert(it[0].ptr().first).c_str(), it[0].ptr().second)
  *                 pinc(it[0]) # ++it             # <<<<<<<<<<<<<<
@@ -2922,7 +3088,7 @@ static PyObject *__pyx_gb_5_cdec_12SparseVector_10generator1(__pyx_GeneratorObje
     }
   }
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":62
+  /* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":63
  *                 pinc(it[0]) # ++it
  *         finally:
  *             del it             # <<<<<<<<<<<<<<
@@ -2982,7 +3148,7 @@ static PyObject *__pyx_pw_5_cdec_12SparseVector_12dot(PyObject *__pyx_v_self, Py
   return __pyx_r;
 }
 
-/* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":64
+/* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":65
  *             del it
  * 
  *     def dot(self, other):             # <<<<<<<<<<<<<<
@@ -3001,7 +3167,7 @@ static PyObject *__pyx_pf_5_cdec_12SparseVector_11dot(struct __pyx_obj_5_cdec_Sp
   int __pyx_clineno = 0;
   __Pyx_RefNannySetupContext("dot", 0);
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":65
+  /* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":66
  * 
  *     def dot(self, other):
  *         if isinstance(other, DenseVector):             # <<<<<<<<<<<<<<
@@ -3014,7 +3180,7 @@ static PyObject *__pyx_pf_5_cdec_12SparseVector_11dot(struct __pyx_obj_5_cdec_Sp
   __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
   if (__pyx_t_2) {
 
-    /* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":66
+    /* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":67
  *     def dot(self, other):
  *         if isinstance(other, DenseVector):
  *             return self.vector.dot((<DenseVector> other).vector[0])             # <<<<<<<<<<<<<<
@@ -3022,7 +3188,7 @@ static PyObject *__pyx_pf_5_cdec_12SparseVector_11dot(struct __pyx_obj_5_cdec_Sp
  *             return self.vector.dot((<SparseVector> other).vector[0])
  */
     __Pyx_XDECREF(__pyx_r);
-    __pyx_t_1 = PyFloat_FromDouble(__pyx_v_self->vector->dot((((struct __pyx_obj_5_cdec_DenseVector *)__pyx_v_other)->vector[0]))); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 66; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_t_1 = PyFloat_FromDouble(__pyx_v_self->vector->dot((((struct __pyx_obj_5_cdec_DenseVector *)__pyx_v_other)->vector[0]))); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 67; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
     __Pyx_GOTREF(__pyx_t_1);
     __pyx_r = __pyx_t_1;
     __pyx_t_1 = 0;
@@ -3030,7 +3196,7 @@ static PyObject *__pyx_pf_5_cdec_12SparseVector_11dot(struct __pyx_obj_5_cdec_Sp
     goto __pyx_L3;
   }
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":67
+  /* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":68
  *         if isinstance(other, DenseVector):
  *             return self.vector.dot((<DenseVector> other).vector[0])
  *         elif isinstance(other, SparseVector):             # <<<<<<<<<<<<<<
@@ -3043,7 +3209,7 @@ static PyObject *__pyx_pf_5_cdec_12SparseVector_11dot(struct __pyx_obj_5_cdec_Sp
   __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
   if (__pyx_t_2) {
 
-    /* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":68
+    /* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":69
  *             return self.vector.dot((<DenseVector> other).vector[0])
  *         elif isinstance(other, SparseVector):
  *             return self.vector.dot((<SparseVector> other).vector[0])             # <<<<<<<<<<<<<<
@@ -3051,7 +3217,7 @@ static PyObject *__pyx_pf_5_cdec_12SparseVector_11dot(struct __pyx_obj_5_cdec_Sp
  * 
  */
     __Pyx_XDECREF(__pyx_r);
-    __pyx_t_1 = PyFloat_FromDouble(__pyx_v_self->vector->dot((((struct __pyx_obj_5_cdec_SparseVector *)__pyx_v_other)->vector[0]))); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 68; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_t_1 = PyFloat_FromDouble(__pyx_v_self->vector->dot((((struct __pyx_obj_5_cdec_SparseVector *)__pyx_v_other)->vector[0]))); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 69; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
     __Pyx_GOTREF(__pyx_t_1);
     __pyx_r = __pyx_t_1;
     __pyx_t_1 = 0;
@@ -3060,26 +3226,26 @@ static PyObject *__pyx_pf_5_cdec_12SparseVector_11dot(struct __pyx_obj_5_cdec_Sp
   }
   __pyx_L3:;
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":69
+  /* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":70
  *         elif isinstance(other, SparseVector):
  *             return self.vector.dot((<SparseVector> other).vector[0])
  *         raise TypeError('cannot take the dot product of %s and SparseVector' % type(other))             # <<<<<<<<<<<<<<
  * 
  *     def __richcmp__(SparseVector x, SparseVector y, int op):
  */
-  __pyx_t_1 = PyNumber_Remainder(((PyObject *)__pyx_kp_s_3), ((PyObject *)Py_TYPE(__pyx_v_other))); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 69; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_1 = PyNumber_Remainder(((PyObject *)__pyx_kp_s_3), ((PyObject *)Py_TYPE(__pyx_v_other))); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 70; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __Pyx_GOTREF(((PyObject *)__pyx_t_1));
-  __pyx_t_3 = PyTuple_New(1); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 69; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_3 = PyTuple_New(1); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 70; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __Pyx_GOTREF(__pyx_t_3);
   PyTuple_SET_ITEM(__pyx_t_3, 0, ((PyObject *)__pyx_t_1));
   __Pyx_GIVEREF(((PyObject *)__pyx_t_1));
   __pyx_t_1 = 0;
-  __pyx_t_1 = PyObject_Call(__pyx_builtin_TypeError, ((PyObject *)__pyx_t_3), NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 69; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_1 = PyObject_Call(__pyx_builtin_TypeError, ((PyObject *)__pyx_t_3), NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 70; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __Pyx_GOTREF(__pyx_t_1);
   __Pyx_DECREF(((PyObject *)__pyx_t_3)); __pyx_t_3 = 0;
   __Pyx_Raise(__pyx_t_1, 0, 0, 0);
   __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
-  {__pyx_filename = __pyx_f[1]; __pyx_lineno = 69; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  {__pyx_filename = __pyx_f[1]; __pyx_lineno = 70; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
 
   __pyx_r = Py_None; __Pyx_INCREF(Py_None);
   goto __pyx_L0;
@@ -3100,8 +3266,8 @@ static PyObject *__pyx_pw_5_cdec_12SparseVector_14__richcmp__(PyObject *__pyx_v_
   PyObject *__pyx_r = 0;
   __Pyx_RefNannyDeclarations
   __Pyx_RefNannySetupContext("__richcmp__ (wrapper)", 0);
-  if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_x), __pyx_ptype_5_cdec_SparseVector, 1, "x", 0))) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 71; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_y), __pyx_ptype_5_cdec_SparseVector, 1, "y", 0))) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 71; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_x), __pyx_ptype_5_cdec_SparseVector, 1, "x", 0))) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 72; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_y), __pyx_ptype_5_cdec_SparseVector, 1, "y", 0))) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 72; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __pyx_r = __pyx_pf_5_cdec_12SparseVector_13__richcmp__(((struct __pyx_obj_5_cdec_SparseVector *)__pyx_v_x), ((struct __pyx_obj_5_cdec_SparseVector *)__pyx_v_y), ((int)__pyx_v_op));
   goto __pyx_L0;
   __pyx_L1_error:;
@@ -3111,7 +3277,7 @@ static PyObject *__pyx_pw_5_cdec_12SparseVector_14__richcmp__(PyObject *__pyx_v_
   return __pyx_r;
 }
 
-/* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":71
+/* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":72
  *         raise TypeError('cannot take the dot product of %s and SparseVector' % type(other))
  * 
  *     def __richcmp__(SparseVector x, SparseVector y, int op):             # <<<<<<<<<<<<<<
@@ -3129,7 +3295,7 @@ static PyObject *__pyx_pf_5_cdec_12SparseVector_13__richcmp__(struct __pyx_obj_5
   int __pyx_clineno = 0;
   __Pyx_RefNannySetupContext("__richcmp__", 0);
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":74
+  /* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":75
  *         if op == 2: # ==
  *             return x.vector[0] == y.vector[0]
  *         elif op == 3: # !=             # <<<<<<<<<<<<<<
@@ -3138,7 +3304,7 @@ static PyObject *__pyx_pf_5_cdec_12SparseVector_13__richcmp__(struct __pyx_obj_5
  */
   switch (__pyx_v_op) {
 
-    /* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":72
+    /* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":73
  * 
  *     def __richcmp__(SparseVector x, SparseVector y, int op):
  *         if op == 2: # ==             # <<<<<<<<<<<<<<
@@ -3147,7 +3313,7 @@ static PyObject *__pyx_pf_5_cdec_12SparseVector_13__richcmp__(struct __pyx_obj_5
  */
     case 2:
 
-    /* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":73
+    /* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":74
  *     def __richcmp__(SparseVector x, SparseVector y, int op):
  *         if op == 2: # ==
  *             return x.vector[0] == y.vector[0]             # <<<<<<<<<<<<<<
@@ -3155,14 +3321,14 @@ static PyObject *__pyx_pf_5_cdec_12SparseVector_13__richcmp__(struct __pyx_obj_5
  *             return not (x == y)
  */
     __Pyx_XDECREF(__pyx_r);
-    __pyx_t_1 = __Pyx_PyBool_FromLong(((__pyx_v_x->vector[0]) == (__pyx_v_y->vector[0]))); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 73; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_t_1 = __Pyx_PyBool_FromLong(((__pyx_v_x->vector[0]) == (__pyx_v_y->vector[0]))); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 74; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
     __Pyx_GOTREF(__pyx_t_1);
     __pyx_r = __pyx_t_1;
     __pyx_t_1 = 0;
     goto __pyx_L0;
     break;
 
-    /* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":74
+    /* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":75
  *         if op == 2: # ==
  *             return x.vector[0] == y.vector[0]
  *         elif op == 3: # !=             # <<<<<<<<<<<<<<
@@ -3171,7 +3337,7 @@ static PyObject *__pyx_pf_5_cdec_12SparseVector_13__richcmp__(struct __pyx_obj_5
  */
     case 3:
 
-    /* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":75
+    /* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":76
  *             return x.vector[0] == y.vector[0]
  *         elif op == 3: # !=
  *             return not (x == y)             # <<<<<<<<<<<<<<
@@ -3179,11 +3345,11 @@ static PyObject *__pyx_pf_5_cdec_12SparseVector_13__richcmp__(struct __pyx_obj_5
  * 
  */
     __Pyx_XDECREF(__pyx_r);
-    __pyx_t_1 = PyObject_RichCompare(((PyObject *)__pyx_v_x), ((PyObject *)__pyx_v_y), Py_EQ); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 75; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_t_1 = PyObject_RichCompare(((PyObject *)__pyx_v_x), ((PyObject *)__pyx_v_y), Py_EQ); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 76; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
     __Pyx_GOTREF(__pyx_t_1);
-    __pyx_t_2 = __Pyx_PyObject_IsTrue(__pyx_t_1); if (unlikely(__pyx_t_2 < 0)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 75; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_t_2 = __Pyx_PyObject_IsTrue(__pyx_t_1); if (unlikely(__pyx_t_2 < 0)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 76; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
     __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
-    __pyx_t_1 = __Pyx_PyBool_FromLong((!__pyx_t_2)); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 75; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_t_1 = __Pyx_PyBool_FromLong((!__pyx_t_2)); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 76; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
     __Pyx_GOTREF(__pyx_t_1);
     __pyx_r = __pyx_t_1;
     __pyx_t_1 = 0;
@@ -3191,18 +3357,18 @@ static PyObject *__pyx_pf_5_cdec_12SparseVector_13__richcmp__(struct __pyx_obj_5
     break;
   }
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":76
+  /* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":77
  *         elif op == 3: # !=
  *             return not (x == y)
  *         raise NotImplemented('comparison not implemented for SparseVector')             # <<<<<<<<<<<<<<
  * 
  *     def __len__(self):
  */
-  __pyx_t_1 = PyObject_Call(__pyx_builtin_NotImplemented, ((PyObject *)__pyx_k_tuple_5), NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 76; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_1 = PyObject_Call(__pyx_builtin_NotImplemented, ((PyObject *)__pyx_k_tuple_5), NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 77; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __Pyx_GOTREF(__pyx_t_1);
   __Pyx_Raise(__pyx_t_1, 0, 0, 0);
   __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
-  {__pyx_filename = __pyx_f[1]; __pyx_lineno = 76; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  {__pyx_filename = __pyx_f[1]; __pyx_lineno = 77; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
 
   __pyx_r = Py_None; __Pyx_INCREF(Py_None);
   goto __pyx_L0;
@@ -3227,7 +3393,7 @@ static Py_ssize_t __pyx_pw_5_cdec_12SparseVector_16__len__(PyObject *__pyx_v_sel
   return __pyx_r;
 }
 
-/* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":78
+/* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":79
  *         raise NotImplemented('comparison not implemented for SparseVector')
  * 
  *     def __len__(self):             # <<<<<<<<<<<<<<
@@ -3240,7 +3406,7 @@ static Py_ssize_t __pyx_pf_5_cdec_12SparseVector_15__len__(struct __pyx_obj_5_cd
   __Pyx_RefNannyDeclarations
   __Pyx_RefNannySetupContext("__len__", 0);
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":79
+  /* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":80
  * 
  *     def __len__(self):
  *         return self.vector.size()             # <<<<<<<<<<<<<<
@@ -3264,7 +3430,7 @@ static int __pyx_pw_5_cdec_12SparseVector_18__contains__(PyObject *__pyx_v_self,
   __Pyx_RefNannyDeclarations
   __Pyx_RefNannySetupContext("__contains__ (wrapper)", 0);
   assert(__pyx_arg_fname); {
-    __pyx_v_fname = PyBytes_AsString(__pyx_arg_fname); if (unlikely((!__pyx_v_fname) && PyErr_Occurred())) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 81; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+    __pyx_v_fname = PyBytes_AsString(__pyx_arg_fname); if (unlikely((!__pyx_v_fname) && PyErr_Occurred())) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 82; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
   }
   goto __pyx_L4_argument_unpacking_done;
   __pyx_L3_error:;
@@ -3277,7 +3443,7 @@ static int __pyx_pw_5_cdec_12SparseVector_18__contains__(PyObject *__pyx_v_self,
   return __pyx_r;
 }
 
-/* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":81
+/* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":82
  *         return self.vector.size()
  * 
  *     def __contains__(self, char* fname):             # <<<<<<<<<<<<<<
@@ -3290,7 +3456,7 @@ static int __pyx_pf_5_cdec_12SparseVector_17__contains__(struct __pyx_obj_5_cdec
   __Pyx_RefNannyDeclarations
   __Pyx_RefNannySetupContext("__contains__", 0);
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":82
+  /* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":83
  * 
  *     def __contains__(self, char* fname):
  *         return self.vector.nonzero(FDConvert(fname))             # <<<<<<<<<<<<<<
@@ -3317,7 +3483,7 @@ static PyObject *__pyx_pw_5_cdec_12SparseVector_20__neg__(PyObject *__pyx_v_self
   return __pyx_r;
 }
 
-/* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":84
+/* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":85
  *         return self.vector.nonzero(FDConvert(fname))
  * 
  *     def __neg__(self):             # <<<<<<<<<<<<<<
@@ -3335,19 +3501,19 @@ static PyObject *__pyx_pf_5_cdec_12SparseVector_19__neg__(struct __pyx_obj_5_cde
   int __pyx_clineno = 0;
   __Pyx_RefNannySetupContext("__neg__", 0);
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":85
+  /* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":86
  * 
  *     def __neg__(self):
  *         cdef SparseVector result = SparseVector()             # <<<<<<<<<<<<<<
  *         result.vector = new FastSparseVector[weight_t](self.vector[0])
  *         result.vector[0] *= -1.0
  */
-  __pyx_t_1 = PyObject_Call(((PyObject *)((PyObject*)__pyx_ptype_5_cdec_SparseVector)), ((PyObject *)__pyx_empty_tuple), NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 85; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_1 = PyObject_Call(((PyObject *)((PyObject*)__pyx_ptype_5_cdec_SparseVector)), ((PyObject *)__pyx_empty_tuple), NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 86; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __Pyx_GOTREF(__pyx_t_1);
   __pyx_v_result = ((struct __pyx_obj_5_cdec_SparseVector *)__pyx_t_1);
   __pyx_t_1 = 0;
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":86
+  /* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":87
  *     def __neg__(self):
  *         cdef SparseVector result = SparseVector()
  *         result.vector = new FastSparseVector[weight_t](self.vector[0])             # <<<<<<<<<<<<<<
@@ -3356,7 +3522,7 @@ static PyObject *__pyx_pf_5_cdec_12SparseVector_19__neg__(struct __pyx_obj_5_cde
  */
   __pyx_v_result->vector = new FastSparseVector<weight_t>((__pyx_v_self->vector[0]));
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":87
+  /* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":88
  *         cdef SparseVector result = SparseVector()
  *         result.vector = new FastSparseVector[weight_t](self.vector[0])
  *         result.vector[0] *= -1.0             # <<<<<<<<<<<<<<
@@ -3365,7 +3531,7 @@ static PyObject *__pyx_pf_5_cdec_12SparseVector_19__neg__(struct __pyx_obj_5_cde
  */
   (__pyx_v_result->vector[0]) *= -1.0;
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":88
+  /* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":89
  *         result.vector = new FastSparseVector[weight_t](self.vector[0])
  *         result.vector[0] *= -1.0
  *         return result             # <<<<<<<<<<<<<<
@@ -3396,7 +3562,7 @@ static PyObject *__pyx_pw_5_cdec_12SparseVector_22__iadd__(PyObject *__pyx_v_sel
   PyObject *__pyx_r = 0;
   __Pyx_RefNannyDeclarations
   __Pyx_RefNannySetupContext("__iadd__ (wrapper)", 0);
-  if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_other), __pyx_ptype_5_cdec_SparseVector, 1, "other", 0))) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 90; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_other), __pyx_ptype_5_cdec_SparseVector, 1, "other", 0))) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 91; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __pyx_r = __pyx_pf_5_cdec_12SparseVector_21__iadd__(((struct __pyx_obj_5_cdec_SparseVector *)__pyx_v_self), ((struct __pyx_obj_5_cdec_SparseVector *)__pyx_v_other));
   goto __pyx_L0;
   __pyx_L1_error:;
@@ -3406,7 +3572,7 @@ static PyObject *__pyx_pw_5_cdec_12SparseVector_22__iadd__(PyObject *__pyx_v_sel
   return __pyx_r;
 }
 
-/* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":90
+/* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":91
  *         return result
  * 
  *     def __iadd__(SparseVector self, SparseVector other):             # <<<<<<<<<<<<<<
@@ -3419,7 +3585,7 @@ static PyObject *__pyx_pf_5_cdec_12SparseVector_21__iadd__(struct __pyx_obj_5_cd
   __Pyx_RefNannyDeclarations
   __Pyx_RefNannySetupContext("__iadd__", 0);
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":91
+  /* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":92
  * 
  *     def __iadd__(SparseVector self, SparseVector other):
  *         self.vector[0] += other.vector[0]             # <<<<<<<<<<<<<<
@@ -3428,7 +3594,7 @@ static PyObject *__pyx_pf_5_cdec_12SparseVector_21__iadd__(struct __pyx_obj_5_cd
  */
   (__pyx_v_self->vector[0]) += (__pyx_v_other->vector[0]);
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":92
+  /* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":93
  *     def __iadd__(SparseVector self, SparseVector other):
  *         self.vector[0] += other.vector[0]
  *         return self             # <<<<<<<<<<<<<<
@@ -3453,7 +3619,7 @@ static PyObject *__pyx_pw_5_cdec_12SparseVector_24__isub__(PyObject *__pyx_v_sel
   PyObject *__pyx_r = 0;
   __Pyx_RefNannyDeclarations
   __Pyx_RefNannySetupContext("__isub__ (wrapper)", 0);
-  if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_other), __pyx_ptype_5_cdec_SparseVector, 1, "other", 0))) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 94; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_other), __pyx_ptype_5_cdec_SparseVector, 1, "other", 0))) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 95; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __pyx_r = __pyx_pf_5_cdec_12SparseVector_23__isub__(((struct __pyx_obj_5_cdec_SparseVector *)__pyx_v_self), ((struct __pyx_obj_5_cdec_SparseVector *)__pyx_v_other));
   goto __pyx_L0;
   __pyx_L1_error:;
@@ -3463,7 +3629,7 @@ static PyObject *__pyx_pw_5_cdec_12SparseVector_24__isub__(PyObject *__pyx_v_sel
   return __pyx_r;
 }
 
-/* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":94
+/* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":95
  *         return self
  * 
  *     def __isub__(SparseVector self, SparseVector other):             # <<<<<<<<<<<<<<
@@ -3476,7 +3642,7 @@ static PyObject *__pyx_pf_5_cdec_12SparseVector_23__isub__(struct __pyx_obj_5_cd
   __Pyx_RefNannyDeclarations
   __Pyx_RefNannySetupContext("__isub__", 0);
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":95
+  /* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":96
  * 
  *     def __isub__(SparseVector self, SparseVector other):
  *         self.vector[0] -= other.vector[0]             # <<<<<<<<<<<<<<
@@ -3485,7 +3651,7 @@ static PyObject *__pyx_pf_5_cdec_12SparseVector_23__isub__(struct __pyx_obj_5_cd
  */
   (__pyx_v_self->vector[0]) -= (__pyx_v_other->vector[0]);
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":96
+  /* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":97
  *     def __isub__(SparseVector self, SparseVector other):
  *         self.vector[0] -= other.vector[0]
  *         return self             # <<<<<<<<<<<<<<
@@ -3512,7 +3678,7 @@ static PyObject *__pyx_pw_5_cdec_12SparseVector_26__imul__(PyObject *__pyx_v_sel
   __Pyx_RefNannyDeclarations
   __Pyx_RefNannySetupContext("__imul__ (wrapper)", 0);
   assert(__pyx_arg_scalar); {
-    __pyx_v_scalar = __pyx_PyFloat_AsFloat(__pyx_arg_scalar); if (unlikely((__pyx_v_scalar == (float)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 98; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+    __pyx_v_scalar = __pyx_PyFloat_AsFloat(__pyx_arg_scalar); if (unlikely((__pyx_v_scalar == (float)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 99; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
   }
   goto __pyx_L4_argument_unpacking_done;
   __pyx_L3_error:;
@@ -3525,7 +3691,7 @@ static PyObject *__pyx_pw_5_cdec_12SparseVector_26__imul__(PyObject *__pyx_v_sel
   return __pyx_r;
 }
 
-/* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":98
+/* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":99
  *         return self
  * 
  *     def __imul__(SparseVector self, float scalar):             # <<<<<<<<<<<<<<
@@ -3538,7 +3704,7 @@ static PyObject *__pyx_pf_5_cdec_12SparseVector_25__imul__(struct __pyx_obj_5_cd
   __Pyx_RefNannyDeclarations
   __Pyx_RefNannySetupContext("__imul__", 0);
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":99
+  /* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":100
  * 
  *     def __imul__(SparseVector self, float scalar):
  *         self.vector[0] *= scalar             # <<<<<<<<<<<<<<
@@ -3547,7 +3713,7 @@ static PyObject *__pyx_pf_5_cdec_12SparseVector_25__imul__(struct __pyx_obj_5_cd
  */
   (__pyx_v_self->vector[0]) *= __pyx_v_scalar;
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":100
+  /* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":101
  *     def __imul__(SparseVector self, float scalar):
  *         self.vector[0] *= scalar
  *         return self             # <<<<<<<<<<<<<<
@@ -3575,7 +3741,7 @@ static PyObject *__pyx_pw_5_cdec_12SparseVector_28__idiv__(PyObject *__pyx_v_sel
   __Pyx_RefNannyDeclarations
   __Pyx_RefNannySetupContext("__idiv__ (wrapper)", 0);
   assert(__pyx_arg_scalar); {
-    __pyx_v_scalar = __pyx_PyFloat_AsFloat(__pyx_arg_scalar); if (unlikely((__pyx_v_scalar == (float)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 102; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+    __pyx_v_scalar = __pyx_PyFloat_AsFloat(__pyx_arg_scalar); if (unlikely((__pyx_v_scalar == (float)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 103; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
   }
   goto __pyx_L4_argument_unpacking_done;
   __pyx_L3_error:;
@@ -3589,7 +3755,7 @@ static PyObject *__pyx_pw_5_cdec_12SparseVector_28__idiv__(PyObject *__pyx_v_sel
 }
 #endif /*!(#if PY_MAJOR_VERSION < 3)*/
 
-/* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":102
+/* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":103
  *         return self
  * 
  *     def __idiv__(SparseVector self, float scalar):             # <<<<<<<<<<<<<<
@@ -3603,7 +3769,7 @@ static PyObject *__pyx_pf_5_cdec_12SparseVector_27__idiv__(struct __pyx_obj_5_cd
   __Pyx_RefNannyDeclarations
   __Pyx_RefNannySetupContext("__idiv__", 0);
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":103
+  /* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":104
  * 
  *     def __idiv__(SparseVector self, float scalar):
  *         self.vector[0] /= scalar             # <<<<<<<<<<<<<<
@@ -3612,7 +3778,7 @@ static PyObject *__pyx_pf_5_cdec_12SparseVector_27__idiv__(struct __pyx_obj_5_cd
  */
   (__pyx_v_self->vector[0]) /= __pyx_v_scalar;
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":104
+  /* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":105
  *     def __idiv__(SparseVector self, float scalar):
  *         self.vector[0] /= scalar
  *         return self             # <<<<<<<<<<<<<<
@@ -3638,8 +3804,8 @@ static PyObject *__pyx_pw_5_cdec_12SparseVector_30__add__(PyObject *__pyx_v_x, P
   PyObject *__pyx_r = 0;
   __Pyx_RefNannyDeclarations
   __Pyx_RefNannySetupContext("__add__ (wrapper)", 0);
-  if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_x), __pyx_ptype_5_cdec_SparseVector, 1, "x", 0))) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 106; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_y), __pyx_ptype_5_cdec_SparseVector, 1, "y", 0))) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 106; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_x), __pyx_ptype_5_cdec_SparseVector, 1, "x", 0))) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 107; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_y), __pyx_ptype_5_cdec_SparseVector, 1, "y", 0))) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 107; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __pyx_r = __pyx_pf_5_cdec_12SparseVector_29__add__(((struct __pyx_obj_5_cdec_SparseVector *)__pyx_v_x), ((struct __pyx_obj_5_cdec_SparseVector *)__pyx_v_y));
   goto __pyx_L0;
   __pyx_L1_error:;
@@ -3649,7 +3815,7 @@ static PyObject *__pyx_pw_5_cdec_12SparseVector_30__add__(PyObject *__pyx_v_x, P
   return __pyx_r;
 }
 
-/* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":106
+/* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":107
  *         return self
  * 
  *     def __add__(SparseVector x, SparseVector y):             # <<<<<<<<<<<<<<
@@ -3667,19 +3833,19 @@ static PyObject *__pyx_pf_5_cdec_12SparseVector_29__add__(struct __pyx_obj_5_cde
   int __pyx_clineno = 0;
   __Pyx_RefNannySetupContext("__add__", 0);
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":107
+  /* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":108
  * 
  *     def __add__(SparseVector x, SparseVector y):
  *         cdef SparseVector result = SparseVector()             # <<<<<<<<<<<<<<
  *         result.vector = new FastSparseVector[weight_t](x.vector[0] + y.vector[0])
  *         return result
  */
-  __pyx_t_1 = PyObject_Call(((PyObject *)((PyObject*)__pyx_ptype_5_cdec_SparseVector)), ((PyObject *)__pyx_empty_tuple), NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 107; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_1 = PyObject_Call(((PyObject *)((PyObject*)__pyx_ptype_5_cdec_SparseVector)), ((PyObject *)__pyx_empty_tuple), NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 108; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __Pyx_GOTREF(__pyx_t_1);
   __pyx_v_result = ((struct __pyx_obj_5_cdec_SparseVector *)__pyx_t_1);
   __pyx_t_1 = 0;
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":108
+  /* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":109
  *     def __add__(SparseVector x, SparseVector y):
  *         cdef SparseVector result = SparseVector()
  *         result.vector = new FastSparseVector[weight_t](x.vector[0] + y.vector[0])             # <<<<<<<<<<<<<<
@@ -3688,7 +3854,7 @@ static PyObject *__pyx_pf_5_cdec_12SparseVector_29__add__(struct __pyx_obj_5_cde
  */
   __pyx_v_result->vector = new FastSparseVector<weight_t>(((__pyx_v_x->vector[0]) + (__pyx_v_y->vector[0])));
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":109
+  /* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":110
  *         cdef SparseVector result = SparseVector()
  *         result.vector = new FastSparseVector[weight_t](x.vector[0] + y.vector[0])
  *         return result             # <<<<<<<<<<<<<<
@@ -3719,8 +3885,8 @@ static PyObject *__pyx_pw_5_cdec_12SparseVector_32__sub__(PyObject *__pyx_v_x, P
   PyObject *__pyx_r = 0;
   __Pyx_RefNannyDeclarations
   __Pyx_RefNannySetupContext("__sub__ (wrapper)", 0);
-  if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_x), __pyx_ptype_5_cdec_SparseVector, 1, "x", 0))) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 111; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_y), __pyx_ptype_5_cdec_SparseVector, 1, "y", 0))) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 111; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_x), __pyx_ptype_5_cdec_SparseVector, 1, "x", 0))) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 112; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_y), __pyx_ptype_5_cdec_SparseVector, 1, "y", 0))) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 112; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __pyx_r = __pyx_pf_5_cdec_12SparseVector_31__sub__(((struct __pyx_obj_5_cdec_SparseVector *)__pyx_v_x), ((struct __pyx_obj_5_cdec_SparseVector *)__pyx_v_y));
   goto __pyx_L0;
   __pyx_L1_error:;
@@ -3730,7 +3896,7 @@ static PyObject *__pyx_pw_5_cdec_12SparseVector_32__sub__(PyObject *__pyx_v_x, P
   return __pyx_r;
 }
 
-/* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":111
+/* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":112
  *         return result
  * 
  *     def __sub__(SparseVector x, SparseVector y):             # <<<<<<<<<<<<<<
@@ -3748,19 +3914,19 @@ static PyObject *__pyx_pf_5_cdec_12SparseVector_31__sub__(struct __pyx_obj_5_cde
   int __pyx_clineno = 0;
   __Pyx_RefNannySetupContext("__sub__", 0);
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":112
+  /* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":113
  * 
  *     def __sub__(SparseVector x, SparseVector y):
  *         cdef SparseVector result = SparseVector()             # <<<<<<<<<<<<<<
  *         result.vector = new FastSparseVector[weight_t](x.vector[0] - y.vector[0])
  *         return result
  */
-  __pyx_t_1 = PyObject_Call(((PyObject *)((PyObject*)__pyx_ptype_5_cdec_SparseVector)), ((PyObject *)__pyx_empty_tuple), NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 112; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_1 = PyObject_Call(((PyObject *)((PyObject*)__pyx_ptype_5_cdec_SparseVector)), ((PyObject *)__pyx_empty_tuple), NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 113; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __Pyx_GOTREF(__pyx_t_1);
   __pyx_v_result = ((struct __pyx_obj_5_cdec_SparseVector *)__pyx_t_1);
   __pyx_t_1 = 0;
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":113
+  /* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":114
  *     def __sub__(SparseVector x, SparseVector y):
  *         cdef SparseVector result = SparseVector()
  *         result.vector = new FastSparseVector[weight_t](x.vector[0] - y.vector[0])             # <<<<<<<<<<<<<<
@@ -3769,7 +3935,7 @@ static PyObject *__pyx_pf_5_cdec_12SparseVector_31__sub__(struct __pyx_obj_5_cde
  */
   __pyx_v_result->vector = new FastSparseVector<weight_t>(((__pyx_v_x->vector[0]) - (__pyx_v_y->vector[0])));
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":114
+  /* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":115
  *         cdef SparseVector result = SparseVector()
  *         result.vector = new FastSparseVector[weight_t](x.vector[0] - y.vector[0])
  *         return result             # <<<<<<<<<<<<<<
@@ -3805,7 +3971,7 @@ static PyObject *__pyx_pw_5_cdec_12SparseVector_34__mul__(PyObject *__pyx_v_x, P
   return __pyx_r;
 }
 
-/* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":116
+/* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":117
  *         return result
  * 
  *     def __mul__(x, y):             # <<<<<<<<<<<<<<
@@ -3827,7 +3993,7 @@ static PyObject *__pyx_pf_5_cdec_12SparseVector_33__mul__(PyObject *__pyx_v_x, P
   int __pyx_clineno = 0;
   __Pyx_RefNannySetupContext("__mul__", 0);
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":119
+  /* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":120
  *         cdef SparseVector vector
  *         cdef float scalar
  *         if isinstance(x, SparseVector): vector, scalar = x, y             # <<<<<<<<<<<<<<
@@ -3839,10 +4005,10 @@ static PyObject *__pyx_pf_5_cdec_12SparseVector_33__mul__(PyObject *__pyx_v_x, P
   __pyx_t_2 = __Pyx_TypeCheck(__pyx_v_x, __pyx_t_1); 
   __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
   if (__pyx_t_2) {
-    if (!(likely(((__pyx_v_x) == Py_None) || likely(__Pyx_TypeTest(__pyx_v_x, __pyx_ptype_5_cdec_SparseVector))))) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 119; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    if (!(likely(((__pyx_v_x) == Py_None) || likely(__Pyx_TypeTest(__pyx_v_x, __pyx_ptype_5_cdec_SparseVector))))) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 120; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
     __pyx_t_1 = __pyx_v_x;
     __Pyx_INCREF(__pyx_t_1);
-    __pyx_t_3 = __pyx_PyFloat_AsFloat(__pyx_v_y); if (unlikely((__pyx_t_3 == (float)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 119; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_t_3 = __pyx_PyFloat_AsFloat(__pyx_v_y); if (unlikely((__pyx_t_3 == (float)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 120; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
     __pyx_v_vector = ((struct __pyx_obj_5_cdec_SparseVector *)__pyx_t_1);
     __pyx_t_1 = 0;
     __pyx_v_scalar = __pyx_t_3;
@@ -3850,36 +4016,36 @@ static PyObject *__pyx_pf_5_cdec_12SparseVector_33__mul__(PyObject *__pyx_v_x, P
   }
   /*else*/ {
 
-    /* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":120
+    /* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":121
  *         cdef float scalar
  *         if isinstance(x, SparseVector): vector, scalar = x, y
  *         else: vector, scalar = y, x             # <<<<<<<<<<<<<<
  *         cdef SparseVector result = SparseVector()
  *         result.vector = new FastSparseVector[weight_t](vector.vector[0] * scalar)
  */
-    if (!(likely(((__pyx_v_y) == Py_None) || likely(__Pyx_TypeTest(__pyx_v_y, __pyx_ptype_5_cdec_SparseVector))))) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 120; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    if (!(likely(((__pyx_v_y) == Py_None) || likely(__Pyx_TypeTest(__pyx_v_y, __pyx_ptype_5_cdec_SparseVector))))) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 121; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
     __pyx_t_1 = __pyx_v_y;
     __Pyx_INCREF(__pyx_t_1);
-    __pyx_t_3 = __pyx_PyFloat_AsFloat(__pyx_v_x); if (unlikely((__pyx_t_3 == (float)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 120; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_t_3 = __pyx_PyFloat_AsFloat(__pyx_v_x); if (unlikely((__pyx_t_3 == (float)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 121; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
     __pyx_v_vector = ((struct __pyx_obj_5_cdec_SparseVector *)__pyx_t_1);
     __pyx_t_1 = 0;
     __pyx_v_scalar = __pyx_t_3;
   }
   __pyx_L3:;
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":121
+  /* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":122
  *         if isinstance(x, SparseVector): vector, scalar = x, y
  *         else: vector, scalar = y, x
  *         cdef SparseVector result = SparseVector()             # <<<<<<<<<<<<<<
  *         result.vector = new FastSparseVector[weight_t](vector.vector[0] * scalar)
  *         return result
  */
-  __pyx_t_1 = PyObject_Call(((PyObject *)((PyObject*)__pyx_ptype_5_cdec_SparseVector)), ((PyObject *)__pyx_empty_tuple), NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 121; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_1 = PyObject_Call(((PyObject *)((PyObject*)__pyx_ptype_5_cdec_SparseVector)), ((PyObject *)__pyx_empty_tuple), NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 122; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __Pyx_GOTREF(__pyx_t_1);
   __pyx_v_result = ((struct __pyx_obj_5_cdec_SparseVector *)__pyx_t_1);
   __pyx_t_1 = 0;
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":122
+  /* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":123
  *         else: vector, scalar = y, x
  *         cdef SparseVector result = SparseVector()
  *         result.vector = new FastSparseVector[weight_t](vector.vector[0] * scalar)             # <<<<<<<<<<<<<<
@@ -3888,7 +4054,7 @@ static PyObject *__pyx_pf_5_cdec_12SparseVector_33__mul__(PyObject *__pyx_v_x, P
  */
   __pyx_v_result->vector = new FastSparseVector<weight_t>(((__pyx_v_vector->vector[0]) * __pyx_v_scalar));
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":123
+  /* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":124
  *         cdef SparseVector result = SparseVector()
  *         result.vector = new FastSparseVector[weight_t](vector.vector[0] * scalar)
  *         return result             # <<<<<<<<<<<<<<
@@ -3927,7 +4093,7 @@ static PyObject *__pyx_pw_5_cdec_12SparseVector_36__div__(PyObject *__pyx_v_x, P
 }
 #endif /*!(#if PY_MAJOR_VERSION < 3)*/
 
-/* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":125
+/* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":126
  *         return result
  * 
  *     def __div__(x, y):             # <<<<<<<<<<<<<<
@@ -3950,7 +4116,7 @@ static PyObject *__pyx_pf_5_cdec_12SparseVector_35__div__(PyObject *__pyx_v_x, P
   int __pyx_clineno = 0;
   __Pyx_RefNannySetupContext("__div__", 0);
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":128
+  /* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":129
  *         cdef SparseVector vector
  *         cdef float scalar
  *         if isinstance(x, SparseVector): vector, scalar = x, y             # <<<<<<<<<<<<<<
@@ -3962,10 +4128,10 @@ static PyObject *__pyx_pf_5_cdec_12SparseVector_35__div__(PyObject *__pyx_v_x, P
   __pyx_t_2 = __Pyx_TypeCheck(__pyx_v_x, __pyx_t_1); 
   __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
   if (__pyx_t_2) {
-    if (!(likely(((__pyx_v_x) == Py_None) || likely(__Pyx_TypeTest(__pyx_v_x, __pyx_ptype_5_cdec_SparseVector))))) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 128; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    if (!(likely(((__pyx_v_x) == Py_None) || likely(__Pyx_TypeTest(__pyx_v_x, __pyx_ptype_5_cdec_SparseVector))))) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 129; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
     __pyx_t_1 = __pyx_v_x;
     __Pyx_INCREF(__pyx_t_1);
-    __pyx_t_3 = __pyx_PyFloat_AsFloat(__pyx_v_y); if (unlikely((__pyx_t_3 == (float)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 128; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_t_3 = __pyx_PyFloat_AsFloat(__pyx_v_y); if (unlikely((__pyx_t_3 == (float)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 129; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
     __pyx_v_vector = ((struct __pyx_obj_5_cdec_SparseVector *)__pyx_t_1);
     __pyx_t_1 = 0;
     __pyx_v_scalar = __pyx_t_3;
@@ -3973,36 +4139,36 @@ static PyObject *__pyx_pf_5_cdec_12SparseVector_35__div__(PyObject *__pyx_v_x, P
   }
   /*else*/ {
 
-    /* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":129
+    /* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":130
  *         cdef float scalar
  *         if isinstance(x, SparseVector): vector, scalar = x, y
  *         else: vector, scalar = y, x             # <<<<<<<<<<<<<<
  *         cdef SparseVector result = SparseVector()
  *         result.vector = new FastSparseVector[weight_t](vector.vector[0] / scalar)
  */
-    if (!(likely(((__pyx_v_y) == Py_None) || likely(__Pyx_TypeTest(__pyx_v_y, __pyx_ptype_5_cdec_SparseVector))))) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 129; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    if (!(likely(((__pyx_v_y) == Py_None) || likely(__Pyx_TypeTest(__pyx_v_y, __pyx_ptype_5_cdec_SparseVector))))) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 130; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
     __pyx_t_1 = __pyx_v_y;
     __Pyx_INCREF(__pyx_t_1);
-    __pyx_t_3 = __pyx_PyFloat_AsFloat(__pyx_v_x); if (unlikely((__pyx_t_3 == (float)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 129; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_t_3 = __pyx_PyFloat_AsFloat(__pyx_v_x); if (unlikely((__pyx_t_3 == (float)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 130; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
     __pyx_v_vector = ((struct __pyx_obj_5_cdec_SparseVector *)__pyx_t_1);
     __pyx_t_1 = 0;
     __pyx_v_scalar = __pyx_t_3;
   }
   __pyx_L3:;
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":130
+  /* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":131
  *         if isinstance(x, SparseVector): vector, scalar = x, y
  *         else: vector, scalar = y, x
  *         cdef SparseVector result = SparseVector()             # <<<<<<<<<<<<<<
  *         result.vector = new FastSparseVector[weight_t](vector.vector[0] / scalar)
  *         return result
  */
-  __pyx_t_1 = PyObject_Call(((PyObject *)((PyObject*)__pyx_ptype_5_cdec_SparseVector)), ((PyObject *)__pyx_empty_tuple), NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 130; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_1 = PyObject_Call(((PyObject *)((PyObject*)__pyx_ptype_5_cdec_SparseVector)), ((PyObject *)__pyx_empty_tuple), NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 131; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __Pyx_GOTREF(__pyx_t_1);
   __pyx_v_result = ((struct __pyx_obj_5_cdec_SparseVector *)__pyx_t_1);
   __pyx_t_1 = 0;
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":131
+  /* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":132
  *         else: vector, scalar = y, x
  *         cdef SparseVector result = SparseVector()
  *         result.vector = new FastSparseVector[weight_t](vector.vector[0] / scalar)             # <<<<<<<<<<<<<<
@@ -4010,7 +4176,7 @@ static PyObject *__pyx_pf_5_cdec_12SparseVector_35__div__(PyObject *__pyx_v_x, P
  */
   __pyx_v_result->vector = new FastSparseVector<weight_t>(((__pyx_v_vector->vector[0]) / __pyx_v_scalar));
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":132
+  /* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":133
  *         cdef SparseVector result = SparseVector()
  *         result.vector = new FastSparseVector[weight_t](vector.vector[0] / scalar)
  *         return result             # <<<<<<<<<<<<<<
@@ -4036,376 +4202,486 @@ static PyObject *__pyx_pf_5_cdec_12SparseVector_35__div__(PyObject *__pyx_v_x, P
 #endif /*!(#if PY_MAJOR_VERSION < 3)*/
 
 /* Python wrapper */
-static void __pyx_pw_5_cdec_10Hypergraph_1__dealloc__(PyObject *__pyx_v_self); /*proto*/
-static void __pyx_pw_5_cdec_10Hypergraph_1__dealloc__(PyObject *__pyx_v_self) {
+static PyObject *__pyx_pw_5_cdec_1_phrase(PyObject *__pyx_self, PyObject *__pyx_v_phrase); /*proto*/
+static PyMethodDef __pyx_mdef_5_cdec_1_phrase = {__Pyx_NAMESTR("_phrase"), (PyCFunction)__pyx_pw_5_cdec_1_phrase, METH_O, __Pyx_DOCSTR(0)};
+static PyObject *__pyx_pw_5_cdec_1_phrase(PyObject *__pyx_self, PyObject *__pyx_v_phrase) {
+  PyObject *__pyx_r = 0;
   __Pyx_RefNannyDeclarations
-  __Pyx_RefNannySetupContext("__dealloc__ (wrapper)", 0);
-  __pyx_pf_5_cdec_10Hypergraph___dealloc__(((struct __pyx_obj_5_cdec_Hypergraph *)__pyx_v_self));
+  __Pyx_RefNannySetupContext("_phrase (wrapper)", 0);
+  __pyx_self = __pyx_self;
+  __pyx_r = __pyx_pf_5_cdec__phrase(__pyx_self, ((PyObject *)__pyx_v_phrase));
   __Pyx_RefNannyFinishContext();
+  return __pyx_r;
 }
+static PyObject *__pyx_gb_5_cdec_7_phrase_2generator17(__pyx_GeneratorObject *__pyx_generator, PyObject *__pyx_sent_value); /* proto */
 
-/* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":8
- *     cdef MT19937* rng
- * 
- *     def __dealloc__(self):             # <<<<<<<<<<<<<<
- *         del self.hg
- *         if self.rng != NULL:
- */
-
-static void __pyx_pf_5_cdec_10Hypergraph___dealloc__(struct __pyx_obj_5_cdec_Hypergraph *__pyx_v_self) {
-  __Pyx_RefNannyDeclarations
-  int __pyx_t_1;
-  __Pyx_RefNannySetupContext("__dealloc__", 0);
-
-  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":9
+/* "/Users/vchahun/Sandbox/cdec/python/src/grammar.pxi":4
  * 
- *     def __dealloc__(self):
- *         del self.hg             # <<<<<<<<<<<<<<
- *         if self.rng != NULL:
- *             del self.rng
- */
-  delete __pyx_v_self->hg;
-
-  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":10
- *     def __dealloc__(self):
- *         del self.hg
- *         if self.rng != NULL:             # <<<<<<<<<<<<<<
- *             del self.rng
+ * def _phrase(phrase):
+ *     return ' '.join(w.encode('utf8') if isinstance(w, unicode) else str(w) for w in phrase)             # <<<<<<<<<<<<<<
  * 
+ * cdef class NT:
  */
-  __pyx_t_1 = (__pyx_v_self->rng != NULL);
-  if (__pyx_t_1) {
 
-    /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":11
- *         del self.hg
- *         if self.rng != NULL:
- *             del self.rng             # <<<<<<<<<<<<<<
- * 
- *     def viterbi(self):
- */
-    delete __pyx_v_self->rng;
-    goto __pyx_L3;
+static PyObject *__pyx_pf_5_cdec_7_phrase_genexpr(PyObject *__pyx_self) {
+  struct __pyx_obj_5_cdec___pyx_scope_struct_3_genexpr *__pyx_cur_scope;
+  PyObject *__pyx_r = NULL;
+  __Pyx_RefNannyDeclarations
+  int __pyx_lineno = 0;
+  const char *__pyx_filename = NULL;
+  int __pyx_clineno = 0;
+  __Pyx_RefNannySetupContext("genexpr", 0);
+  __pyx_cur_scope = (struct __pyx_obj_5_cdec___pyx_scope_struct_3_genexpr *)__pyx_ptype_5_cdec___pyx_scope_struct_3_genexpr->tp_new(__pyx_ptype_5_cdec___pyx_scope_struct_3_genexpr, __pyx_empty_tuple, NULL);
+  if (unlikely(!__pyx_cur_scope)) {
+    __Pyx_RefNannyFinishContext();
+    return NULL;
+  }
+  __Pyx_GOTREF(__pyx_cur_scope);
+  __pyx_cur_scope->__pyx_outer_scope = (struct __pyx_obj_5_cdec___pyx_scope_struct_2__phrase *) __pyx_self;
+  __Pyx_INCREF(((PyObject *)__pyx_cur_scope->__pyx_outer_scope));
+  __Pyx_GIVEREF(__pyx_cur_scope->__pyx_outer_scope);
+  {
+    __pyx_GeneratorObject *gen = __Pyx_Generator_New((__pyx_generator_body_t) __pyx_gb_5_cdec_7_phrase_2generator17, (PyObject *) __pyx_cur_scope); if (unlikely(!gen)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 4; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_DECREF(__pyx_cur_scope);
+    __Pyx_RefNannyFinishContext();
+    return (PyObject *) gen;
   }
-  __pyx_L3:;
 
+  __pyx_r = Py_None; __Pyx_INCREF(Py_None);
+  goto __pyx_L0;
+  __pyx_L1_error:;
+  __Pyx_AddTraceback("_cdec._phrase.genexpr", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __pyx_r = NULL;
+  __pyx_L0:;
+  __Pyx_DECREF(((PyObject *)__pyx_cur_scope));
+  __Pyx_XGIVEREF(__pyx_r);
   __Pyx_RefNannyFinishContext();
+  return __pyx_r;
 }
 
-/* Python wrapper */
-static PyObject *__pyx_pw_5_cdec_10Hypergraph_3viterbi(PyObject *__pyx_v_self, CYTHON_UNUSED PyObject *unused); /*proto*/
-static PyObject *__pyx_pw_5_cdec_10Hypergraph_3viterbi(PyObject *__pyx_v_self, CYTHON_UNUSED PyObject *unused) {
-  PyObject *__pyx_r = 0;
+static PyObject *__pyx_gb_5_cdec_7_phrase_2generator17(__pyx_GeneratorObject *__pyx_generator, PyObject *__pyx_sent_value) /* generator body */
+{
+  struct __pyx_obj_5_cdec___pyx_scope_struct_3_genexpr *__pyx_cur_scope = ((struct __pyx_obj_5_cdec___pyx_scope_struct_3_genexpr *)__pyx_generator->closure);
+  PyObject *__pyx_r = NULL;
+  PyObject *__pyx_t_1 = NULL;
+  Py_ssize_t __pyx_t_2;
+  PyObject *(*__pyx_t_3)(PyObject *);
+  PyObject *__pyx_t_4 = NULL;
+  PyObject *__pyx_t_5 = NULL;
+  int __pyx_t_6;
+  PyObject *__pyx_t_7 = NULL;
   __Pyx_RefNannyDeclarations
-  __Pyx_RefNannySetupContext("viterbi (wrapper)", 0);
-  __pyx_r = __pyx_pf_5_cdec_10Hypergraph_2viterbi(((struct __pyx_obj_5_cdec_Hypergraph *)__pyx_v_self));
+  __Pyx_RefNannySetupContext("None", 0);
+  switch (__pyx_generator->resume_label) {
+    case 0: goto __pyx_L3_first_run;
+    case 1: goto __pyx_L6_resume_from_yield;
+    default: /* CPython raises the right error here */
+    __Pyx_RefNannyFinishContext();
+    return NULL;
+  }
+  __pyx_L3_first_run:;
+  if (unlikely(!__pyx_sent_value)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 4; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (unlikely(!__pyx_cur_scope->__pyx_outer_scope->__pyx_v_phrase)) { __Pyx_RaiseClosureNameError("phrase"); {__pyx_filename = __pyx_f[2]; __pyx_lineno = 4; __pyx_clineno = __LINE__; goto __pyx_L1_error;} }
+  if (PyList_CheckExact(__pyx_cur_scope->__pyx_outer_scope->__pyx_v_phrase) || PyTuple_CheckExact(__pyx_cur_scope->__pyx_outer_scope->__pyx_v_phrase)) {
+    __pyx_t_1 = __pyx_cur_scope->__pyx_outer_scope->__pyx_v_phrase; __Pyx_INCREF(__pyx_t_1); __pyx_t_2 = 0;
+    __pyx_t_3 = NULL;
+  } else {
+    __pyx_t_2 = -1; __pyx_t_1 = PyObject_GetIter(__pyx_cur_scope->__pyx_outer_scope->__pyx_v_phrase); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 4; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_1);
+    __pyx_t_3 = Py_TYPE(__pyx_t_1)->tp_iternext;
+  }
+  for (;;) {
+    if (!__pyx_t_3 && PyList_CheckExact(__pyx_t_1)) {
+      if (__pyx_t_2 >= PyList_GET_SIZE(__pyx_t_1)) break;
+      __pyx_t_4 = PyList_GET_ITEM(__pyx_t_1, __pyx_t_2); __Pyx_INCREF(__pyx_t_4); __pyx_t_2++;
+    } else if (!__pyx_t_3 && PyTuple_CheckExact(__pyx_t_1)) {
+      if (__pyx_t_2 >= PyTuple_GET_SIZE(__pyx_t_1)) break;
+      __pyx_t_4 = PyTuple_GET_ITEM(__pyx_t_1, __pyx_t_2); __Pyx_INCREF(__pyx_t_4); __pyx_t_2++;
+    } else {
+      __pyx_t_4 = __pyx_t_3(__pyx_t_1);
+      if (unlikely(!__pyx_t_4)) {
+        if (PyErr_Occurred()) {
+          if (likely(PyErr_ExceptionMatches(PyExc_StopIteration))) PyErr_Clear();
+          else {__pyx_filename = __pyx_f[2]; __pyx_lineno = 4; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+        }
+        break;
+      }
+      __Pyx_GOTREF(__pyx_t_4);
+    }
+    __Pyx_XGOTREF(__pyx_cur_scope->__pyx_v_w);
+    __Pyx_XDECREF(__pyx_cur_scope->__pyx_v_w);
+    __Pyx_GIVEREF(__pyx_t_4);
+    __pyx_cur_scope->__pyx_v_w = __pyx_t_4;
+    __pyx_t_4 = 0;
+    __pyx_t_5 = ((PyObject *)((PyObject*)(&PyUnicode_Type)));
+    __Pyx_INCREF(__pyx_t_5);
+    __pyx_t_6 = __Pyx_TypeCheck(__pyx_cur_scope->__pyx_v_w, __pyx_t_5); 
+    __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
+    if (__pyx_t_6) {
+      __pyx_t_5 = PyObject_GetAttr(__pyx_cur_scope->__pyx_v_w, __pyx_n_s__encode); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 4; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __Pyx_GOTREF(__pyx_t_5);
+      __pyx_t_7 = PyObject_Call(__pyx_t_5, ((PyObject *)__pyx_k_tuple_6), NULL); if (unlikely(!__pyx_t_7)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 4; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __Pyx_GOTREF(__pyx_t_7);
+      __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
+      __pyx_t_4 = __pyx_t_7;
+      __pyx_t_7 = 0;
+    } else {
+      __pyx_t_7 = PyTuple_New(1); if (unlikely(!__pyx_t_7)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 4; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __Pyx_GOTREF(__pyx_t_7);
+      __Pyx_INCREF(__pyx_cur_scope->__pyx_v_w);
+      PyTuple_SET_ITEM(__pyx_t_7, 0, __pyx_cur_scope->__pyx_v_w);
+      __Pyx_GIVEREF(__pyx_cur_scope->__pyx_v_w);
+      __pyx_t_5 = PyObject_Call(((PyObject *)((PyObject*)(&PyString_Type))), ((PyObject *)__pyx_t_7), NULL); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 4; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __Pyx_GOTREF(__pyx_t_5);
+      __Pyx_DECREF(((PyObject *)__pyx_t_7)); __pyx_t_7 = 0;
+      __pyx_t_4 = __pyx_t_5;
+      __pyx_t_5 = 0;
+    }
+    __pyx_r = __pyx_t_4;
+    __pyx_t_4 = 0;
+    __Pyx_XGIVEREF(__pyx_t_1);
+    __pyx_cur_scope->__pyx_t_0 = __pyx_t_1;
+    __pyx_cur_scope->__pyx_t_1 = __pyx_t_2;
+    __pyx_cur_scope->__pyx_t_2 = __pyx_t_3;
+    __Pyx_XGIVEREF(__pyx_r);
+    __Pyx_RefNannyFinishContext();
+    /* return from generator, yielding value */
+    __pyx_generator->resume_label = 1;
+    return __pyx_r;
+    __pyx_L6_resume_from_yield:;
+    __pyx_t_1 = __pyx_cur_scope->__pyx_t_0;
+    __pyx_cur_scope->__pyx_t_0 = 0;
+    __Pyx_XGOTREF(__pyx_t_1);
+    __pyx_t_2 = __pyx_cur_scope->__pyx_t_1;
+    __pyx_t_3 = __pyx_cur_scope->__pyx_t_2;
+    if (unlikely(!__pyx_sent_value)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 4; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  }
+  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+  PyErr_SetNone(PyExc_StopIteration);
+  goto __pyx_L0;
+  __pyx_L1_error:;
+  __Pyx_XDECREF(__pyx_t_1);
+  __Pyx_XDECREF(__pyx_t_4);
+  __Pyx_XDECREF(__pyx_t_5);
+  __Pyx_XDECREF(__pyx_t_7);
+  __Pyx_AddTraceback("genexpr", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __pyx_L0:;
+  __Pyx_XDECREF(__pyx_r);
+  __pyx_generator->resume_label = -1;
   __Pyx_RefNannyFinishContext();
-  return __pyx_r;
+  return NULL;
 }
 
-/* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":13
- *             del self.rng
+/* "/Users/vchahun/Sandbox/cdec/python/src/grammar.pxi":3
+ * cimport grammar
+ * 
+ * def _phrase(phrase):             # <<<<<<<<<<<<<<
+ *     return ' '.join(w.encode('utf8') if isinstance(w, unicode) else str(w) for w in phrase)
  * 
- *     def viterbi(self):             # <<<<<<<<<<<<<<
- *         cdef vector[WordID] trans
- *         hypergraph.ViterbiESentence(self.hg[0], &trans)
  */
 
-static PyObject *__pyx_pf_5_cdec_10Hypergraph_2viterbi(struct __pyx_obj_5_cdec_Hypergraph *__pyx_v_self) {
-  std::vector<WordID> __pyx_v_trans;
+static PyObject *__pyx_pf_5_cdec__phrase(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_phrase) {
+  struct __pyx_obj_5_cdec___pyx_scope_struct_2__phrase *__pyx_cur_scope;
   PyObject *__pyx_r = NULL;
   __Pyx_RefNannyDeclarations
   PyObject *__pyx_t_1 = NULL;
   PyObject *__pyx_t_2 = NULL;
+  PyObject *__pyx_t_3 = NULL;
   int __pyx_lineno = 0;
   const char *__pyx_filename = NULL;
   int __pyx_clineno = 0;
-  __Pyx_RefNannySetupContext("viterbi", 0);
+  __Pyx_RefNannySetupContext("_phrase", 0);
+  __pyx_cur_scope = (struct __pyx_obj_5_cdec___pyx_scope_struct_2__phrase *)__pyx_ptype_5_cdec___pyx_scope_struct_2__phrase->tp_new(__pyx_ptype_5_cdec___pyx_scope_struct_2__phrase, __pyx_empty_tuple, NULL);
+  if (unlikely(!__pyx_cur_scope)) {
+    __Pyx_RefNannyFinishContext();
+    return NULL;
+  }
+  __Pyx_GOTREF(__pyx_cur_scope);
+  __pyx_cur_scope->__pyx_v_phrase = __pyx_v_phrase;
+  __Pyx_INCREF(__pyx_cur_scope->__pyx_v_phrase);
+  __Pyx_GIVEREF(__pyx_cur_scope->__pyx_v_phrase);
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":15
- *     def viterbi(self):
- *         cdef vector[WordID] trans
- *         hypergraph.ViterbiESentence(self.hg[0], &trans)             # <<<<<<<<<<<<<<
- *         return unicode(GetString(trans).c_str(), 'utf8')
+  /* "/Users/vchahun/Sandbox/cdec/python/src/grammar.pxi":4
  * 
- */
-  ViterbiESentence((__pyx_v_self->hg[0]), (&__pyx_v_trans));
-
-  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":16
- *         cdef vector[WordID] trans
- *         hypergraph.ViterbiESentence(self.hg[0], &trans)
- *         return unicode(GetString(trans).c_str(), 'utf8')             # <<<<<<<<<<<<<<
+ * def _phrase(phrase):
+ *     return ' '.join(w.encode('utf8') if isinstance(w, unicode) else str(w) for w in phrase)             # <<<<<<<<<<<<<<
  * 
- *     def viterbi_trees(self):
+ * cdef class NT:
  */
   __Pyx_XDECREF(__pyx_r);
-  __pyx_t_1 = PyBytes_FromString(TD::GetString(__pyx_v_trans).c_str()); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 16; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __Pyx_GOTREF(((PyObject *)__pyx_t_1));
-  __pyx_t_2 = PyTuple_New(2); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 16; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __Pyx_GOTREF(__pyx_t_2);
-  PyTuple_SET_ITEM(__pyx_t_2, 0, ((PyObject *)__pyx_t_1));
-  __Pyx_GIVEREF(((PyObject *)__pyx_t_1));
-  __Pyx_INCREF(((PyObject *)__pyx_n_s__utf8));
-  PyTuple_SET_ITEM(__pyx_t_2, 1, ((PyObject *)__pyx_n_s__utf8));
-  __Pyx_GIVEREF(((PyObject *)__pyx_n_s__utf8));
-  __pyx_t_1 = 0;
-  __pyx_t_1 = PyObject_Call(((PyObject *)((PyObject*)(&PyUnicode_Type))), ((PyObject *)__pyx_t_2), NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 16; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_1 = PyObject_GetAttr(((PyObject *)__pyx_kp_s_7), __pyx_n_s__join); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 4; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __Pyx_GOTREF(__pyx_t_1);
-  __Pyx_DECREF(((PyObject *)__pyx_t_2)); __pyx_t_2 = 0;
-  __pyx_r = __pyx_t_1;
-  __pyx_t_1 = 0;
-  goto __pyx_L0;
-
-  __pyx_r = Py_None; __Pyx_INCREF(Py_None);
-  goto __pyx_L0;
-  __pyx_L1_error:;
+  __pyx_t_2 = __pyx_pf_5_cdec_7_phrase_genexpr(((PyObject*)__pyx_cur_scope)); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 4; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_2);
+  __pyx_t_3 = PyTuple_New(1); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 4; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_3);
+  PyTuple_SET_ITEM(__pyx_t_3, 0, __pyx_t_2);
+  __Pyx_GIVEREF(__pyx_t_2);
+  __pyx_t_2 = 0;
+  __pyx_t_2 = PyObject_Call(__pyx_t_1, ((PyObject *)__pyx_t_3), NULL); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 4; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_2);
+  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+  __Pyx_DECREF(((PyObject *)__pyx_t_3)); __pyx_t_3 = 0;
+  __pyx_r = __pyx_t_2;
+  __pyx_t_2 = 0;
+  goto __pyx_L0;
+
+  __pyx_r = Py_None; __Pyx_INCREF(Py_None);
+  goto __pyx_L0;
+  __pyx_L1_error:;
   __Pyx_XDECREF(__pyx_t_1);
   __Pyx_XDECREF(__pyx_t_2);
-  __Pyx_AddTraceback("_cdec.Hypergraph.viterbi", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __Pyx_XDECREF(__pyx_t_3);
+  __Pyx_AddTraceback("_cdec._phrase", __pyx_clineno, __pyx_lineno, __pyx_filename);
   __pyx_r = NULL;
   __pyx_L0:;
+  __Pyx_DECREF(((PyObject *)__pyx_cur_scope));
   __Pyx_XGIVEREF(__pyx_r);
   __Pyx_RefNannyFinishContext();
   return __pyx_r;
 }
 
 /* Python wrapper */
-static PyObject *__pyx_pw_5_cdec_10Hypergraph_5viterbi_trees(PyObject *__pyx_v_self, CYTHON_UNUSED PyObject *unused); /*proto*/
-static PyObject *__pyx_pw_5_cdec_10Hypergraph_5viterbi_trees(PyObject *__pyx_v_self, CYTHON_UNUSED PyObject *unused) {
-  PyObject *__pyx_r = 0;
+static int __pyx_pw_5_cdec_2NT_1__init__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/
+static int __pyx_pw_5_cdec_2NT_1__init__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) {
+  PyObject *__pyx_v_cat = 0;
+  PyObject *__pyx_v_ref = 0;
+  static PyObject **__pyx_pyargnames[] = {&__pyx_n_s__cat,&__pyx_n_s__ref,0};
+  int __pyx_r;
   __Pyx_RefNannyDeclarations
-  __Pyx_RefNannySetupContext("viterbi_trees (wrapper)", 0);
-  __pyx_r = __pyx_pf_5_cdec_10Hypergraph_4viterbi_trees(((struct __pyx_obj_5_cdec_Hypergraph *)__pyx_v_self));
+  __Pyx_RefNannySetupContext("__init__ (wrapper)", 0);
+  {
+    PyObject* values[2] = {0,0};
+    values[1] = ((PyObject *)__pyx_int_0);
+    if (unlikely(__pyx_kwds)) {
+      Py_ssize_t kw_args;
+      const Py_ssize_t pos_args = PyTuple_GET_SIZE(__pyx_args);
+      switch (pos_args) {
+        case  2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1);
+        case  1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0);
+        case  0: break;
+        default: goto __pyx_L5_argtuple_error;
+      }
+      kw_args = PyDict_Size(__pyx_kwds);
+      switch (pos_args) {
+        case  0:
+        values[0] = PyDict_GetItem(__pyx_kwds, __pyx_n_s__cat);
+        if (likely(values[0])) kw_args--;
+        else goto __pyx_L5_argtuple_error;
+        case  1:
+        if (kw_args > 0) {
+          PyObject* value = PyDict_GetItem(__pyx_kwds, __pyx_n_s__ref);
+          if (value) { values[1] = value; kw_args--; }
+        }
+      }
+      if (unlikely(kw_args > 0)) {
+        if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "__init__") < 0)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 9; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+      }
+    } else {
+      switch (PyTuple_GET_SIZE(__pyx_args)) {
+        case  2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1);
+        case  1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0);
+        break;
+        default: goto __pyx_L5_argtuple_error;
+      }
+    }
+    __pyx_v_cat = values[0];
+    __pyx_v_ref = values[1];
+  }
+  goto __pyx_L4_argument_unpacking_done;
+  __pyx_L5_argtuple_error:;
+  __Pyx_RaiseArgtupleInvalid("__init__", 0, 1, 2, PyTuple_GET_SIZE(__pyx_args)); {__pyx_filename = __pyx_f[2]; __pyx_lineno = 9; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+  __pyx_L3_error:;
+  __Pyx_AddTraceback("_cdec.NT.__init__", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __Pyx_RefNannyFinishContext();
+  return -1;
+  __pyx_L4_argument_unpacking_done:;
+  __pyx_r = __pyx_pf_5_cdec_2NT___init__(((struct __pyx_obj_5_cdec_NT *)__pyx_v_self), __pyx_v_cat, __pyx_v_ref);
   __Pyx_RefNannyFinishContext();
   return __pyx_r;
 }
 
-/* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":18
- *         return unicode(GetString(trans).c_str(), 'utf8')
- * 
- *     def viterbi_trees(self):             # <<<<<<<<<<<<<<
- *         f_tree = unicode(hypergraph.ViterbiFTree(self.hg[0]).c_str(), 'utf8')
- *         e_tree = unicode(hypergraph.ViterbiETree(self.hg[0]).c_str(), 'utf8')
+/* "/Users/vchahun/Sandbox/cdec/python/src/grammar.pxi":9
+ *     cdef public char* cat
+ *     cdef public unsigned ref
+ *     def __init__(self, cat, ref=0):             # <<<<<<<<<<<<<<
+ *         self.cat = cat
+ *         self.ref = ref
  */
 
-static PyObject *__pyx_pf_5_cdec_10Hypergraph_4viterbi_trees(struct __pyx_obj_5_cdec_Hypergraph *__pyx_v_self) {
-  PyObject *__pyx_v_f_tree = NULL;
-  PyObject *__pyx_v_e_tree = NULL;
-  PyObject *__pyx_r = NULL;
+static int __pyx_pf_5_cdec_2NT___init__(struct __pyx_obj_5_cdec_NT *__pyx_v_self, PyObject *__pyx_v_cat, PyObject *__pyx_v_ref) {
+  int __pyx_r;
   __Pyx_RefNannyDeclarations
-  PyObject *__pyx_t_1 = NULL;
-  PyObject *__pyx_t_2 = NULL;
+  char *__pyx_t_1;
+  unsigned int __pyx_t_2;
   int __pyx_lineno = 0;
   const char *__pyx_filename = NULL;
   int __pyx_clineno = 0;
-  __Pyx_RefNannySetupContext("viterbi_trees", 0);
-
-  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":19
- * 
- *     def viterbi_trees(self):
- *         f_tree = unicode(hypergraph.ViterbiFTree(self.hg[0]).c_str(), 'utf8')             # <<<<<<<<<<<<<<
- *         e_tree = unicode(hypergraph.ViterbiETree(self.hg[0]).c_str(), 'utf8')
- *         return (f_tree, e_tree)
- */
-  __pyx_t_1 = PyBytes_FromString(ViterbiFTree((__pyx_v_self->hg[0])).c_str()); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 19; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __Pyx_GOTREF(((PyObject *)__pyx_t_1));
-  __pyx_t_2 = PyTuple_New(2); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 19; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __Pyx_GOTREF(__pyx_t_2);
-  PyTuple_SET_ITEM(__pyx_t_2, 0, ((PyObject *)__pyx_t_1));
-  __Pyx_GIVEREF(((PyObject *)__pyx_t_1));
-  __Pyx_INCREF(((PyObject *)__pyx_n_s__utf8));
-  PyTuple_SET_ITEM(__pyx_t_2, 1, ((PyObject *)__pyx_n_s__utf8));
-  __Pyx_GIVEREF(((PyObject *)__pyx_n_s__utf8));
-  __pyx_t_1 = 0;
-  __pyx_t_1 = PyObject_Call(((PyObject *)((PyObject*)(&PyUnicode_Type))), ((PyObject *)__pyx_t_2), NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 19; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __Pyx_GOTREF(__pyx_t_1);
-  __Pyx_DECREF(((PyObject *)__pyx_t_2)); __pyx_t_2 = 0;
-  __pyx_v_f_tree = ((PyObject*)__pyx_t_1);
-  __pyx_t_1 = 0;
+  __Pyx_RefNannySetupContext("__init__", 0);
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":20
- *     def viterbi_trees(self):
- *         f_tree = unicode(hypergraph.ViterbiFTree(self.hg[0]).c_str(), 'utf8')
- *         e_tree = unicode(hypergraph.ViterbiETree(self.hg[0]).c_str(), 'utf8')             # <<<<<<<<<<<<<<
- *         return (f_tree, e_tree)
+  /* "/Users/vchahun/Sandbox/cdec/python/src/grammar.pxi":10
+ *     cdef public unsigned ref
+ *     def __init__(self, cat, ref=0):
+ *         self.cat = cat             # <<<<<<<<<<<<<<
+ *         self.ref = ref
  * 
  */
-  __pyx_t_1 = PyBytes_FromString(ViterbiETree((__pyx_v_self->hg[0])).c_str()); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 20; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __Pyx_GOTREF(((PyObject *)__pyx_t_1));
-  __pyx_t_2 = PyTuple_New(2); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 20; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __Pyx_GOTREF(__pyx_t_2);
-  PyTuple_SET_ITEM(__pyx_t_2, 0, ((PyObject *)__pyx_t_1));
-  __Pyx_GIVEREF(((PyObject *)__pyx_t_1));
-  __Pyx_INCREF(((PyObject *)__pyx_n_s__utf8));
-  PyTuple_SET_ITEM(__pyx_t_2, 1, ((PyObject *)__pyx_n_s__utf8));
-  __Pyx_GIVEREF(((PyObject *)__pyx_n_s__utf8));
-  __pyx_t_1 = 0;
-  __pyx_t_1 = PyObject_Call(((PyObject *)((PyObject*)(&PyUnicode_Type))), ((PyObject *)__pyx_t_2), NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 20; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __Pyx_GOTREF(__pyx_t_1);
-  __Pyx_DECREF(((PyObject *)__pyx_t_2)); __pyx_t_2 = 0;
-  __pyx_v_e_tree = ((PyObject*)__pyx_t_1);
-  __pyx_t_1 = 0;
+  __pyx_t_1 = PyBytes_AsString(__pyx_v_cat); if (unlikely((!__pyx_t_1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 10; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_v_self->cat = __pyx_t_1;
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":21
- *         f_tree = unicode(hypergraph.ViterbiFTree(self.hg[0]).c_str(), 'utf8')
- *         e_tree = unicode(hypergraph.ViterbiETree(self.hg[0]).c_str(), 'utf8')
- *         return (f_tree, e_tree)             # <<<<<<<<<<<<<<
+  /* "/Users/vchahun/Sandbox/cdec/python/src/grammar.pxi":11
+ *     def __init__(self, cat, ref=0):
+ *         self.cat = cat
+ *         self.ref = ref             # <<<<<<<<<<<<<<
  * 
- *     def viterbi_features(self):
+ *     def __str__(self):
  */
-  __Pyx_XDECREF(__pyx_r);
-  __pyx_t_1 = PyTuple_New(2); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 21; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __Pyx_GOTREF(__pyx_t_1);
-  __Pyx_INCREF(((PyObject *)__pyx_v_f_tree));
-  PyTuple_SET_ITEM(__pyx_t_1, 0, ((PyObject *)__pyx_v_f_tree));
-  __Pyx_GIVEREF(((PyObject *)__pyx_v_f_tree));
-  __Pyx_INCREF(((PyObject *)__pyx_v_e_tree));
-  PyTuple_SET_ITEM(__pyx_t_1, 1, ((PyObject *)__pyx_v_e_tree));
-  __Pyx_GIVEREF(((PyObject *)__pyx_v_e_tree));
-  __pyx_r = ((PyObject *)__pyx_t_1);
-  __pyx_t_1 = 0;
-  goto __pyx_L0;
+  __pyx_t_2 = __Pyx_PyInt_AsUnsignedInt(__pyx_v_ref); if (unlikely((__pyx_t_2 == (unsigned int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 11; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_v_self->ref = __pyx_t_2;
 
-  __pyx_r = Py_None; __Pyx_INCREF(Py_None);
+  __pyx_r = 0;
   goto __pyx_L0;
   __pyx_L1_error:;
-  __Pyx_XDECREF(__pyx_t_1);
-  __Pyx_XDECREF(__pyx_t_2);
-  __Pyx_AddTraceback("_cdec.Hypergraph.viterbi_trees", __pyx_clineno, __pyx_lineno, __pyx_filename);
-  __pyx_r = NULL;
+  __Pyx_AddTraceback("_cdec.NT.__init__", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __pyx_r = -1;
   __pyx_L0:;
-  __Pyx_XDECREF(__pyx_v_f_tree);
-  __Pyx_XDECREF(__pyx_v_e_tree);
-  __Pyx_XGIVEREF(__pyx_r);
   __Pyx_RefNannyFinishContext();
   return __pyx_r;
 }
 
 /* Python wrapper */
-static PyObject *__pyx_pw_5_cdec_10Hypergraph_7viterbi_features(PyObject *__pyx_v_self, CYTHON_UNUSED PyObject *unused); /*proto*/
-static PyObject *__pyx_pw_5_cdec_10Hypergraph_7viterbi_features(PyObject *__pyx_v_self, CYTHON_UNUSED PyObject *unused) {
+static PyObject *__pyx_pw_5_cdec_2NT_3__str__(PyObject *__pyx_v_self); /*proto*/
+static PyObject *__pyx_pw_5_cdec_2NT_3__str__(PyObject *__pyx_v_self) {
   PyObject *__pyx_r = 0;
   __Pyx_RefNannyDeclarations
-  __Pyx_RefNannySetupContext("viterbi_features (wrapper)", 0);
-  __pyx_r = __pyx_pf_5_cdec_10Hypergraph_6viterbi_features(((struct __pyx_obj_5_cdec_Hypergraph *)__pyx_v_self));
+  __Pyx_RefNannySetupContext("__str__ (wrapper)", 0);
+  __pyx_r = __pyx_pf_5_cdec_2NT_2__str__(((struct __pyx_obj_5_cdec_NT *)__pyx_v_self));
   __Pyx_RefNannyFinishContext();
   return __pyx_r;
 }
 
-/* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":23
- *         return (f_tree, e_tree)
+/* "/Users/vchahun/Sandbox/cdec/python/src/grammar.pxi":13
+ *         self.ref = ref
  * 
- *     def viterbi_features(self):             # <<<<<<<<<<<<<<
- *         cdef SparseVector fmap = SparseVector()
- *         fmap.vector = new FastSparseVector[weight_t](hypergraph.ViterbiFeatures(self.hg[0]))
+ *     def __str__(self):             # <<<<<<<<<<<<<<
+ *         if self.ref > 0:
+ *             return '[%s,%d]' % (self.cat, self.ref)
  */
 
-static PyObject *__pyx_pf_5_cdec_10Hypergraph_6viterbi_features(struct __pyx_obj_5_cdec_Hypergraph *__pyx_v_self) {
-  struct __pyx_obj_5_cdec_SparseVector *__pyx_v_fmap = 0;
+static PyObject *__pyx_pf_5_cdec_2NT_2__str__(struct __pyx_obj_5_cdec_NT *__pyx_v_self) {
   PyObject *__pyx_r = NULL;
   __Pyx_RefNannyDeclarations
-  PyObject *__pyx_t_1 = NULL;
+  int __pyx_t_1;
+  PyObject *__pyx_t_2 = NULL;
+  PyObject *__pyx_t_3 = NULL;
+  PyObject *__pyx_t_4 = NULL;
   int __pyx_lineno = 0;
   const char *__pyx_filename = NULL;
   int __pyx_clineno = 0;
-  __Pyx_RefNannySetupContext("viterbi_features", 0);
+  __Pyx_RefNannySetupContext("__str__", 0);
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":24
+  /* "/Users/vchahun/Sandbox/cdec/python/src/grammar.pxi":14
  * 
- *     def viterbi_features(self):
- *         cdef SparseVector fmap = SparseVector()             # <<<<<<<<<<<<<<
- *         fmap.vector = new FastSparseVector[weight_t](hypergraph.ViterbiFeatures(self.hg[0]))
- *         return fmap
+ *     def __str__(self):
+ *         if self.ref > 0:             # <<<<<<<<<<<<<<
+ *             return '[%s,%d]' % (self.cat, self.ref)
+ *         return '[%s]' % self.cat
  */
-  __pyx_t_1 = PyObject_Call(((PyObject *)((PyObject*)__pyx_ptype_5_cdec_SparseVector)), ((PyObject *)__pyx_empty_tuple), NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 24; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __Pyx_GOTREF(__pyx_t_1);
-  __pyx_v_fmap = ((struct __pyx_obj_5_cdec_SparseVector *)__pyx_t_1);
-  __pyx_t_1 = 0;
+  __pyx_t_1 = (__pyx_v_self->ref > 0);
+  if (__pyx_t_1) {
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":25
- *     def viterbi_features(self):
- *         cdef SparseVector fmap = SparseVector()
- *         fmap.vector = new FastSparseVector[weight_t](hypergraph.ViterbiFeatures(self.hg[0]))             # <<<<<<<<<<<<<<
- *         return fmap
+    /* "/Users/vchahun/Sandbox/cdec/python/src/grammar.pxi":15
+ *     def __str__(self):
+ *         if self.ref > 0:
+ *             return '[%s,%d]' % (self.cat, self.ref)             # <<<<<<<<<<<<<<
+ *         return '[%s]' % self.cat
  * 
  */
-  __pyx_v_fmap->vector = new FastSparseVector<weight_t>(ViterbiFeatures((__pyx_v_self->hg[0])));
+    __Pyx_XDECREF(__pyx_r);
+    __pyx_t_2 = PyBytes_FromString(__pyx_v_self->cat); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 15; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(((PyObject *)__pyx_t_2));
+    __pyx_t_3 = PyLong_FromUnsignedLong(__pyx_v_self->ref); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 15; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_3);
+    __pyx_t_4 = PyTuple_New(2); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 15; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_4);
+    PyTuple_SET_ITEM(__pyx_t_4, 0, ((PyObject *)__pyx_t_2));
+    __Pyx_GIVEREF(((PyObject *)__pyx_t_2));
+    PyTuple_SET_ITEM(__pyx_t_4, 1, __pyx_t_3);
+    __Pyx_GIVEREF(__pyx_t_3);
+    __pyx_t_2 = 0;
+    __pyx_t_3 = 0;
+    __pyx_t_3 = PyNumber_Remainder(((PyObject *)__pyx_kp_s_8), ((PyObject *)__pyx_t_4)); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 15; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(((PyObject *)__pyx_t_3));
+    __Pyx_DECREF(((PyObject *)__pyx_t_4)); __pyx_t_4 = 0;
+    __pyx_r = ((PyObject *)__pyx_t_3);
+    __pyx_t_3 = 0;
+    goto __pyx_L0;
+    goto __pyx_L3;
+  }
+  __pyx_L3:;
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":26
- *         cdef SparseVector fmap = SparseVector()
- *         fmap.vector = new FastSparseVector[weight_t](hypergraph.ViterbiFeatures(self.hg[0]))
- *         return fmap             # <<<<<<<<<<<<<<
+  /* "/Users/vchahun/Sandbox/cdec/python/src/grammar.pxi":16
+ *         if self.ref > 0:
+ *             return '[%s,%d]' % (self.cat, self.ref)
+ *         return '[%s]' % self.cat             # <<<<<<<<<<<<<<
  * 
- *     def viterbi_joshua(self):
+ * cdef class NTRef:
  */
   __Pyx_XDECREF(__pyx_r);
-  __Pyx_INCREF(((PyObject *)__pyx_v_fmap));
-  __pyx_r = ((PyObject *)__pyx_v_fmap);
+  __pyx_t_3 = PyBytes_FromString(__pyx_v_self->cat); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 16; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(((PyObject *)__pyx_t_3));
+  __pyx_t_4 = PyNumber_Remainder(((PyObject *)__pyx_kp_s_9), ((PyObject *)__pyx_t_3)); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 16; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(((PyObject *)__pyx_t_4));
+  __Pyx_DECREF(((PyObject *)__pyx_t_3)); __pyx_t_3 = 0;
+  __pyx_r = ((PyObject *)__pyx_t_4);
+  __pyx_t_4 = 0;
   goto __pyx_L0;
 
   __pyx_r = Py_None; __Pyx_INCREF(Py_None);
   goto __pyx_L0;
   __pyx_L1_error:;
-  __Pyx_XDECREF(__pyx_t_1);
-  __Pyx_AddTraceback("_cdec.Hypergraph.viterbi_features", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __Pyx_XDECREF(__pyx_t_2);
+  __Pyx_XDECREF(__pyx_t_3);
+  __Pyx_XDECREF(__pyx_t_4);
+  __Pyx_AddTraceback("_cdec.NT.__str__", __pyx_clineno, __pyx_lineno, __pyx_filename);
   __pyx_r = NULL;
   __pyx_L0:;
-  __Pyx_XDECREF((PyObject *)__pyx_v_fmap);
   __Pyx_XGIVEREF(__pyx_r);
   __Pyx_RefNannyFinishContext();
   return __pyx_r;
 }
 
 /* Python wrapper */
-static PyObject *__pyx_pw_5_cdec_10Hypergraph_9viterbi_joshua(PyObject *__pyx_v_self, CYTHON_UNUSED PyObject *unused); /*proto*/
-static PyObject *__pyx_pw_5_cdec_10Hypergraph_9viterbi_joshua(PyObject *__pyx_v_self, CYTHON_UNUSED PyObject *unused) {
+static PyObject *__pyx_pw_5_cdec_2NT_3cat_1__get__(PyObject *__pyx_v_self); /*proto*/
+static PyObject *__pyx_pw_5_cdec_2NT_3cat_1__get__(PyObject *__pyx_v_self) {
   PyObject *__pyx_r = 0;
   __Pyx_RefNannyDeclarations
-  __Pyx_RefNannySetupContext("viterbi_joshua (wrapper)", 0);
-  __pyx_r = __pyx_pf_5_cdec_10Hypergraph_8viterbi_joshua(((struct __pyx_obj_5_cdec_Hypergraph *)__pyx_v_self));
+  __Pyx_RefNannySetupContext("__get__ (wrapper)", 0);
+  __pyx_r = __pyx_pf_5_cdec_2NT_3cat___get__(((struct __pyx_obj_5_cdec_NT *)__pyx_v_self));
   __Pyx_RefNannyFinishContext();
   return __pyx_r;
 }
 
-/* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":28
- *         return fmap
- * 
- *     def viterbi_joshua(self):             # <<<<<<<<<<<<<<
- *         return unicode(hypergraph.JoshuaVisualizationString(self.hg[0]).c_str(), 'utf8')
+/* "/Users/vchahun/Sandbox/cdec/python/src/grammar.pxi":7
  * 
+ * cdef class NT:
+ *     cdef public char* cat             # <<<<<<<<<<<<<<
+ *     cdef public unsigned ref
+ *     def __init__(self, cat, ref=0):
  */
 
-static PyObject *__pyx_pf_5_cdec_10Hypergraph_8viterbi_joshua(struct __pyx_obj_5_cdec_Hypergraph *__pyx_v_self) {
+static PyObject *__pyx_pf_5_cdec_2NT_3cat___get__(struct __pyx_obj_5_cdec_NT *__pyx_v_self) {
   PyObject *__pyx_r = NULL;
   __Pyx_RefNannyDeclarations
   PyObject *__pyx_t_1 = NULL;
-  PyObject *__pyx_t_2 = NULL;
   int __pyx_lineno = 0;
   const char *__pyx_filename = NULL;
   int __pyx_clineno = 0;
-  __Pyx_RefNannySetupContext("viterbi_joshua", 0);
-
-  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":29
- * 
- *     def viterbi_joshua(self):
- *         return unicode(hypergraph.JoshuaVisualizationString(self.hg[0]).c_str(), 'utf8')             # <<<<<<<<<<<<<<
- * 
- *     def kbest(self, size):
- */
+  __Pyx_RefNannySetupContext("__get__", 0);
   __Pyx_XDECREF(__pyx_r);
-  __pyx_t_1 = PyBytes_FromString(JoshuaVisualizationString((__pyx_v_self->hg[0])).c_str()); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 29; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_1 = PyBytes_FromString(__pyx_v_self->cat); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 7; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __Pyx_GOTREF(((PyObject *)__pyx_t_1));
-  __pyx_t_2 = PyTuple_New(2); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 29; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __Pyx_GOTREF(__pyx_t_2);
-  PyTuple_SET_ITEM(__pyx_t_2, 0, ((PyObject *)__pyx_t_1));
-  __Pyx_GIVEREF(((PyObject *)__pyx_t_1));
-  __Pyx_INCREF(((PyObject *)__pyx_n_s__utf8));
-  PyTuple_SET_ITEM(__pyx_t_2, 1, ((PyObject *)__pyx_n_s__utf8));
-  __Pyx_GIVEREF(((PyObject *)__pyx_n_s__utf8));
-  __pyx_t_1 = 0;
-  __pyx_t_1 = PyObject_Call(((PyObject *)((PyObject*)(&PyUnicode_Type))), ((PyObject *)__pyx_t_2), NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 29; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __Pyx_GOTREF(__pyx_t_1);
-  __Pyx_DECREF(((PyObject *)__pyx_t_2)); __pyx_t_2 = 0;
-  __pyx_r = __pyx_t_1;
+  __pyx_r = ((PyObject *)__pyx_t_1);
   __pyx_t_1 = 0;
   goto __pyx_L0;
 
@@ -4413,1030 +4689,416 @@ static PyObject *__pyx_pf_5_cdec_10Hypergraph_8viterbi_joshua(struct __pyx_obj_5
   goto __pyx_L0;
   __pyx_L1_error:;
   __Pyx_XDECREF(__pyx_t_1);
-  __Pyx_XDECREF(__pyx_t_2);
-  __Pyx_AddTraceback("_cdec.Hypergraph.viterbi_joshua", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __Pyx_AddTraceback("_cdec.NT.cat.__get__", __pyx_clineno, __pyx_lineno, __pyx_filename);
   __pyx_r = NULL;
   __pyx_L0:;
   __Pyx_XGIVEREF(__pyx_r);
   __Pyx_RefNannyFinishContext();
   return __pyx_r;
 }
-static PyObject *__pyx_gb_5_cdec_10Hypergraph_12generator2(__pyx_GeneratorObject *__pyx_generator, PyObject *__pyx_sent_value); /* proto */
 
 /* Python wrapper */
-static PyObject *__pyx_pw_5_cdec_10Hypergraph_11kbest(PyObject *__pyx_v_self, PyObject *__pyx_v_size); /*proto*/
-static PyObject *__pyx_pw_5_cdec_10Hypergraph_11kbest(PyObject *__pyx_v_self, PyObject *__pyx_v_size) {
-  PyObject *__pyx_r = 0;
+static int __pyx_pw_5_cdec_2NT_3cat_3__set__(PyObject *__pyx_v_self, PyObject *__pyx_v_value); /*proto*/
+static int __pyx_pw_5_cdec_2NT_3cat_3__set__(PyObject *__pyx_v_self, PyObject *__pyx_v_value) {
+  int __pyx_r;
   __Pyx_RefNannyDeclarations
-  __Pyx_RefNannySetupContext("kbest (wrapper)", 0);
-  __pyx_r = __pyx_pf_5_cdec_10Hypergraph_10kbest(((struct __pyx_obj_5_cdec_Hypergraph *)__pyx_v_self), ((PyObject *)__pyx_v_size));
+  __Pyx_RefNannySetupContext("__set__ (wrapper)", 0);
+  __pyx_r = __pyx_pf_5_cdec_2NT_3cat_2__set__(((struct __pyx_obj_5_cdec_NT *)__pyx_v_self), ((PyObject *)__pyx_v_value));
   __Pyx_RefNannyFinishContext();
   return __pyx_r;
 }
 
-/* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":31
- *         return unicode(hypergraph.JoshuaVisualizationString(self.hg[0]).c_str(), 'utf8')
- * 
- *     def kbest(self, size):             # <<<<<<<<<<<<<<
- *         cdef kbest.KBestDerivations[vector[WordID], kbest.ESentenceTraversal]* derivations = new kbest.KBestDerivations[vector[WordID], kbest.ESentenceTraversal](self.hg[0], size)
- *         cdef kbest.KBestDerivations[vector[WordID], kbest.ESentenceTraversal].Derivation* derivation
- */
-
-static PyObject *__pyx_pf_5_cdec_10Hypergraph_10kbest(struct __pyx_obj_5_cdec_Hypergraph *__pyx_v_self, PyObject *__pyx_v_size) {
-  struct __pyx_obj_5_cdec___pyx_scope_struct_2_kbest *__pyx_cur_scope;
-  PyObject *__pyx_r = NULL;
+static int __pyx_pf_5_cdec_2NT_3cat_2__set__(struct __pyx_obj_5_cdec_NT *__pyx_v_self, PyObject *__pyx_v_value) {
+  int __pyx_r;
   __Pyx_RefNannyDeclarations
+  char *__pyx_t_1;
   int __pyx_lineno = 0;
   const char *__pyx_filename = NULL;
   int __pyx_clineno = 0;
-  __Pyx_RefNannySetupContext("kbest", 0);
-  __pyx_cur_scope = (struct __pyx_obj_5_cdec___pyx_scope_struct_2_kbest *)__pyx_ptype_5_cdec___pyx_scope_struct_2_kbest->tp_new(__pyx_ptype_5_cdec___pyx_scope_struct_2_kbest, __pyx_empty_tuple, NULL);
-  if (unlikely(!__pyx_cur_scope)) {
-    __Pyx_RefNannyFinishContext();
-    return NULL;
-  }
-  __Pyx_GOTREF(__pyx_cur_scope);
-  __pyx_cur_scope->__pyx_v_self = __pyx_v_self;
-  __Pyx_INCREF((PyObject *)__pyx_cur_scope->__pyx_v_self);
-  __Pyx_GIVEREF((PyObject *)__pyx_cur_scope->__pyx_v_self);
-  __pyx_cur_scope->__pyx_v_size = __pyx_v_size;
-  __Pyx_INCREF(__pyx_cur_scope->__pyx_v_size);
-  __Pyx_GIVEREF(__pyx_cur_scope->__pyx_v_size);
-  {
-    __pyx_GeneratorObject *gen = __Pyx_Generator_New((__pyx_generator_body_t) __pyx_gb_5_cdec_10Hypergraph_12generator2, (PyObject *) __pyx_cur_scope); if (unlikely(!gen)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 31; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-    __Pyx_DECREF(__pyx_cur_scope);
-    __Pyx_RefNannyFinishContext();
-    return (PyObject *) gen;
-  }
+  __Pyx_RefNannySetupContext("__set__", 0);
+  __pyx_t_1 = PyBytes_AsString(__pyx_v_value); if (unlikely((!__pyx_t_1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 7; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_v_self->cat = __pyx_t_1;
 
-  __pyx_r = Py_None; __Pyx_INCREF(Py_None);
+  __pyx_r = 0;
   goto __pyx_L0;
   __pyx_L1_error:;
-  __Pyx_AddTraceback("_cdec.Hypergraph.kbest", __pyx_clineno, __pyx_lineno, __pyx_filename);
-  __pyx_r = NULL;
+  __Pyx_AddTraceback("_cdec.NT.cat.__set__", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __pyx_r = -1;
   __pyx_L0:;
-  __Pyx_DECREF(((PyObject *)__pyx_cur_scope));
-  __Pyx_XGIVEREF(__pyx_r);
   __Pyx_RefNannyFinishContext();
   return __pyx_r;
 }
 
-static PyObject *__pyx_gb_5_cdec_10Hypergraph_12generator2(__pyx_GeneratorObject *__pyx_generator, PyObject *__pyx_sent_value) /* generator body */
-{
-  struct __pyx_obj_5_cdec___pyx_scope_struct_2_kbest *__pyx_cur_scope = ((struct __pyx_obj_5_cdec___pyx_scope_struct_2_kbest *)__pyx_generator->closure);
-  PyObject *__pyx_r = NULL;
-  unsigned int __pyx_t_1;
-  long __pyx_t_2;
-  int __pyx_t_3;
-  PyObject *__pyx_t_4 = NULL;
-  PyObject *__pyx_t_5 = NULL;
+/* Python wrapper */
+static PyObject *__pyx_pw_5_cdec_2NT_3ref_1__get__(PyObject *__pyx_v_self); /*proto*/
+static PyObject *__pyx_pw_5_cdec_2NT_3ref_1__get__(PyObject *__pyx_v_self) {
+  PyObject *__pyx_r = 0;
   __Pyx_RefNannyDeclarations
-  __Pyx_RefNannySetupContext("None", 0);
-  switch (__pyx_generator->resume_label) {
-    case 0: goto __pyx_L3_first_run;
-    case 1: goto __pyx_L10_resume_from_yield;
-    default: /* CPython raises the right error here */
-    __Pyx_RefNannyFinishContext();
-    return NULL;
-  }
-  __pyx_L3_first_run:;
-  if (unlikely(!__pyx_sent_value)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 31; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-
-  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":32
- * 
- *     def kbest(self, size):
- *         cdef kbest.KBestDerivations[vector[WordID], kbest.ESentenceTraversal]* derivations = new kbest.KBestDerivations[vector[WordID], kbest.ESentenceTraversal](self.hg[0], size)             # <<<<<<<<<<<<<<
- *         cdef kbest.KBestDerivations[vector[WordID], kbest.ESentenceTraversal].Derivation* derivation
- *         cdef unsigned k
- */
-  __pyx_t_1 = __Pyx_PyInt_AsUnsignedInt(__pyx_cur_scope->__pyx_v_size); if (unlikely((__pyx_t_1 == (unsigned int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 32; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __pyx_cur_scope->__pyx_v_derivations = new KBest::KBestDerivations<std::vector<WordID>,ESentenceTraversal>((__pyx_cur_scope->__pyx_v_self->hg[0]), __pyx_t_1);
-
-  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":35
- *         cdef kbest.KBestDerivations[vector[WordID], kbest.ESentenceTraversal].Derivation* derivation
- *         cdef unsigned k
- *         try:             # <<<<<<<<<<<<<<
- *             for k in range(size):
- *                 derivation = derivations.LazyKthBest(self.hg.nodes_.size() - 1, k)
- */
-  /*try:*/ {
-
-    /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":36
- *         cdef unsigned k
- *         try:
- *             for k in range(size):             # <<<<<<<<<<<<<<
- *                 derivation = derivations.LazyKthBest(self.hg.nodes_.size() - 1, k)
- *                 if not derivation: break
- */
-    __pyx_t_2 = __Pyx_PyInt_AsLong(__pyx_cur_scope->__pyx_v_size); if (unlikely((__pyx_t_2 == (long)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 36; __pyx_clineno = __LINE__; goto __pyx_L5;}
-    for (__pyx_t_1 = 0; __pyx_t_1 < __pyx_t_2; __pyx_t_1+=1) {
-      __pyx_cur_scope->__pyx_v_k = __pyx_t_1;
-
-      /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":37
- *         try:
- *             for k in range(size):
- *                 derivation = derivations.LazyKthBest(self.hg.nodes_.size() - 1, k)             # <<<<<<<<<<<<<<
- *                 if not derivation: break
- *                 yield unicode(GetString(derivation._yield).c_str(), 'utf8')
- */
-      __pyx_cur_scope->__pyx_v_derivation = __pyx_cur_scope->__pyx_v_derivations->LazyKthBest((__pyx_cur_scope->__pyx_v_self->hg->nodes_.size() - 1), __pyx_cur_scope->__pyx_v_k);
+  __Pyx_RefNannySetupContext("__get__ (wrapper)", 0);
+  __pyx_r = __pyx_pf_5_cdec_2NT_3ref___get__(((struct __pyx_obj_5_cdec_NT *)__pyx_v_self));
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
 
-      /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":38
- *             for k in range(size):
- *                 derivation = derivations.LazyKthBest(self.hg.nodes_.size() - 1, k)
- *                 if not derivation: break             # <<<<<<<<<<<<<<
- *                 yield unicode(GetString(derivation._yield).c_str(), 'utf8')
- *         finally:
+/* "/Users/vchahun/Sandbox/cdec/python/src/grammar.pxi":8
+ * cdef class NT:
+ *     cdef public char* cat
+ *     cdef public unsigned ref             # <<<<<<<<<<<<<<
+ *     def __init__(self, cat, ref=0):
+ *         self.cat = cat
  */
-      __pyx_t_3 = (!(__pyx_cur_scope->__pyx_v_derivation != 0));
-      if (__pyx_t_3) {
-        goto __pyx_L8_break;
-        goto __pyx_L9;
-      }
-      __pyx_L9:;
 
-      /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":39
- *                 derivation = derivations.LazyKthBest(self.hg.nodes_.size() - 1, k)
- *                 if not derivation: break
- *                 yield unicode(GetString(derivation._yield).c_str(), 'utf8')             # <<<<<<<<<<<<<<
- *         finally:
- *             del derivations
- */
-      __pyx_t_4 = PyBytes_FromString(TD::GetString(__pyx_cur_scope->__pyx_v_derivation->yield).c_str()); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 39; __pyx_clineno = __LINE__; goto __pyx_L5;}
-      __Pyx_GOTREF(((PyObject *)__pyx_t_4));
-      __pyx_t_5 = PyTuple_New(2); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 39; __pyx_clineno = __LINE__; goto __pyx_L5;}
-      __Pyx_GOTREF(__pyx_t_5);
-      PyTuple_SET_ITEM(__pyx_t_5, 0, ((PyObject *)__pyx_t_4));
-      __Pyx_GIVEREF(((PyObject *)__pyx_t_4));
-      __Pyx_INCREF(((PyObject *)__pyx_n_s__utf8));
-      PyTuple_SET_ITEM(__pyx_t_5, 1, ((PyObject *)__pyx_n_s__utf8));
-      __Pyx_GIVEREF(((PyObject *)__pyx_n_s__utf8));
-      __pyx_t_4 = 0;
-      __pyx_t_4 = PyObject_Call(((PyObject *)((PyObject*)(&PyUnicode_Type))), ((PyObject *)__pyx_t_5), NULL); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 39; __pyx_clineno = __LINE__; goto __pyx_L5;}
-      __Pyx_GOTREF(__pyx_t_4);
-      __Pyx_DECREF(((PyObject *)__pyx_t_5)); __pyx_t_5 = 0;
-      __pyx_r = __pyx_t_4;
-      __pyx_t_4 = 0;
-      __pyx_cur_scope->__pyx_t_0 = __pyx_t_1;
-      __pyx_cur_scope->__pyx_t_1 = __pyx_t_2;
-      __Pyx_XGIVEREF(__pyx_r);
-      __Pyx_RefNannyFinishContext();
-      /* return from generator, yielding value */
-      __pyx_generator->resume_label = 1;
-      return __pyx_r;
-      __pyx_L10_resume_from_yield:;
-      __pyx_t_1 = __pyx_cur_scope->__pyx_t_0;
-      __pyx_t_2 = __pyx_cur_scope->__pyx_t_1;
-      if (unlikely(!__pyx_sent_value)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 39; __pyx_clineno = __LINE__; goto __pyx_L5;}
-    }
-    __pyx_L8_break:;
-  }
+static PyObject *__pyx_pf_5_cdec_2NT_3ref___get__(struct __pyx_obj_5_cdec_NT *__pyx_v_self) {
+  PyObject *__pyx_r = NULL;
+  __Pyx_RefNannyDeclarations
+  PyObject *__pyx_t_1 = NULL;
+  int __pyx_lineno = 0;
+  const char *__pyx_filename = NULL;
+  int __pyx_clineno = 0;
+  __Pyx_RefNannySetupContext("__get__", 0);
+  __Pyx_XDECREF(__pyx_r);
+  __pyx_t_1 = PyLong_FromUnsignedLong(__pyx_v_self->ref); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 8; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_1);
+  __pyx_r = __pyx_t_1;
+  __pyx_t_1 = 0;
+  goto __pyx_L0;
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":41
- *                 yield unicode(GetString(derivation._yield).c_str(), 'utf8')
- *         finally:
- *             del derivations             # <<<<<<<<<<<<<<
- * 
- *     def kbest_trees(self, size):
- */
-  /*finally:*/ {
-    int __pyx_why;
-    PyObject *__pyx_exc_type, *__pyx_exc_value, *__pyx_exc_tb;
-    int __pyx_exc_lineno;
-    __pyx_exc_type = 0; __pyx_exc_value = 0; __pyx_exc_tb = 0; __pyx_exc_lineno = 0;
-    __pyx_why = 0; goto __pyx_L6;
-    __pyx_L5: {
-      __pyx_why = 4;
-      __Pyx_XDECREF(__pyx_t_5); __pyx_t_5 = 0;
-      __Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0;
-      __Pyx_ErrFetch(&__pyx_exc_type, &__pyx_exc_value, &__pyx_exc_tb);
-      __pyx_exc_lineno = __pyx_lineno;
-      goto __pyx_L6;
-    }
-    __pyx_L6:;
-    delete __pyx_cur_scope->__pyx_v_derivations;
-    switch (__pyx_why) {
-      case 4: {
-        __Pyx_ErrRestore(__pyx_exc_type, __pyx_exc_value, __pyx_exc_tb);
-        __pyx_lineno = __pyx_exc_lineno;
-        __pyx_exc_type = 0;
-        __pyx_exc_value = 0;
-        __pyx_exc_tb = 0;
-        goto __pyx_L1_error;
-      }
-    }
-  }
-  PyErr_SetNone(PyExc_StopIteration);
+  __pyx_r = Py_None; __Pyx_INCREF(Py_None);
   goto __pyx_L0;
   __pyx_L1_error:;
-  __Pyx_XDECREF(__pyx_t_4);
-  __Pyx_XDECREF(__pyx_t_5);
-  __Pyx_AddTraceback("kbest", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __Pyx_XDECREF(__pyx_t_1);
+  __Pyx_AddTraceback("_cdec.NT.ref.__get__", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __pyx_r = NULL;
   __pyx_L0:;
-  __Pyx_XDECREF(__pyx_r);
-  __pyx_generator->resume_label = -1;
+  __Pyx_XGIVEREF(__pyx_r);
   __Pyx_RefNannyFinishContext();
-  return NULL;
+  return __pyx_r;
 }
-static PyObject *__pyx_gb_5_cdec_10Hypergraph_15generator3(__pyx_GeneratorObject *__pyx_generator, PyObject *__pyx_sent_value); /* proto */
 
 /* Python wrapper */
-static PyObject *__pyx_pw_5_cdec_10Hypergraph_14kbest_trees(PyObject *__pyx_v_self, PyObject *__pyx_v_size); /*proto*/
-static PyObject *__pyx_pw_5_cdec_10Hypergraph_14kbest_trees(PyObject *__pyx_v_self, PyObject *__pyx_v_size) {
-  PyObject *__pyx_r = 0;
+static int __pyx_pw_5_cdec_2NT_3ref_3__set__(PyObject *__pyx_v_self, PyObject *__pyx_v_value); /*proto*/
+static int __pyx_pw_5_cdec_2NT_3ref_3__set__(PyObject *__pyx_v_self, PyObject *__pyx_v_value) {
+  int __pyx_r;
   __Pyx_RefNannyDeclarations
-  __Pyx_RefNannySetupContext("kbest_trees (wrapper)", 0);
-  __pyx_r = __pyx_pf_5_cdec_10Hypergraph_13kbest_trees(((struct __pyx_obj_5_cdec_Hypergraph *)__pyx_v_self), ((PyObject *)__pyx_v_size));
+  __Pyx_RefNannySetupContext("__set__ (wrapper)", 0);
+  __pyx_r = __pyx_pf_5_cdec_2NT_3ref_2__set__(((struct __pyx_obj_5_cdec_NT *)__pyx_v_self), ((PyObject *)__pyx_v_value));
   __Pyx_RefNannyFinishContext();
   return __pyx_r;
 }
 
-/* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":43
- *             del derivations
- * 
- *     def kbest_trees(self, size):             # <<<<<<<<<<<<<<
- *         cdef kbest.KBestDerivations[vector[WordID], kbest.FTreeTraversal]* f_derivations = new kbest.KBestDerivations[vector[WordID], kbest.FTreeTraversal](self.hg[0], size)
- *         cdef kbest.KBestDerivations[vector[WordID], kbest.FTreeTraversal].Derivation* f_derivation
- */
-
-static PyObject *__pyx_pf_5_cdec_10Hypergraph_13kbest_trees(struct __pyx_obj_5_cdec_Hypergraph *__pyx_v_self, PyObject *__pyx_v_size) {
-  struct __pyx_obj_5_cdec___pyx_scope_struct_3_kbest_trees *__pyx_cur_scope;
-  PyObject *__pyx_r = NULL;
+static int __pyx_pf_5_cdec_2NT_3ref_2__set__(struct __pyx_obj_5_cdec_NT *__pyx_v_self, PyObject *__pyx_v_value) {
+  int __pyx_r;
   __Pyx_RefNannyDeclarations
+  unsigned int __pyx_t_1;
   int __pyx_lineno = 0;
   const char *__pyx_filename = NULL;
   int __pyx_clineno = 0;
-  __Pyx_RefNannySetupContext("kbest_trees", 0);
-  __pyx_cur_scope = (struct __pyx_obj_5_cdec___pyx_scope_struct_3_kbest_trees *)__pyx_ptype_5_cdec___pyx_scope_struct_3_kbest_trees->tp_new(__pyx_ptype_5_cdec___pyx_scope_struct_3_kbest_trees, __pyx_empty_tuple, NULL);
-  if (unlikely(!__pyx_cur_scope)) {
-    __Pyx_RefNannyFinishContext();
-    return NULL;
-  }
-  __Pyx_GOTREF(__pyx_cur_scope);
-  __pyx_cur_scope->__pyx_v_self = __pyx_v_self;
-  __Pyx_INCREF((PyObject *)__pyx_cur_scope->__pyx_v_self);
-  __Pyx_GIVEREF((PyObject *)__pyx_cur_scope->__pyx_v_self);
-  __pyx_cur_scope->__pyx_v_size = __pyx_v_size;
-  __Pyx_INCREF(__pyx_cur_scope->__pyx_v_size);
-  __Pyx_GIVEREF(__pyx_cur_scope->__pyx_v_size);
-  {
-    __pyx_GeneratorObject *gen = __Pyx_Generator_New((__pyx_generator_body_t) __pyx_gb_5_cdec_10Hypergraph_15generator3, (PyObject *) __pyx_cur_scope); if (unlikely(!gen)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 43; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-    __Pyx_DECREF(__pyx_cur_scope);
-    __Pyx_RefNannyFinishContext();
-    return (PyObject *) gen;
-  }
+  __Pyx_RefNannySetupContext("__set__", 0);
+  __pyx_t_1 = __Pyx_PyInt_AsUnsignedInt(__pyx_v_value); if (unlikely((__pyx_t_1 == (unsigned int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 8; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_v_self->ref = __pyx_t_1;
 
-  __pyx_r = Py_None; __Pyx_INCREF(Py_None);
+  __pyx_r = 0;
   goto __pyx_L0;
   __pyx_L1_error:;
-  __Pyx_AddTraceback("_cdec.Hypergraph.kbest_trees", __pyx_clineno, __pyx_lineno, __pyx_filename);
-  __pyx_r = NULL;
+  __Pyx_AddTraceback("_cdec.NT.ref.__set__", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __pyx_r = -1;
   __pyx_L0:;
-  __Pyx_DECREF(((PyObject *)__pyx_cur_scope));
-  __Pyx_XGIVEREF(__pyx_r);
   __Pyx_RefNannyFinishContext();
   return __pyx_r;
 }
 
-static PyObject *__pyx_gb_5_cdec_10Hypergraph_15generator3(__pyx_GeneratorObject *__pyx_generator, PyObject *__pyx_sent_value) /* generator body */
-{
-  struct __pyx_obj_5_cdec___pyx_scope_struct_3_kbest_trees *__pyx_cur_scope = ((struct __pyx_obj_5_cdec___pyx_scope_struct_3_kbest_trees *)__pyx_generator->closure);
-  PyObject *__pyx_r = NULL;
-  unsigned int __pyx_t_1;
-  long __pyx_t_2;
-  int __pyx_t_3;
-  int __pyx_t_4;
-  int __pyx_t_5;
-  PyObject *__pyx_t_6 = NULL;
-  PyObject *__pyx_t_7 = NULL;
+/* Python wrapper */
+static int __pyx_pw_5_cdec_5NTRef_1__init__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/
+static int __pyx_pw_5_cdec_5NTRef_1__init__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) {
+  PyObject *__pyx_v_ref = 0;
+  static PyObject **__pyx_pyargnames[] = {&__pyx_n_s__ref,0};
+  int __pyx_r;
   __Pyx_RefNannyDeclarations
-  __Pyx_RefNannySetupContext("None", 0);
-  switch (__pyx_generator->resume_label) {
-    case 0: goto __pyx_L3_first_run;
-    case 1: goto __pyx_L10_resume_from_yield;
-    default: /* CPython raises the right error here */
-    __Pyx_RefNannyFinishContext();
-    return NULL;
-  }
-  __pyx_L3_first_run:;
-  if (unlikely(!__pyx_sent_value)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 43; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-
-  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":44
- * 
- *     def kbest_trees(self, size):
- *         cdef kbest.KBestDerivations[vector[WordID], kbest.FTreeTraversal]* f_derivations = new kbest.KBestDerivations[vector[WordID], kbest.FTreeTraversal](self.hg[0], size)             # <<<<<<<<<<<<<<
- *         cdef kbest.KBestDerivations[vector[WordID], kbest.FTreeTraversal].Derivation* f_derivation
- *         cdef kbest.KBestDerivations[vector[WordID], kbest.ETreeTraversal]* e_derivations = new kbest.KBestDerivations[vector[WordID], kbest.ETreeTraversal](self.hg[0], size)
- */
-  __pyx_t_1 = __Pyx_PyInt_AsUnsignedInt(__pyx_cur_scope->__pyx_v_size); if (unlikely((__pyx_t_1 == (unsigned int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 44; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __pyx_cur_scope->__pyx_v_f_derivations = new KBest::KBestDerivations<std::vector<WordID>,FTreeTraversal>((__pyx_cur_scope->__pyx_v_self->hg[0]), __pyx_t_1);
-
-  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":46
- *         cdef kbest.KBestDerivations[vector[WordID], kbest.FTreeTraversal]* f_derivations = new kbest.KBestDerivations[vector[WordID], kbest.FTreeTraversal](self.hg[0], size)
- *         cdef kbest.KBestDerivations[vector[WordID], kbest.FTreeTraversal].Derivation* f_derivation
- *         cdef kbest.KBestDerivations[vector[WordID], kbest.ETreeTraversal]* e_derivations = new kbest.KBestDerivations[vector[WordID], kbest.ETreeTraversal](self.hg[0], size)             # <<<<<<<<<<<<<<
- *         cdef kbest.KBestDerivations[vector[WordID], kbest.ETreeTraversal].Derivation* e_derivation
- *         cdef unsigned k
- */
-  __pyx_t_1 = __Pyx_PyInt_AsUnsignedInt(__pyx_cur_scope->__pyx_v_size); if (unlikely((__pyx_t_1 == (unsigned int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 46; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __pyx_cur_scope->__pyx_v_e_derivations = new KBest::KBestDerivations<std::vector<WordID>,ETreeTraversal>((__pyx_cur_scope->__pyx_v_self->hg[0]), __pyx_t_1);
-
-  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":49
- *         cdef kbest.KBestDerivations[vector[WordID], kbest.ETreeTraversal].Derivation* e_derivation
- *         cdef unsigned k
- *         try:             # <<<<<<<<<<<<<<
- *             for k in range(size):
- *                 f_derivation = f_derivations.LazyKthBest(self.hg.nodes_.size() - 1, k)
- */
-  /*try:*/ {
-
-    /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":50
- *         cdef unsigned k
- *         try:
- *             for k in range(size):             # <<<<<<<<<<<<<<
- *                 f_derivation = f_derivations.LazyKthBest(self.hg.nodes_.size() - 1, k)
- *                 e_derivation = e_derivations.LazyKthBest(self.hg.nodes_.size() - 1, k)
- */
-    __pyx_t_2 = __Pyx_PyInt_AsLong(__pyx_cur_scope->__pyx_v_size); if (unlikely((__pyx_t_2 == (long)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 50; __pyx_clineno = __LINE__; goto __pyx_L5;}
-    for (__pyx_t_1 = 0; __pyx_t_1 < __pyx_t_2; __pyx_t_1+=1) {
-      __pyx_cur_scope->__pyx_v_k = __pyx_t_1;
-
-      /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":51
- *         try:
- *             for k in range(size):
- *                 f_derivation = f_derivations.LazyKthBest(self.hg.nodes_.size() - 1, k)             # <<<<<<<<<<<<<<
- *                 e_derivation = e_derivations.LazyKthBest(self.hg.nodes_.size() - 1, k)
- *                 if not f_derivation or not e_derivation: break
- */
-      __pyx_cur_scope->__pyx_v_f_derivation = __pyx_cur_scope->__pyx_v_f_derivations->LazyKthBest((__pyx_cur_scope->__pyx_v_self->hg->nodes_.size() - 1), __pyx_cur_scope->__pyx_v_k);
-
-      /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":52
- *             for k in range(size):
- *                 f_derivation = f_derivations.LazyKthBest(self.hg.nodes_.size() - 1, k)
- *                 e_derivation = e_derivations.LazyKthBest(self.hg.nodes_.size() - 1, k)             # <<<<<<<<<<<<<<
- *                 if not f_derivation or not e_derivation: break
- *                 f_tree = unicode(GetString(f_derivation._yield).c_str(), 'utf8')
- */
-      __pyx_cur_scope->__pyx_v_e_derivation = __pyx_cur_scope->__pyx_v_e_derivations->LazyKthBest((__pyx_cur_scope->__pyx_v_self->hg->nodes_.size() - 1), __pyx_cur_scope->__pyx_v_k);
-
-      /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":53
- *                 f_derivation = f_derivations.LazyKthBest(self.hg.nodes_.size() - 1, k)
- *                 e_derivation = e_derivations.LazyKthBest(self.hg.nodes_.size() - 1, k)
- *                 if not f_derivation or not e_derivation: break             # <<<<<<<<<<<<<<
- *                 f_tree = unicode(GetString(f_derivation._yield).c_str(), 'utf8')
- *                 e_tree = unicode(GetString(e_derivation._yield).c_str(), 'utf8')
- */
-      __pyx_t_3 = (!(__pyx_cur_scope->__pyx_v_f_derivation != 0));
-      if (!__pyx_t_3) {
-        __pyx_t_4 = (!(__pyx_cur_scope->__pyx_v_e_derivation != 0));
-        __pyx_t_5 = __pyx_t_4;
-      } else {
-        __pyx_t_5 = __pyx_t_3;
+  __Pyx_RefNannySetupContext("__init__ (wrapper)", 0);
+  {
+    PyObject* values[1] = {0};
+    if (unlikely(__pyx_kwds)) {
+      Py_ssize_t kw_args;
+      const Py_ssize_t pos_args = PyTuple_GET_SIZE(__pyx_args);
+      switch (pos_args) {
+        case  1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0);
+        case  0: break;
+        default: goto __pyx_L5_argtuple_error;
       }
-      if (__pyx_t_5) {
-        goto __pyx_L8_break;
-        goto __pyx_L9;
+      kw_args = PyDict_Size(__pyx_kwds);
+      switch (pos_args) {
+        case  0:
+        values[0] = PyDict_GetItem(__pyx_kwds, __pyx_n_s__ref);
+        if (likely(values[0])) kw_args--;
+        else goto __pyx_L5_argtuple_error;
       }
-      __pyx_L9:;
-
-      /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":54
- *                 e_derivation = e_derivations.LazyKthBest(self.hg.nodes_.size() - 1, k)
- *                 if not f_derivation or not e_derivation: break
- *                 f_tree = unicode(GetString(f_derivation._yield).c_str(), 'utf8')             # <<<<<<<<<<<<<<
- *                 e_tree = unicode(GetString(e_derivation._yield).c_str(), 'utf8')
- *                 yield (f_tree, e_tree)
- */
-      __pyx_t_6 = PyBytes_FromString(TD::GetString(__pyx_cur_scope->__pyx_v_f_derivation->yield).c_str()); if (unlikely(!__pyx_t_6)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 54; __pyx_clineno = __LINE__; goto __pyx_L5;}
-      __Pyx_GOTREF(((PyObject *)__pyx_t_6));
-      __pyx_t_7 = PyTuple_New(2); if (unlikely(!__pyx_t_7)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 54; __pyx_clineno = __LINE__; goto __pyx_L5;}
-      __Pyx_GOTREF(__pyx_t_7);
-      PyTuple_SET_ITEM(__pyx_t_7, 0, ((PyObject *)__pyx_t_6));
-      __Pyx_GIVEREF(((PyObject *)__pyx_t_6));
-      __Pyx_INCREF(((PyObject *)__pyx_n_s__utf8));
-      PyTuple_SET_ITEM(__pyx_t_7, 1, ((PyObject *)__pyx_n_s__utf8));
-      __Pyx_GIVEREF(((PyObject *)__pyx_n_s__utf8));
-      __pyx_t_6 = 0;
-      __pyx_t_6 = PyObject_Call(((PyObject *)((PyObject*)(&PyUnicode_Type))), ((PyObject *)__pyx_t_7), NULL); if (unlikely(!__pyx_t_6)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 54; __pyx_clineno = __LINE__; goto __pyx_L5;}
-      __Pyx_GOTREF(__pyx_t_6);
-      __Pyx_DECREF(((PyObject *)__pyx_t_7)); __pyx_t_7 = 0;
-      __Pyx_XGOTREF(((PyObject *)__pyx_cur_scope->__pyx_v_f_tree));
-      __Pyx_XDECREF(((PyObject *)__pyx_cur_scope->__pyx_v_f_tree));
-      __Pyx_GIVEREF(__pyx_t_6);
-      __pyx_cur_scope->__pyx_v_f_tree = ((PyObject*)__pyx_t_6);
-      __pyx_t_6 = 0;
-
-      /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":55
- *                 if not f_derivation or not e_derivation: break
- *                 f_tree = unicode(GetString(f_derivation._yield).c_str(), 'utf8')
- *                 e_tree = unicode(GetString(e_derivation._yield).c_str(), 'utf8')             # <<<<<<<<<<<<<<
- *                 yield (f_tree, e_tree)
- *         finally:
- */
-      __pyx_t_6 = PyBytes_FromString(TD::GetString(__pyx_cur_scope->__pyx_v_e_derivation->yield).c_str()); if (unlikely(!__pyx_t_6)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 55; __pyx_clineno = __LINE__; goto __pyx_L5;}
-      __Pyx_GOTREF(((PyObject *)__pyx_t_6));
-      __pyx_t_7 = PyTuple_New(2); if (unlikely(!__pyx_t_7)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 55; __pyx_clineno = __LINE__; goto __pyx_L5;}
-      __Pyx_GOTREF(__pyx_t_7);
-      PyTuple_SET_ITEM(__pyx_t_7, 0, ((PyObject *)__pyx_t_6));
-      __Pyx_GIVEREF(((PyObject *)__pyx_t_6));
-      __Pyx_INCREF(((PyObject *)__pyx_n_s__utf8));
-      PyTuple_SET_ITEM(__pyx_t_7, 1, ((PyObject *)__pyx_n_s__utf8));
-      __Pyx_GIVEREF(((PyObject *)__pyx_n_s__utf8));
-      __pyx_t_6 = 0;
-      __pyx_t_6 = PyObject_Call(((PyObject *)((PyObject*)(&PyUnicode_Type))), ((PyObject *)__pyx_t_7), NULL); if (unlikely(!__pyx_t_6)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 55; __pyx_clineno = __LINE__; goto __pyx_L5;}
-      __Pyx_GOTREF(__pyx_t_6);
-      __Pyx_DECREF(((PyObject *)__pyx_t_7)); __pyx_t_7 = 0;
-      __Pyx_XGOTREF(((PyObject *)__pyx_cur_scope->__pyx_v_e_tree));
-      __Pyx_XDECREF(((PyObject *)__pyx_cur_scope->__pyx_v_e_tree));
-      __Pyx_GIVEREF(__pyx_t_6);
-      __pyx_cur_scope->__pyx_v_e_tree = ((PyObject*)__pyx_t_6);
-      __pyx_t_6 = 0;
-
-      /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":56
- *                 f_tree = unicode(GetString(f_derivation._yield).c_str(), 'utf8')
- *                 e_tree = unicode(GetString(e_derivation._yield).c_str(), 'utf8')
- *                 yield (f_tree, e_tree)             # <<<<<<<<<<<<<<
- *         finally:
- *             del f_derivations
- */
-      __pyx_t_6 = PyTuple_New(2); if (unlikely(!__pyx_t_6)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 56; __pyx_clineno = __LINE__; goto __pyx_L5;}
-      __Pyx_GOTREF(__pyx_t_6);
-      __Pyx_INCREF(((PyObject *)__pyx_cur_scope->__pyx_v_f_tree));
-      PyTuple_SET_ITEM(__pyx_t_6, 0, ((PyObject *)__pyx_cur_scope->__pyx_v_f_tree));
-      __Pyx_GIVEREF(((PyObject *)__pyx_cur_scope->__pyx_v_f_tree));
-      __Pyx_INCREF(((PyObject *)__pyx_cur_scope->__pyx_v_e_tree));
-      PyTuple_SET_ITEM(__pyx_t_6, 1, ((PyObject *)__pyx_cur_scope->__pyx_v_e_tree));
-      __Pyx_GIVEREF(((PyObject *)__pyx_cur_scope->__pyx_v_e_tree));
-      __pyx_r = ((PyObject *)__pyx_t_6);
-      __pyx_t_6 = 0;
-      __pyx_cur_scope->__pyx_t_0 = __pyx_t_1;
-      __pyx_cur_scope->__pyx_t_1 = __pyx_t_2;
-      __Pyx_XGIVEREF(__pyx_r);
-      __Pyx_RefNannyFinishContext();
-      /* return from generator, yielding value */
-      __pyx_generator->resume_label = 1;
-      return __pyx_r;
-      __pyx_L10_resume_from_yield:;
-      __pyx_t_1 = __pyx_cur_scope->__pyx_t_0;
-      __pyx_t_2 = __pyx_cur_scope->__pyx_t_1;
-      if (unlikely(!__pyx_sent_value)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 56; __pyx_clineno = __LINE__; goto __pyx_L5;}
+      if (unlikely(kw_args > 0)) {
+        if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "__init__") < 0)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 20; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+      }
+    } else if (PyTuple_GET_SIZE(__pyx_args) != 1) {
+      goto __pyx_L5_argtuple_error;
+    } else {
+      values[0] = PyTuple_GET_ITEM(__pyx_args, 0);
     }
-    __pyx_L8_break:;
+    __pyx_v_ref = values[0];
   }
+  goto __pyx_L4_argument_unpacking_done;
+  __pyx_L5_argtuple_error:;
+  __Pyx_RaiseArgtupleInvalid("__init__", 1, 1, 1, PyTuple_GET_SIZE(__pyx_args)); {__pyx_filename = __pyx_f[2]; __pyx_lineno = 20; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+  __pyx_L3_error:;
+  __Pyx_AddTraceback("_cdec.NTRef.__init__", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __Pyx_RefNannyFinishContext();
+  return -1;
+  __pyx_L4_argument_unpacking_done:;
+  __pyx_r = __pyx_pf_5_cdec_5NTRef___init__(((struct __pyx_obj_5_cdec_NTRef *)__pyx_v_self), __pyx_v_ref);
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":58
- *                 yield (f_tree, e_tree)
- *         finally:
- *             del f_derivations             # <<<<<<<<<<<<<<
- *             del e_derivations
+/* "/Users/vchahun/Sandbox/cdec/python/src/grammar.pxi":20
+ * cdef class NTRef:
+ *     cdef public unsigned ref
+ *     def __init__(self, ref):             # <<<<<<<<<<<<<<
+ *         self.ref = ref
  * 
  */
-  /*finally:*/ {
-    int __pyx_why;
-    PyObject *__pyx_exc_type, *__pyx_exc_value, *__pyx_exc_tb;
-    int __pyx_exc_lineno;
-    __pyx_exc_type = 0; __pyx_exc_value = 0; __pyx_exc_tb = 0; __pyx_exc_lineno = 0;
-    __pyx_why = 0; goto __pyx_L6;
-    __pyx_L5: {
-      __pyx_why = 4;
-      __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0;
-      __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0;
-      __Pyx_ErrFetch(&__pyx_exc_type, &__pyx_exc_value, &__pyx_exc_tb);
-      __pyx_exc_lineno = __pyx_lineno;
-      goto __pyx_L6;
-    }
-    __pyx_L6:;
-    delete __pyx_cur_scope->__pyx_v_f_derivations;
 
-    /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":59
- *         finally:
- *             del f_derivations
- *             del e_derivations             # <<<<<<<<<<<<<<
+static int __pyx_pf_5_cdec_5NTRef___init__(struct __pyx_obj_5_cdec_NTRef *__pyx_v_self, PyObject *__pyx_v_ref) {
+  int __pyx_r;
+  __Pyx_RefNannyDeclarations
+  unsigned int __pyx_t_1;
+  int __pyx_lineno = 0;
+  const char *__pyx_filename = NULL;
+  int __pyx_clineno = 0;
+  __Pyx_RefNannySetupContext("__init__", 0);
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/grammar.pxi":21
+ *     cdef public unsigned ref
+ *     def __init__(self, ref):
+ *         self.ref = ref             # <<<<<<<<<<<<<<
  * 
- *     def kbest_features(self, size):
+ *     def __str__(self):
  */
-    delete __pyx_cur_scope->__pyx_v_e_derivations;
-    switch (__pyx_why) {
-      case 4: {
-        __Pyx_ErrRestore(__pyx_exc_type, __pyx_exc_value, __pyx_exc_tb);
-        __pyx_lineno = __pyx_exc_lineno;
-        __pyx_exc_type = 0;
-        __pyx_exc_value = 0;
-        __pyx_exc_tb = 0;
-        goto __pyx_L1_error;
-      }
-    }
-  }
-  PyErr_SetNone(PyExc_StopIteration);
+  __pyx_t_1 = __Pyx_PyInt_AsUnsignedInt(__pyx_v_ref); if (unlikely((__pyx_t_1 == (unsigned int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 21; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_v_self->ref = __pyx_t_1;
+
+  __pyx_r = 0;
   goto __pyx_L0;
   __pyx_L1_error:;
-  __Pyx_XDECREF(__pyx_t_6);
-  __Pyx_XDECREF(__pyx_t_7);
-  __Pyx_AddTraceback("kbest_trees", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __Pyx_AddTraceback("_cdec.NTRef.__init__", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __pyx_r = -1;
   __pyx_L0:;
-  __Pyx_XDECREF(__pyx_r);
-  __pyx_generator->resume_label = -1;
   __Pyx_RefNannyFinishContext();
-  return NULL;
+  return __pyx_r;
 }
-static PyObject *__pyx_gb_5_cdec_10Hypergraph_18generator4(__pyx_GeneratorObject *__pyx_generator, PyObject *__pyx_sent_value); /* proto */
 
 /* Python wrapper */
-static PyObject *__pyx_pw_5_cdec_10Hypergraph_17kbest_features(PyObject *__pyx_v_self, PyObject *__pyx_v_size); /*proto*/
-static PyObject *__pyx_pw_5_cdec_10Hypergraph_17kbest_features(PyObject *__pyx_v_self, PyObject *__pyx_v_size) {
+static PyObject *__pyx_pw_5_cdec_5NTRef_3__str__(PyObject *__pyx_v_self); /*proto*/
+static PyObject *__pyx_pw_5_cdec_5NTRef_3__str__(PyObject *__pyx_v_self) {
   PyObject *__pyx_r = 0;
   __Pyx_RefNannyDeclarations
-  __Pyx_RefNannySetupContext("kbest_features (wrapper)", 0);
-  __pyx_r = __pyx_pf_5_cdec_10Hypergraph_16kbest_features(((struct __pyx_obj_5_cdec_Hypergraph *)__pyx_v_self), ((PyObject *)__pyx_v_size));
+  __Pyx_RefNannySetupContext("__str__ (wrapper)", 0);
+  __pyx_r = __pyx_pf_5_cdec_5NTRef_2__str__(((struct __pyx_obj_5_cdec_NTRef *)__pyx_v_self));
   __Pyx_RefNannyFinishContext();
   return __pyx_r;
 }
 
-/* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":61
- *             del e_derivations
+/* "/Users/vchahun/Sandbox/cdec/python/src/grammar.pxi":23
+ *         self.ref = ref
+ * 
+ *     def __str__(self):             # <<<<<<<<<<<<<<
+ *         return '[%d]' % self.ref
  * 
- *     def kbest_features(self, size):             # <<<<<<<<<<<<<<
- *         cdef kbest.KBestDerivations[FastSparseVector[weight_t], kbest.FeatureVectorTraversal]* derivations = new kbest.KBestDerivations[FastSparseVector[weight_t], kbest.FeatureVectorTraversal](self.hg[0], size)
- *         cdef kbest.KBestDerivations[FastSparseVector[weight_t], kbest.FeatureVectorTraversal].Derivation* derivation
  */
 
-static PyObject *__pyx_pf_5_cdec_10Hypergraph_16kbest_features(struct __pyx_obj_5_cdec_Hypergraph *__pyx_v_self, PyObject *__pyx_v_size) {
-  struct __pyx_obj_5_cdec___pyx_scope_struct_4_kbest_features *__pyx_cur_scope;
+static PyObject *__pyx_pf_5_cdec_5NTRef_2__str__(struct __pyx_obj_5_cdec_NTRef *__pyx_v_self) {
   PyObject *__pyx_r = NULL;
   __Pyx_RefNannyDeclarations
+  PyObject *__pyx_t_1 = NULL;
+  PyObject *__pyx_t_2 = NULL;
   int __pyx_lineno = 0;
   const char *__pyx_filename = NULL;
   int __pyx_clineno = 0;
-  __Pyx_RefNannySetupContext("kbest_features", 0);
-  __pyx_cur_scope = (struct __pyx_obj_5_cdec___pyx_scope_struct_4_kbest_features *)__pyx_ptype_5_cdec___pyx_scope_struct_4_kbest_features->tp_new(__pyx_ptype_5_cdec___pyx_scope_struct_4_kbest_features, __pyx_empty_tuple, NULL);
-  if (unlikely(!__pyx_cur_scope)) {
-    __Pyx_RefNannyFinishContext();
-    return NULL;
-  }
-  __Pyx_GOTREF(__pyx_cur_scope);
-  __pyx_cur_scope->__pyx_v_self = __pyx_v_self;
-  __Pyx_INCREF((PyObject *)__pyx_cur_scope->__pyx_v_self);
-  __Pyx_GIVEREF((PyObject *)__pyx_cur_scope->__pyx_v_self);
-  __pyx_cur_scope->__pyx_v_size = __pyx_v_size;
-  __Pyx_INCREF(__pyx_cur_scope->__pyx_v_size);
-  __Pyx_GIVEREF(__pyx_cur_scope->__pyx_v_size);
-  {
-    __pyx_GeneratorObject *gen = __Pyx_Generator_New((__pyx_generator_body_t) __pyx_gb_5_cdec_10Hypergraph_18generator4, (PyObject *) __pyx_cur_scope); if (unlikely(!gen)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 61; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-    __Pyx_DECREF(__pyx_cur_scope);
-    __Pyx_RefNannyFinishContext();
-    return (PyObject *) gen;
-  }
+  __Pyx_RefNannySetupContext("__str__", 0);
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/grammar.pxi":24
+ * 
+ *     def __str__(self):
+ *         return '[%d]' % self.ref             # <<<<<<<<<<<<<<
+ * 
+ * cdef class BaseTRule:
+ */
+  __Pyx_XDECREF(__pyx_r);
+  __pyx_t_1 = PyLong_FromUnsignedLong(__pyx_v_self->ref); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 24; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_1);
+  __pyx_t_2 = PyNumber_Remainder(((PyObject *)__pyx_kp_s_10), __pyx_t_1); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 24; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(((PyObject *)__pyx_t_2));
+  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+  __pyx_r = ((PyObject *)__pyx_t_2);
+  __pyx_t_2 = 0;
+  goto __pyx_L0;
 
   __pyx_r = Py_None; __Pyx_INCREF(Py_None);
   goto __pyx_L0;
   __pyx_L1_error:;
-  __Pyx_AddTraceback("_cdec.Hypergraph.kbest_features", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __Pyx_XDECREF(__pyx_t_1);
+  __Pyx_XDECREF(__pyx_t_2);
+  __Pyx_AddTraceback("_cdec.NTRef.__str__", __pyx_clineno, __pyx_lineno, __pyx_filename);
   __pyx_r = NULL;
   __pyx_L0:;
-  __Pyx_DECREF(((PyObject *)__pyx_cur_scope));
   __Pyx_XGIVEREF(__pyx_r);
   __Pyx_RefNannyFinishContext();
   return __pyx_r;
 }
 
-static PyObject *__pyx_gb_5_cdec_10Hypergraph_18generator4(__pyx_GeneratorObject *__pyx_generator, PyObject *__pyx_sent_value) /* generator body */
-{
-  struct __pyx_obj_5_cdec___pyx_scope_struct_4_kbest_features *__pyx_cur_scope = ((struct __pyx_obj_5_cdec___pyx_scope_struct_4_kbest_features *)__pyx_generator->closure);
-  PyObject *__pyx_r = NULL;
-  unsigned int __pyx_t_1;
-  long __pyx_t_2;
-  int __pyx_t_3;
-  PyObject *__pyx_t_4 = NULL;
+/* Python wrapper */
+static PyObject *__pyx_pw_5_cdec_5NTRef_3ref_1__get__(PyObject *__pyx_v_self); /*proto*/
+static PyObject *__pyx_pw_5_cdec_5NTRef_3ref_1__get__(PyObject *__pyx_v_self) {
+  PyObject *__pyx_r = 0;
   __Pyx_RefNannyDeclarations
-  __Pyx_RefNannySetupContext("None", 0);
-  switch (__pyx_generator->resume_label) {
-    case 0: goto __pyx_L3_first_run;
-    case 1: goto __pyx_L10_resume_from_yield;
-    default: /* CPython raises the right error here */
-    __Pyx_RefNannyFinishContext();
-    return NULL;
-  }
-  __pyx_L3_first_run:;
-  if (unlikely(!__pyx_sent_value)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 61; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_RefNannySetupContext("__get__ (wrapper)", 0);
+  __pyx_r = __pyx_pf_5_cdec_5NTRef_3ref___get__(((struct __pyx_obj_5_cdec_NTRef *)__pyx_v_self));
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":62
+/* "/Users/vchahun/Sandbox/cdec/python/src/grammar.pxi":19
  * 
- *     def kbest_features(self, size):
- *         cdef kbest.KBestDerivations[FastSparseVector[weight_t], kbest.FeatureVectorTraversal]* derivations = new kbest.KBestDerivations[FastSparseVector[weight_t], kbest.FeatureVectorTraversal](self.hg[0], size)             # <<<<<<<<<<<<<<
- *         cdef kbest.KBestDerivations[FastSparseVector[weight_t], kbest.FeatureVectorTraversal].Derivation* derivation
- *         cdef SparseVector fmap
- */
-  __pyx_t_1 = __Pyx_PyInt_AsUnsignedInt(__pyx_cur_scope->__pyx_v_size); if (unlikely((__pyx_t_1 == (unsigned int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 62; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __pyx_cur_scope->__pyx_v_derivations = new KBest::KBestDerivations<FastSparseVector<weight_t>,FeatureVectorTraversal>((__pyx_cur_scope->__pyx_v_self->hg[0]), __pyx_t_1);
-
-  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":66
- *         cdef SparseVector fmap
- *         cdef unsigned k
- *         try:             # <<<<<<<<<<<<<<
- *             for k in range(size):
- *                 derivation = derivations.LazyKthBest(self.hg.nodes_.size() - 1, k)
- */
-  /*try:*/ {
-
-    /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":67
- *         cdef unsigned k
- *         try:
- *             for k in range(size):             # <<<<<<<<<<<<<<
- *                 derivation = derivations.LazyKthBest(self.hg.nodes_.size() - 1, k)
- *                 if not derivation: break
- */
-    __pyx_t_2 = __Pyx_PyInt_AsLong(__pyx_cur_scope->__pyx_v_size); if (unlikely((__pyx_t_2 == (long)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 67; __pyx_clineno = __LINE__; goto __pyx_L5;}
-    for (__pyx_t_1 = 0; __pyx_t_1 < __pyx_t_2; __pyx_t_1+=1) {
-      __pyx_cur_scope->__pyx_v_k = __pyx_t_1;
-
-      /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":68
- *         try:
- *             for k in range(size):
- *                 derivation = derivations.LazyKthBest(self.hg.nodes_.size() - 1, k)             # <<<<<<<<<<<<<<
- *                 if not derivation: break
- *                 fmap = SparseVector()
- */
-      __pyx_cur_scope->__pyx_v_derivation = __pyx_cur_scope->__pyx_v_derivations->LazyKthBest((__pyx_cur_scope->__pyx_v_self->hg->nodes_.size() - 1), __pyx_cur_scope->__pyx_v_k);
-
-      /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":69
- *             for k in range(size):
- *                 derivation = derivations.LazyKthBest(self.hg.nodes_.size() - 1, k)
- *                 if not derivation: break             # <<<<<<<<<<<<<<
- *                 fmap = SparseVector()
- *                 fmap.vector = new FastSparseVector[weight_t](derivation._yield)
- */
-      __pyx_t_3 = (!(__pyx_cur_scope->__pyx_v_derivation != 0));
-      if (__pyx_t_3) {
-        goto __pyx_L8_break;
-        goto __pyx_L9;
-      }
-      __pyx_L9:;
-
-      /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":70
- *                 derivation = derivations.LazyKthBest(self.hg.nodes_.size() - 1, k)
- *                 if not derivation: break
- *                 fmap = SparseVector()             # <<<<<<<<<<<<<<
- *                 fmap.vector = new FastSparseVector[weight_t](derivation._yield)
- *                 yield fmap
- */
-      __pyx_t_4 = PyObject_Call(((PyObject *)((PyObject*)__pyx_ptype_5_cdec_SparseVector)), ((PyObject *)__pyx_empty_tuple), NULL); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 70; __pyx_clineno = __LINE__; goto __pyx_L5;}
-      __Pyx_GOTREF(__pyx_t_4);
-      __Pyx_XGOTREF(((PyObject *)__pyx_cur_scope->__pyx_v_fmap));
-      __Pyx_XDECREF(((PyObject *)__pyx_cur_scope->__pyx_v_fmap));
-      __Pyx_GIVEREF(__pyx_t_4);
-      __pyx_cur_scope->__pyx_v_fmap = ((struct __pyx_obj_5_cdec_SparseVector *)__pyx_t_4);
-      __pyx_t_4 = 0;
-
-      /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":71
- *                 if not derivation: break
- *                 fmap = SparseVector()
- *                 fmap.vector = new FastSparseVector[weight_t](derivation._yield)             # <<<<<<<<<<<<<<
- *                 yield fmap
- *         finally:
+ * cdef class NTRef:
+ *     cdef public unsigned ref             # <<<<<<<<<<<<<<
+ *     def __init__(self, ref):
+ *         self.ref = ref
  */
-      __pyx_cur_scope->__pyx_v_fmap->vector = new FastSparseVector<weight_t>(__pyx_cur_scope->__pyx_v_derivation->yield);
 
-      /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":72
- *                 fmap = SparseVector()
- *                 fmap.vector = new FastSparseVector[weight_t](derivation._yield)
- *                 yield fmap             # <<<<<<<<<<<<<<
- *         finally:
- *             del derivations
- */
-      __Pyx_INCREF(((PyObject *)__pyx_cur_scope->__pyx_v_fmap));
-      __pyx_r = ((PyObject *)__pyx_cur_scope->__pyx_v_fmap);
-      __pyx_cur_scope->__pyx_t_0 = __pyx_t_1;
-      __pyx_cur_scope->__pyx_t_1 = __pyx_t_2;
-      __Pyx_XGIVEREF(__pyx_r);
-      __Pyx_RefNannyFinishContext();
-      /* return from generator, yielding value */
-      __pyx_generator->resume_label = 1;
-      return __pyx_r;
-      __pyx_L10_resume_from_yield:;
-      __pyx_t_1 = __pyx_cur_scope->__pyx_t_0;
-      __pyx_t_2 = __pyx_cur_scope->__pyx_t_1;
-      if (unlikely(!__pyx_sent_value)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 72; __pyx_clineno = __LINE__; goto __pyx_L5;}
-    }
-    __pyx_L8_break:;
-  }
+static PyObject *__pyx_pf_5_cdec_5NTRef_3ref___get__(struct __pyx_obj_5_cdec_NTRef *__pyx_v_self) {
+  PyObject *__pyx_r = NULL;
+  __Pyx_RefNannyDeclarations
+  PyObject *__pyx_t_1 = NULL;
+  int __pyx_lineno = 0;
+  const char *__pyx_filename = NULL;
+  int __pyx_clineno = 0;
+  __Pyx_RefNannySetupContext("__get__", 0);
+  __Pyx_XDECREF(__pyx_r);
+  __pyx_t_1 = PyLong_FromUnsignedLong(__pyx_v_self->ref); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 19; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_1);
+  __pyx_r = __pyx_t_1;
+  __pyx_t_1 = 0;
+  goto __pyx_L0;
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":74
- *                 yield fmap
- *         finally:
- *             del derivations             # <<<<<<<<<<<<<<
- * 
- *     def sample(self, unsigned n):
- */
-  /*finally:*/ {
-    int __pyx_why;
-    PyObject *__pyx_exc_type, *__pyx_exc_value, *__pyx_exc_tb;
-    int __pyx_exc_lineno;
-    __pyx_exc_type = 0; __pyx_exc_value = 0; __pyx_exc_tb = 0; __pyx_exc_lineno = 0;
-    __pyx_why = 0; goto __pyx_L6;
-    __pyx_L5: {
-      __pyx_why = 4;
-      __Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0;
-      __Pyx_ErrFetch(&__pyx_exc_type, &__pyx_exc_value, &__pyx_exc_tb);
-      __pyx_exc_lineno = __pyx_lineno;
-      goto __pyx_L6;
-    }
-    __pyx_L6:;
-    delete __pyx_cur_scope->__pyx_v_derivations;
-    switch (__pyx_why) {
-      case 4: {
-        __Pyx_ErrRestore(__pyx_exc_type, __pyx_exc_value, __pyx_exc_tb);
-        __pyx_lineno = __pyx_exc_lineno;
-        __pyx_exc_type = 0;
-        __pyx_exc_value = 0;
-        __pyx_exc_tb = 0;
-        goto __pyx_L1_error;
-      }
-    }
-  }
-  PyErr_SetNone(PyExc_StopIteration);
+  __pyx_r = Py_None; __Pyx_INCREF(Py_None);
   goto __pyx_L0;
   __pyx_L1_error:;
-  __Pyx_XDECREF(__pyx_t_4);
-  __Pyx_AddTraceback("kbest_features", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __Pyx_XDECREF(__pyx_t_1);
+  __Pyx_AddTraceback("_cdec.NTRef.ref.__get__", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __pyx_r = NULL;
   __pyx_L0:;
-  __Pyx_XDECREF(__pyx_r);
-  __pyx_generator->resume_label = -1;
+  __Pyx_XGIVEREF(__pyx_r);
   __Pyx_RefNannyFinishContext();
-  return NULL;
+  return __pyx_r;
 }
-static PyObject *__pyx_gb_5_cdec_10Hypergraph_21generator5(__pyx_GeneratorObject *__pyx_generator, PyObject *__pyx_sent_value); /* proto */
 
 /* Python wrapper */
-static PyObject *__pyx_pw_5_cdec_10Hypergraph_20sample(PyObject *__pyx_v_self, PyObject *__pyx_arg_n); /*proto*/
-static PyObject *__pyx_pw_5_cdec_10Hypergraph_20sample(PyObject *__pyx_v_self, PyObject *__pyx_arg_n) {
-  unsigned int __pyx_v_n;
-  PyObject *__pyx_r = 0;
+static int __pyx_pw_5_cdec_5NTRef_3ref_3__set__(PyObject *__pyx_v_self, PyObject *__pyx_v_value); /*proto*/
+static int __pyx_pw_5_cdec_5NTRef_3ref_3__set__(PyObject *__pyx_v_self, PyObject *__pyx_v_value) {
+  int __pyx_r;
   __Pyx_RefNannyDeclarations
-  __Pyx_RefNannySetupContext("sample (wrapper)", 0);
-  assert(__pyx_arg_n); {
-    __pyx_v_n = __Pyx_PyInt_AsUnsignedInt(__pyx_arg_n); if (unlikely((__pyx_v_n == (unsigned int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 76; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
-  }
-  goto __pyx_L4_argument_unpacking_done;
-  __pyx_L3_error:;
-  __Pyx_AddTraceback("_cdec.Hypergraph.sample", __pyx_clineno, __pyx_lineno, __pyx_filename);
-  __Pyx_RefNannyFinishContext();
-  return NULL;
-  __pyx_L4_argument_unpacking_done:;
-  __pyx_r = __pyx_pf_5_cdec_10Hypergraph_19sample(((struct __pyx_obj_5_cdec_Hypergraph *)__pyx_v_self), ((unsigned int)__pyx_v_n));
+  __Pyx_RefNannySetupContext("__set__ (wrapper)", 0);
+  __pyx_r = __pyx_pf_5_cdec_5NTRef_3ref_2__set__(((struct __pyx_obj_5_cdec_NTRef *)__pyx_v_self), ((PyObject *)__pyx_v_value));
   __Pyx_RefNannyFinishContext();
   return __pyx_r;
 }
 
-/* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":76
- *             del derivations
- * 
- *     def sample(self, unsigned n):             # <<<<<<<<<<<<<<
- *         cdef vector[hypergraph.Hypothesis]* hypos = new vector[hypergraph.Hypothesis]()
- *         if self.rng == NULL:
- */
-
-static PyObject *__pyx_pf_5_cdec_10Hypergraph_19sample(struct __pyx_obj_5_cdec_Hypergraph *__pyx_v_self, unsigned int __pyx_v_n) {
-  struct __pyx_obj_5_cdec___pyx_scope_struct_5_sample *__pyx_cur_scope;
-  PyObject *__pyx_r = NULL;
+static int __pyx_pf_5_cdec_5NTRef_3ref_2__set__(struct __pyx_obj_5_cdec_NTRef *__pyx_v_self, PyObject *__pyx_v_value) {
+  int __pyx_r;
   __Pyx_RefNannyDeclarations
+  unsigned int __pyx_t_1;
   int __pyx_lineno = 0;
   const char *__pyx_filename = NULL;
   int __pyx_clineno = 0;
-  __Pyx_RefNannySetupContext("sample", 0);
-  __pyx_cur_scope = (struct __pyx_obj_5_cdec___pyx_scope_struct_5_sample *)__pyx_ptype_5_cdec___pyx_scope_struct_5_sample->tp_new(__pyx_ptype_5_cdec___pyx_scope_struct_5_sample, __pyx_empty_tuple, NULL);
-  if (unlikely(!__pyx_cur_scope)) {
-    __Pyx_RefNannyFinishContext();
-    return NULL;
-  }
-  __Pyx_GOTREF(__pyx_cur_scope);
-  __pyx_cur_scope->__pyx_v_self = __pyx_v_self;
-  __Pyx_INCREF((PyObject *)__pyx_cur_scope->__pyx_v_self);
-  __Pyx_GIVEREF((PyObject *)__pyx_cur_scope->__pyx_v_self);
-  __pyx_cur_scope->__pyx_v_n = __pyx_v_n;
-  {
-    __pyx_GeneratorObject *gen = __Pyx_Generator_New((__pyx_generator_body_t) __pyx_gb_5_cdec_10Hypergraph_21generator5, (PyObject *) __pyx_cur_scope); if (unlikely(!gen)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 76; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-    __Pyx_DECREF(__pyx_cur_scope);
-    __Pyx_RefNannyFinishContext();
-    return (PyObject *) gen;
-  }
+  __Pyx_RefNannySetupContext("__set__", 0);
+  __pyx_t_1 = __Pyx_PyInt_AsUnsignedInt(__pyx_v_value); if (unlikely((__pyx_t_1 == (unsigned int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 19; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_v_self->ref = __pyx_t_1;
 
-  __pyx_r = Py_None; __Pyx_INCREF(Py_None);
+  __pyx_r = 0;
   goto __pyx_L0;
   __pyx_L1_error:;
-  __Pyx_AddTraceback("_cdec.Hypergraph.sample", __pyx_clineno, __pyx_lineno, __pyx_filename);
-  __pyx_r = NULL;
+  __Pyx_AddTraceback("_cdec.NTRef.ref.__set__", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __pyx_r = -1;
   __pyx_L0:;
-  __Pyx_DECREF(((PyObject *)__pyx_cur_scope));
-  __Pyx_XGIVEREF(__pyx_r);
   __Pyx_RefNannyFinishContext();
   return __pyx_r;
 }
 
-static PyObject *__pyx_gb_5_cdec_10Hypergraph_21generator5(__pyx_GeneratorObject *__pyx_generator, PyObject *__pyx_sent_value) /* generator body */
-{
-  struct __pyx_obj_5_cdec___pyx_scope_struct_5_sample *__pyx_cur_scope = ((struct __pyx_obj_5_cdec___pyx_scope_struct_5_sample *)__pyx_generator->closure);
-  PyObject *__pyx_r = NULL;
-  int __pyx_t_1;
-  size_t __pyx_t_2;
-  unsigned int __pyx_t_3;
-  PyObject *__pyx_t_4 = NULL;
-  PyObject *__pyx_t_5 = NULL;
+/* Python wrapper */
+static void __pyx_pw_5_cdec_9BaseTRule_1__dealloc__(PyObject *__pyx_v_self); /*proto*/
+static void __pyx_pw_5_cdec_9BaseTRule_1__dealloc__(PyObject *__pyx_v_self) {
   __Pyx_RefNannyDeclarations
-  __Pyx_RefNannySetupContext("None", 0);
-  switch (__pyx_generator->resume_label) {
-    case 0: goto __pyx_L3_first_run;
-    case 1: goto __pyx_L10_resume_from_yield;
-    default: /* CPython raises the right error here */
-    __Pyx_RefNannyFinishContext();
-    return NULL;
-  }
-  __pyx_L3_first_run:;
-  if (unlikely(!__pyx_sent_value)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 76; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_RefNannySetupContext("__dealloc__ (wrapper)", 0);
+  __pyx_pf_5_cdec_9BaseTRule___dealloc__(((struct __pyx_obj_5_cdec_BaseTRule *)__pyx_v_self));
+  __Pyx_RefNannyFinishContext();
+}
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":77
+/* "/Users/vchahun/Sandbox/cdec/python/src/grammar.pxi":29
+ *     cdef shared_ptr[grammar.TRule]* rule
+ * 
+ *     def __dealloc__(self):             # <<<<<<<<<<<<<<
+ *         del self.rule
  * 
- *     def sample(self, unsigned n):
- *         cdef vector[hypergraph.Hypothesis]* hypos = new vector[hypergraph.Hypothesis]()             # <<<<<<<<<<<<<<
- *         if self.rng == NULL:
- *             self.rng = new MT19937()
- */
-  __pyx_cur_scope->__pyx_v_hypos = new std::vector<HypergraphSampler::Hypothesis>();
-
-  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":78
- *     def sample(self, unsigned n):
- *         cdef vector[hypergraph.Hypothesis]* hypos = new vector[hypergraph.Hypothesis]()
- *         if self.rng == NULL:             # <<<<<<<<<<<<<<
- *             self.rng = new MT19937()
- *         hypergraph.sample_hypotheses(self.hg[0], n, self.rng, hypos)
- */
-  __pyx_t_1 = (__pyx_cur_scope->__pyx_v_self->rng == NULL);
-  if (__pyx_t_1) {
-
-    /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":79
- *         cdef vector[hypergraph.Hypothesis]* hypos = new vector[hypergraph.Hypothesis]()
- *         if self.rng == NULL:
- *             self.rng = new MT19937()             # <<<<<<<<<<<<<<
- *         hypergraph.sample_hypotheses(self.hg[0], n, self.rng, hypos)
- *         cdef unsigned k
- */
-    __pyx_cur_scope->__pyx_v_self->rng = new MT19937();
-    goto __pyx_L4;
-  }
-  __pyx_L4:;
-
-  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":80
- *         if self.rng == NULL:
- *             self.rng = new MT19937()
- *         hypergraph.sample_hypotheses(self.hg[0], n, self.rng, hypos)             # <<<<<<<<<<<<<<
- *         cdef unsigned k
- *         try:
- */
-  HypergraphSampler::sample_hypotheses((__pyx_cur_scope->__pyx_v_self->hg[0]), __pyx_cur_scope->__pyx_v_n, __pyx_cur_scope->__pyx_v_self->rng, __pyx_cur_scope->__pyx_v_hypos);
-
-  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":82
- *         hypergraph.sample_hypotheses(self.hg[0], n, self.rng, hypos)
- *         cdef unsigned k
- *         try:             # <<<<<<<<<<<<<<
- *             for k in range(hypos.size()):
- *                 yield unicode(GetString(hypos[0][k].words).c_str(), 'utf8')
- */
-  /*try:*/ {
-
-    /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":83
- *         cdef unsigned k
- *         try:
- *             for k in range(hypos.size()):             # <<<<<<<<<<<<<<
- *                 yield unicode(GetString(hypos[0][k].words).c_str(), 'utf8')
- *         finally:
  */
-    __pyx_t_2 = __pyx_cur_scope->__pyx_v_hypos->size();
-    for (__pyx_t_3 = 0; __pyx_t_3 < __pyx_t_2; __pyx_t_3+=1) {
-      __pyx_cur_scope->__pyx_v_k = __pyx_t_3;
 
-      /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":84
- *         try:
- *             for k in range(hypos.size()):
- *                 yield unicode(GetString(hypos[0][k].words).c_str(), 'utf8')             # <<<<<<<<<<<<<<
- *         finally:
- *             del hypos
- */
-      __pyx_t_4 = PyBytes_FromString(TD::GetString(((__pyx_cur_scope->__pyx_v_hypos[0])[__pyx_cur_scope->__pyx_v_k]).words).c_str()); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 84; __pyx_clineno = __LINE__; goto __pyx_L6;}
-      __Pyx_GOTREF(((PyObject *)__pyx_t_4));
-      __pyx_t_5 = PyTuple_New(2); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 84; __pyx_clineno = __LINE__; goto __pyx_L6;}
-      __Pyx_GOTREF(__pyx_t_5);
-      PyTuple_SET_ITEM(__pyx_t_5, 0, ((PyObject *)__pyx_t_4));
-      __Pyx_GIVEREF(((PyObject *)__pyx_t_4));
-      __Pyx_INCREF(((PyObject *)__pyx_n_s__utf8));
-      PyTuple_SET_ITEM(__pyx_t_5, 1, ((PyObject *)__pyx_n_s__utf8));
-      __Pyx_GIVEREF(((PyObject *)__pyx_n_s__utf8));
-      __pyx_t_4 = 0;
-      __pyx_t_4 = PyObject_Call(((PyObject *)((PyObject*)(&PyUnicode_Type))), ((PyObject *)__pyx_t_5), NULL); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 84; __pyx_clineno = __LINE__; goto __pyx_L6;}
-      __Pyx_GOTREF(__pyx_t_4);
-      __Pyx_DECREF(((PyObject *)__pyx_t_5)); __pyx_t_5 = 0;
-      __pyx_r = __pyx_t_4;
-      __pyx_t_4 = 0;
-      __pyx_cur_scope->__pyx_t_0 = __pyx_t_2;
-      __pyx_cur_scope->__pyx_t_1 = __pyx_t_3;
-      __Pyx_XGIVEREF(__pyx_r);
-      __Pyx_RefNannyFinishContext();
-      /* return from generator, yielding value */
-      __pyx_generator->resume_label = 1;
-      return __pyx_r;
-      __pyx_L10_resume_from_yield:;
-      __pyx_t_2 = __pyx_cur_scope->__pyx_t_0;
-      __pyx_t_3 = __pyx_cur_scope->__pyx_t_1;
-      if (unlikely(!__pyx_sent_value)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 84; __pyx_clineno = __LINE__; goto __pyx_L6;}
-    }
-  }
+static void __pyx_pf_5_cdec_9BaseTRule___dealloc__(CYTHON_UNUSED struct __pyx_obj_5_cdec_BaseTRule *__pyx_v_self) {
+  __Pyx_RefNannyDeclarations
+  __Pyx_RefNannySetupContext("__dealloc__", 0);
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":86
- *                 yield unicode(GetString(hypos[0][k].words).c_str(), 'utf8')
- *         finally:
- *             del hypos             # <<<<<<<<<<<<<<
+  /* "/Users/vchahun/Sandbox/cdec/python/src/grammar.pxi":30
  * 
- *     def intersect(self, Lattice lat):
+ *     def __dealloc__(self):
+ *         del self.rule             # <<<<<<<<<<<<<<
+ * 
+ *     property arity:
  */
-  /*finally:*/ {
-    int __pyx_why;
-    PyObject *__pyx_exc_type, *__pyx_exc_value, *__pyx_exc_tb;
-    int __pyx_exc_lineno;
-    __pyx_exc_type = 0; __pyx_exc_value = 0; __pyx_exc_tb = 0; __pyx_exc_lineno = 0;
-    __pyx_why = 0; goto __pyx_L7;
-    __pyx_L6: {
-      __pyx_why = 4;
-      __Pyx_XDECREF(__pyx_t_5); __pyx_t_5 = 0;
-      __Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0;
-      __Pyx_ErrFetch(&__pyx_exc_type, &__pyx_exc_value, &__pyx_exc_tb);
-      __pyx_exc_lineno = __pyx_lineno;
-      goto __pyx_L7;
-    }
-    __pyx_L7:;
-    delete __pyx_cur_scope->__pyx_v_hypos;
-    switch (__pyx_why) {
-      case 4: {
-        __Pyx_ErrRestore(__pyx_exc_type, __pyx_exc_value, __pyx_exc_tb);
-        __pyx_lineno = __pyx_exc_lineno;
-        __pyx_exc_type = 0;
-        __pyx_exc_value = 0;
-        __pyx_exc_tb = 0;
-        goto __pyx_L1_error;
-      }
-    }
-  }
-  PyErr_SetNone(PyExc_StopIteration);
-  goto __pyx_L0;
-  __pyx_L1_error:;
-  __Pyx_XDECREF(__pyx_t_4);
-  __Pyx_XDECREF(__pyx_t_5);
-  __Pyx_AddTraceback("sample", __pyx_clineno, __pyx_lineno, __pyx_filename);
-  __pyx_L0:;
-  __Pyx_XDECREF(__pyx_r);
-  __pyx_generator->resume_label = -1;
+  delete __pyx_v_self->rule;
+
   __Pyx_RefNannyFinishContext();
-  return NULL;
 }
 
 /* Python wrapper */
-static PyObject *__pyx_pw_5_cdec_10Hypergraph_23intersect(PyObject *__pyx_v_self, PyObject *__pyx_v_lat); /*proto*/
-static PyObject *__pyx_pw_5_cdec_10Hypergraph_23intersect(PyObject *__pyx_v_self, PyObject *__pyx_v_lat) {
+static PyObject *__pyx_pw_5_cdec_9BaseTRule_5arity_1__get__(PyObject *__pyx_v_self); /*proto*/
+static PyObject *__pyx_pw_5_cdec_9BaseTRule_5arity_1__get__(PyObject *__pyx_v_self) {
   PyObject *__pyx_r = 0;
   __Pyx_RefNannyDeclarations
-  __Pyx_RefNannySetupContext("intersect (wrapper)", 0);
-  if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_lat), __pyx_ptype_5_cdec_Lattice, 1, "lat", 0))) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 88; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __pyx_r = __pyx_pf_5_cdec_10Hypergraph_22intersect(((struct __pyx_obj_5_cdec_Hypergraph *)__pyx_v_self), ((struct __pyx_obj_5_cdec_Lattice *)__pyx_v_lat));
-  goto __pyx_L0;
-  __pyx_L1_error:;
-  __pyx_r = NULL;
-  __pyx_L0:;
+  __Pyx_RefNannySetupContext("__get__ (wrapper)", 0);
+  __pyx_r = __pyx_pf_5_cdec_9BaseTRule_5arity___get__(((struct __pyx_obj_5_cdec_BaseTRule *)__pyx_v_self));
   __Pyx_RefNannyFinishContext();
   return __pyx_r;
 }
 
-/* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":88
- *             del hypos
+/* "/Users/vchahun/Sandbox/cdec/python/src/grammar.pxi":33
  * 
- *     def intersect(self, Lattice lat):             # <<<<<<<<<<<<<<
- *         return hypergraph.Intersect(lat.lattice[0], self.hg)
+ *     property arity:
+ *         def __get__(self):             # <<<<<<<<<<<<<<
+ *             return self.rule.get().arity_
  * 
  */
 
-static PyObject *__pyx_pf_5_cdec_10Hypergraph_22intersect(struct __pyx_obj_5_cdec_Hypergraph *__pyx_v_self, struct __pyx_obj_5_cdec_Lattice *__pyx_v_lat) {
+static PyObject *__pyx_pf_5_cdec_9BaseTRule_5arity___get__(struct __pyx_obj_5_cdec_BaseTRule *__pyx_v_self) {
   PyObject *__pyx_r = NULL;
   __Pyx_RefNannyDeclarations
   PyObject *__pyx_t_1 = NULL;
   int __pyx_lineno = 0;
   const char *__pyx_filename = NULL;
   int __pyx_clineno = 0;
-  __Pyx_RefNannySetupContext("intersect", 0);
+  __Pyx_RefNannySetupContext("__get__", 0);
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":89
- * 
- *     def intersect(self, Lattice lat):
- *         return hypergraph.Intersect(lat.lattice[0], self.hg)             # <<<<<<<<<<<<<<
+  /* "/Users/vchahun/Sandbox/cdec/python/src/grammar.pxi":34
+ *     property arity:
+ *         def __get__(self):
+ *             return self.rule.get().arity_             # <<<<<<<<<<<<<<
  * 
- *     def prune(self, beam_alpha=0, density=0, **kwargs):
+ *     property f:
  */
   __Pyx_XDECREF(__pyx_r);
-  __pyx_t_1 = __Pyx_PyBool_FromLong(HG::Intersect((__pyx_v_lat->lattice[0]), __pyx_v_self->hg)); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 89; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_1 = PyInt_FromLong(__pyx_v_self->rule->get()->arity_); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 34; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __Pyx_GOTREF(__pyx_t_1);
   __pyx_r = __pyx_t_1;
   __pyx_t_1 = 0;
@@ -5446,7 +5108,7 @@ static PyObject *__pyx_pf_5_cdec_10Hypergraph_22intersect(struct __pyx_obj_5_cde
   goto __pyx_L0;
   __pyx_L1_error:;
   __Pyx_XDECREF(__pyx_t_1);
-  __Pyx_AddTraceback("_cdec.Hypergraph.intersect", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __Pyx_AddTraceback("_cdec.BaseTRule.arity.__get__", __pyx_clineno, __pyx_lineno, __pyx_filename);
   __pyx_r = NULL;
   __pyx_L0:;
   __Pyx_XGIVEREF(__pyx_r);
@@ -5455,423 +5117,682 @@ static PyObject *__pyx_pf_5_cdec_10Hypergraph_22intersect(struct __pyx_obj_5_cde
 }
 
 /* Python wrapper */
-static PyObject *__pyx_pw_5_cdec_10Hypergraph_25prune(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/
-static PyObject *__pyx_pw_5_cdec_10Hypergraph_25prune(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) {
-  PyObject *__pyx_v_beam_alpha = 0;
-  PyObject *__pyx_v_density = 0;
-  PyObject *__pyx_v_kwargs = 0;
-  static PyObject **__pyx_pyargnames[] = {&__pyx_n_s__beam_alpha,&__pyx_n_s__density,0};
+static PyObject *__pyx_pw_5_cdec_9BaseTRule_1f_1__get__(PyObject *__pyx_v_self); /*proto*/
+static PyObject *__pyx_pw_5_cdec_9BaseTRule_1f_1__get__(PyObject *__pyx_v_self) {
   PyObject *__pyx_r = 0;
   __Pyx_RefNannyDeclarations
-  __Pyx_RefNannySetupContext("prune (wrapper)", 0);
-  __pyx_v_kwargs = PyDict_New(); if (unlikely(!__pyx_v_kwargs)) return NULL;
-  __Pyx_GOTREF(__pyx_v_kwargs);
-  {
-    PyObject* values[2] = {0,0};
-    values[0] = ((PyObject *)__pyx_int_0);
-    values[1] = ((PyObject *)__pyx_int_0);
-    if (unlikely(__pyx_kwds)) {
-      Py_ssize_t kw_args;
-      const Py_ssize_t pos_args = PyTuple_GET_SIZE(__pyx_args);
-      switch (pos_args) {
-        case  2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1);
-        case  1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0);
-        case  0: break;
-        default: goto __pyx_L5_argtuple_error;
-      }
-      kw_args = PyDict_Size(__pyx_kwds);
-      switch (pos_args) {
-        case  0:
-        if (kw_args > 0) {
-          PyObject* value = PyDict_GetItem(__pyx_kwds, __pyx_n_s__beam_alpha);
-          if (value) { values[0] = value; kw_args--; }
-        }
-        case  1:
-        if (kw_args > 0) {
-          PyObject* value = PyDict_GetItem(__pyx_kwds, __pyx_n_s__density);
-          if (value) { values[1] = value; kw_args--; }
-        }
-      }
-      if (unlikely(kw_args > 0)) {
-        if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, __pyx_v_kwargs, values, pos_args, "prune") < 0)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 91; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
-      }
-    } else {
-      switch (PyTuple_GET_SIZE(__pyx_args)) {
-        case  2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1);
-        case  1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0);
-        case  0: break;
-        default: goto __pyx_L5_argtuple_error;
-      }
-    }
-    __pyx_v_beam_alpha = values[0];
-    __pyx_v_density = values[1];
-  }
-  goto __pyx_L4_argument_unpacking_done;
-  __pyx_L5_argtuple_error:;
-  __Pyx_RaiseArgtupleInvalid("prune", 0, 0, 2, PyTuple_GET_SIZE(__pyx_args)); {__pyx_filename = __pyx_f[2]; __pyx_lineno = 91; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
-  __pyx_L3_error:;
-  __Pyx_DECREF(__pyx_v_kwargs); __pyx_v_kwargs = 0;
-  __Pyx_AddTraceback("_cdec.Hypergraph.prune", __pyx_clineno, __pyx_lineno, __pyx_filename);
-  __Pyx_RefNannyFinishContext();
-  return NULL;
-  __pyx_L4_argument_unpacking_done:;
-  __pyx_r = __pyx_pf_5_cdec_10Hypergraph_24prune(((struct __pyx_obj_5_cdec_Hypergraph *)__pyx_v_self), __pyx_v_beam_alpha, __pyx_v_density, __pyx_v_kwargs);
-  __Pyx_XDECREF(__pyx_v_kwargs);
+  __Pyx_RefNannySetupContext("__get__ (wrapper)", 0);
+  __pyx_r = __pyx_pf_5_cdec_9BaseTRule_1f___get__(((struct __pyx_obj_5_cdec_BaseTRule *)__pyx_v_self));
   __Pyx_RefNannyFinishContext();
   return __pyx_r;
 }
 
-/* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":91
- *         return hypergraph.Intersect(lat.lattice[0], self.hg)
+/* "/Users/vchahun/Sandbox/cdec/python/src/grammar.pxi":37
  * 
- *     def prune(self, beam_alpha=0, density=0, **kwargs):             # <<<<<<<<<<<<<<
- *         cdef hypergraph.EdgeMask* preserve_mask = NULL
- *         if 'csplit_preserve_full_word' in kwargs:
+ *     property f:
+ *         def __get__(self):             # <<<<<<<<<<<<<<
+ *             cdef vector[WordID]* f_ = &self.rule.get().f_
+ *             cdef WordID w
  */
 
-static PyObject *__pyx_pf_5_cdec_10Hypergraph_24prune(struct __pyx_obj_5_cdec_Hypergraph *__pyx_v_self, PyObject *__pyx_v_beam_alpha, PyObject *__pyx_v_density, PyObject *__pyx_v_kwargs) {
-  std::vector<bool> *__pyx_v_preserve_mask;
+static PyObject *__pyx_pf_5_cdec_9BaseTRule_1f___get__(struct __pyx_obj_5_cdec_BaseTRule *__pyx_v_self) {
+  std::vector<WordID> *__pyx_v_f_;
+  WordID __pyx_v_w;
+  PyObject *__pyx_v_f = 0;
+  unsigned int __pyx_v_i;
+  int __pyx_v_idx;
   PyObject *__pyx_r = NULL;
   __Pyx_RefNannyDeclarations
-  int __pyx_t_1;
-  double __pyx_t_2;
-  double __pyx_t_3;
+  PyObject *__pyx_t_1 = NULL;
+  size_t __pyx_t_2;
+  unsigned int __pyx_t_3;
+  int __pyx_t_4;
+  PyObject *__pyx_t_5 = NULL;
+  PyObject *__pyx_t_6 = NULL;
   int __pyx_lineno = 0;
   const char *__pyx_filename = NULL;
   int __pyx_clineno = 0;
-  __Pyx_RefNannySetupContext("prune", 0);
+  __Pyx_RefNannySetupContext("__get__", 0);
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":92
- * 
- *     def prune(self, beam_alpha=0, density=0, **kwargs):
- *         cdef hypergraph.EdgeMask* preserve_mask = NULL             # <<<<<<<<<<<<<<
- *         if 'csplit_preserve_full_word' in kwargs:
- *              preserve_mask = new hypergraph.EdgeMask(self.hg.edges_.size())
+  /* "/Users/vchahun/Sandbox/cdec/python/src/grammar.pxi":38
+ *     property f:
+ *         def __get__(self):
+ *             cdef vector[WordID]* f_ = &self.rule.get().f_             # <<<<<<<<<<<<<<
+ *             cdef WordID w
+ *             cdef f = []
  */
-  __pyx_v_preserve_mask = NULL;
+  __pyx_v_f_ = (&__pyx_v_self->rule->get()->f_);
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":93
- *     def prune(self, beam_alpha=0, density=0, **kwargs):
- *         cdef hypergraph.EdgeMask* preserve_mask = NULL
- *         if 'csplit_preserve_full_word' in kwargs:             # <<<<<<<<<<<<<<
- *              preserve_mask = new hypergraph.EdgeMask(self.hg.edges_.size())
- *              preserve_mask[0][hypergraph.GetFullWordEdgeIndex(self.hg[0])] = True
+  /* "/Users/vchahun/Sandbox/cdec/python/src/grammar.pxi":40
+ *             cdef vector[WordID]* f_ = &self.rule.get().f_
+ *             cdef WordID w
+ *             cdef f = []             # <<<<<<<<<<<<<<
+ *             cdef unsigned i
+ *             cdef int idx = 0
  */
-  __pyx_t_1 = ((PyDict_Contains(((PyObject *)__pyx_v_kwargs), ((PyObject *)__pyx_n_s_6)))); if (unlikely(__pyx_t_1 < 0)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 93; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  if (__pyx_t_1) {
+  __pyx_t_1 = PyList_New(0); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 40; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_1);
+  __pyx_v_f = ((PyObject *)__pyx_t_1);
+  __pyx_t_1 = 0;
 
-    /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":94
- *         cdef hypergraph.EdgeMask* preserve_mask = NULL
- *         if 'csplit_preserve_full_word' in kwargs:
- *              preserve_mask = new hypergraph.EdgeMask(self.hg.edges_.size())             # <<<<<<<<<<<<<<
- *              preserve_mask[0][hypergraph.GetFullWordEdgeIndex(self.hg[0])] = True
- *         self.hg.PruneInsideOutside(beam_alpha, density, preserve_mask, False, 1, False)
+  /* "/Users/vchahun/Sandbox/cdec/python/src/grammar.pxi":42
+ *             cdef f = []
+ *             cdef unsigned i
+ *             cdef int idx = 0             # <<<<<<<<<<<<<<
+ *             for i in range(f_.size()):
+ *                 w = f_[0][i]
  */
-    __pyx_v_preserve_mask = new std::vector<bool>(__pyx_v_self->hg->edges_.size());
+  __pyx_v_idx = 0;
 
-    /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":95
- *         if 'csplit_preserve_full_word' in kwargs:
- *              preserve_mask = new hypergraph.EdgeMask(self.hg.edges_.size())
- *              preserve_mask[0][hypergraph.GetFullWordEdgeIndex(self.hg[0])] = True             # <<<<<<<<<<<<<<
- *         self.hg.PruneInsideOutside(beam_alpha, density, preserve_mask, False, 1, False)
- *         if preserve_mask:
+  /* "/Users/vchahun/Sandbox/cdec/python/src/grammar.pxi":43
+ *             cdef unsigned i
+ *             cdef int idx = 0
+ *             for i in range(f_.size()):             # <<<<<<<<<<<<<<
+ *                 w = f_[0][i]
+ *                 if w < 0:
  */
-    ((__pyx_v_preserve_mask[0])[CompoundSplit::GetFullWordEdgeIndex((__pyx_v_self->hg[0]))]) = 1;
-    goto __pyx_L3;
-  }
-  __pyx_L3:;
+  __pyx_t_2 = __pyx_v_f_->size();
+  for (__pyx_t_3 = 0; __pyx_t_3 < __pyx_t_2; __pyx_t_3+=1) {
+    __pyx_v_i = __pyx_t_3;
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":96
- *              preserve_mask = new hypergraph.EdgeMask(self.hg.edges_.size())
- *              preserve_mask[0][hypergraph.GetFullWordEdgeIndex(self.hg[0])] = True
- *         self.hg.PruneInsideOutside(beam_alpha, density, preserve_mask, False, 1, False)             # <<<<<<<<<<<<<<
- *         if preserve_mask:
- *             del preserve_mask
+    /* "/Users/vchahun/Sandbox/cdec/python/src/grammar.pxi":44
+ *             cdef int idx = 0
+ *             for i in range(f_.size()):
+ *                 w = f_[0][i]             # <<<<<<<<<<<<<<
+ *                 if w < 0:
+ *                     idx += 1
  */
-  __pyx_t_2 = __pyx_PyFloat_AsDouble(__pyx_v_beam_alpha); if (unlikely((__pyx_t_2 == (double)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 96; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __pyx_t_3 = __pyx_PyFloat_AsDouble(__pyx_v_density); if (unlikely((__pyx_t_3 == (double)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 96; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __pyx_v_self->hg->PruneInsideOutside(__pyx_t_2, __pyx_t_3, __pyx_v_preserve_mask, 0, 1.0, 0);
+    __pyx_v_w = ((__pyx_v_f_[0])[__pyx_v_i]);
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":97
- *              preserve_mask[0][hypergraph.GetFullWordEdgeIndex(self.hg[0])] = True
- *         self.hg.PruneInsideOutside(beam_alpha, density, preserve_mask, False, 1, False)
- *         if preserve_mask:             # <<<<<<<<<<<<<<
- *             del preserve_mask
- * 
+    /* "/Users/vchahun/Sandbox/cdec/python/src/grammar.pxi":45
+ *             for i in range(f_.size()):
+ *                 w = f_[0][i]
+ *                 if w < 0:             # <<<<<<<<<<<<<<
+ *                     idx += 1
+ *                     f.append(NT(TDConvert(-w), idx))
  */
-  __pyx_t_1 = (__pyx_v_preserve_mask != 0);
-  if (__pyx_t_1) {
+    __pyx_t_4 = (__pyx_v_w < 0);
+    if (__pyx_t_4) {
 
-    /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":98
- *         self.hg.PruneInsideOutside(beam_alpha, density, preserve_mask, False, 1, False)
- *         if preserve_mask:
- *             del preserve_mask             # <<<<<<<<<<<<<<
+      /* "/Users/vchahun/Sandbox/cdec/python/src/grammar.pxi":46
+ *                 w = f_[0][i]
+ *                 if w < 0:
+ *                     idx += 1             # <<<<<<<<<<<<<<
+ *                     f.append(NT(TDConvert(-w), idx))
+ *                 else:
+ */
+      __pyx_v_idx = (__pyx_v_idx + 1);
+
+      /* "/Users/vchahun/Sandbox/cdec/python/src/grammar.pxi":47
+ *                 if w < 0:
+ *                     idx += 1
+ *                     f.append(NT(TDConvert(-w), idx))             # <<<<<<<<<<<<<<
+ *                 else:
+ *                     f.append(unicode(TDConvert(w), encoding='utf8'))
+ */
+      __pyx_t_1 = PyBytes_FromString(TD::Convert((-__pyx_v_w))); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 47; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __Pyx_GOTREF(((PyObject *)__pyx_t_1));
+      __pyx_t_5 = PyInt_FromLong(__pyx_v_idx); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 47; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __Pyx_GOTREF(__pyx_t_5);
+      __pyx_t_6 = PyTuple_New(2); if (unlikely(!__pyx_t_6)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 47; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __Pyx_GOTREF(__pyx_t_6);
+      PyTuple_SET_ITEM(__pyx_t_6, 0, ((PyObject *)__pyx_t_1));
+      __Pyx_GIVEREF(((PyObject *)__pyx_t_1));
+      PyTuple_SET_ITEM(__pyx_t_6, 1, __pyx_t_5);
+      __Pyx_GIVEREF(__pyx_t_5);
+      __pyx_t_1 = 0;
+      __pyx_t_5 = 0;
+      __pyx_t_5 = PyObject_Call(((PyObject *)((PyObject*)__pyx_ptype_5_cdec_NT)), ((PyObject *)__pyx_t_6), NULL); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 47; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __Pyx_GOTREF(__pyx_t_5);
+      __Pyx_DECREF(((PyObject *)__pyx_t_6)); __pyx_t_6 = 0;
+      __pyx_t_6 = __Pyx_PyObject_Append(__pyx_v_f, __pyx_t_5); if (unlikely(!__pyx_t_6)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 47; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __Pyx_GOTREF(__pyx_t_6);
+      __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
+      __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0;
+      goto __pyx_L5;
+    }
+    /*else*/ {
+
+      /* "/Users/vchahun/Sandbox/cdec/python/src/grammar.pxi":49
+ *                     f.append(NT(TDConvert(-w), idx))
+ *                 else:
+ *                     f.append(unicode(TDConvert(w), encoding='utf8'))             # <<<<<<<<<<<<<<
+ *             return f
  * 
- *     def lattice(self): # TODO direct hg -> lattice conversion in cdec
  */
-    delete __pyx_v_preserve_mask;
-    goto __pyx_L4;
+      __pyx_t_6 = PyBytes_FromString(TD::Convert(__pyx_v_w)); if (unlikely(!__pyx_t_6)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 49; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __Pyx_GOTREF(((PyObject *)__pyx_t_6));
+      __pyx_t_5 = PyTuple_New(1); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 49; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __Pyx_GOTREF(__pyx_t_5);
+      PyTuple_SET_ITEM(__pyx_t_5, 0, ((PyObject *)__pyx_t_6));
+      __Pyx_GIVEREF(((PyObject *)__pyx_t_6));
+      __pyx_t_6 = 0;
+      __pyx_t_6 = PyDict_New(); if (unlikely(!__pyx_t_6)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 49; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __Pyx_GOTREF(((PyObject *)__pyx_t_6));
+      if (PyDict_SetItem(__pyx_t_6, ((PyObject *)__pyx_n_s__encoding), ((PyObject *)__pyx_n_s__utf8)) < 0) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 49; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __pyx_t_1 = PyObject_Call(((PyObject *)((PyObject*)(&PyUnicode_Type))), ((PyObject *)__pyx_t_5), ((PyObject *)__pyx_t_6)); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 49; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __Pyx_GOTREF(__pyx_t_1);
+      __Pyx_DECREF(((PyObject *)__pyx_t_5)); __pyx_t_5 = 0;
+      __Pyx_DECREF(((PyObject *)__pyx_t_6)); __pyx_t_6 = 0;
+      __pyx_t_6 = __Pyx_PyObject_Append(__pyx_v_f, __pyx_t_1); if (unlikely(!__pyx_t_6)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 49; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __Pyx_GOTREF(__pyx_t_6);
+      __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+      __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0;
+    }
+    __pyx_L5:;
   }
-  __pyx_L4:;
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/grammar.pxi":50
+ *                 else:
+ *                     f.append(unicode(TDConvert(w), encoding='utf8'))
+ *             return f             # <<<<<<<<<<<<<<
+ * 
+ *         def __set__(self, f):
+ */
+  __Pyx_XDECREF(__pyx_r);
+  __Pyx_INCREF(__pyx_v_f);
+  __pyx_r = __pyx_v_f;
+  goto __pyx_L0;
 
   __pyx_r = Py_None; __Pyx_INCREF(Py_None);
   goto __pyx_L0;
   __pyx_L1_error:;
-  __Pyx_AddTraceback("_cdec.Hypergraph.prune", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __Pyx_XDECREF(__pyx_t_1);
+  __Pyx_XDECREF(__pyx_t_5);
+  __Pyx_XDECREF(__pyx_t_6);
+  __Pyx_AddTraceback("_cdec.BaseTRule.f.__get__", __pyx_clineno, __pyx_lineno, __pyx_filename);
   __pyx_r = NULL;
   __pyx_L0:;
+  __Pyx_XDECREF(__pyx_v_f);
   __Pyx_XGIVEREF(__pyx_r);
   __Pyx_RefNannyFinishContext();
   return __pyx_r;
 }
 
 /* Python wrapper */
-static PyObject *__pyx_pw_5_cdec_10Hypergraph_27lattice(PyObject *__pyx_v_self, CYTHON_UNUSED PyObject *unused); /*proto*/
-static PyObject *__pyx_pw_5_cdec_10Hypergraph_27lattice(PyObject *__pyx_v_self, CYTHON_UNUSED PyObject *unused) {
-  PyObject *__pyx_r = 0;
+static int __pyx_pw_5_cdec_9BaseTRule_1f_3__set__(PyObject *__pyx_v_self, PyObject *__pyx_v_f); /*proto*/
+static int __pyx_pw_5_cdec_9BaseTRule_1f_3__set__(PyObject *__pyx_v_self, PyObject *__pyx_v_f) {
+  int __pyx_r;
   __Pyx_RefNannyDeclarations
-  __Pyx_RefNannySetupContext("lattice (wrapper)", 0);
-  __pyx_r = __pyx_pf_5_cdec_10Hypergraph_26lattice(((struct __pyx_obj_5_cdec_Hypergraph *)__pyx_v_self));
+  __Pyx_RefNannySetupContext("__set__ (wrapper)", 0);
+  __pyx_r = __pyx_pf_5_cdec_9BaseTRule_1f_2__set__(((struct __pyx_obj_5_cdec_BaseTRule *)__pyx_v_self), ((PyObject *)__pyx_v_f));
   __Pyx_RefNannyFinishContext();
   return __pyx_r;
 }
 
-/* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":100
- *             del preserve_mask
+/* "/Users/vchahun/Sandbox/cdec/python/src/grammar.pxi":52
+ *             return f
  * 
- *     def lattice(self): # TODO direct hg -> lattice conversion in cdec             # <<<<<<<<<<<<<<
- *         cdef str plf = hypergraph.AsPLF(self.hg[0], True).c_str()
- *         return Lattice(eval(plf))
+ *         def __set__(self, f):             # <<<<<<<<<<<<<<
+ *             cdef vector[WordID]* f_ = &self.rule.get().f_
+ *             f_.resize(len(f))
  */
 
-static PyObject *__pyx_pf_5_cdec_10Hypergraph_26lattice(struct __pyx_obj_5_cdec_Hypergraph *__pyx_v_self) {
-  PyObject *__pyx_v_plf = 0;
-  PyObject *__pyx_r = NULL;
+static int __pyx_pf_5_cdec_9BaseTRule_1f_2__set__(struct __pyx_obj_5_cdec_BaseTRule *__pyx_v_self, PyObject *__pyx_v_f) {
+  std::vector<WordID> *__pyx_v_f_;
+  unsigned int __pyx_v_i;
+  CYTHON_UNUSED int __pyx_v_idx;
+  int __pyx_r;
   __Pyx_RefNannyDeclarations
-  PyObject *__pyx_t_1 = NULL;
-  PyObject *__pyx_t_2 = NULL;
+  Py_ssize_t __pyx_t_1;
+  unsigned int __pyx_t_2;
   PyObject *__pyx_t_3 = NULL;
+  PyObject *__pyx_t_4 = NULL;
+  int __pyx_t_5;
+  char *__pyx_t_6;
   int __pyx_lineno = 0;
   const char *__pyx_filename = NULL;
   int __pyx_clineno = 0;
-  __Pyx_RefNannySetupContext("lattice", 0);
+  __Pyx_RefNannySetupContext("__set__", 0);
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":101
- * 
- *     def lattice(self): # TODO direct hg -> lattice conversion in cdec
- *         cdef str plf = hypergraph.AsPLF(self.hg[0], True).c_str()             # <<<<<<<<<<<<<<
- *         return Lattice(eval(plf))
+  /* "/Users/vchahun/Sandbox/cdec/python/src/grammar.pxi":53
  * 
+ *         def __set__(self, f):
+ *             cdef vector[WordID]* f_ = &self.rule.get().f_             # <<<<<<<<<<<<<<
+ *             f_.resize(len(f))
+ *             cdef unsigned i
  */
-  __pyx_t_1 = PyBytes_FromString(HypergraphIO::AsPLF((__pyx_v_self->hg[0]), 1).c_str()); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 101; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __Pyx_GOTREF(((PyObject *)__pyx_t_1));
-  if (!(likely(PyString_CheckExact(((PyObject *)__pyx_t_1)))||(PyErr_Format(PyExc_TypeError, "Expected str, got %.200s", Py_TYPE(((PyObject *)__pyx_t_1))->tp_name), 0))) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 101; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __pyx_v_plf = ((PyObject*)__pyx_t_1);
-  __pyx_t_1 = 0;
+  __pyx_v_f_ = (&__pyx_v_self->rule->get()->f_);
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":102
- *     def lattice(self): # TODO direct hg -> lattice conversion in cdec
- *         cdef str plf = hypergraph.AsPLF(self.hg[0], True).c_str()
- *         return Lattice(eval(plf))             # <<<<<<<<<<<<<<
+  /* "/Users/vchahun/Sandbox/cdec/python/src/grammar.pxi":54
+ *         def __set__(self, f):
+ *             cdef vector[WordID]* f_ = &self.rule.get().f_
+ *             f_.resize(len(f))             # <<<<<<<<<<<<<<
+ *             cdef unsigned i
+ *             cdef int idx = 0
+ */
+  __pyx_t_1 = PyObject_Length(__pyx_v_f); if (unlikely(__pyx_t_1 == -1)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 54; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_v_f_->resize(__pyx_t_1);
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/grammar.pxi":56
+ *             f_.resize(len(f))
+ *             cdef unsigned i
+ *             cdef int idx = 0             # <<<<<<<<<<<<<<
+ *             for i in range(len(f)):
+ *                 if isinstance(f[i], NT):
+ */
+  __pyx_v_idx = 0;
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/grammar.pxi":57
+ *             cdef unsigned i
+ *             cdef int idx = 0
+ *             for i in range(len(f)):             # <<<<<<<<<<<<<<
+ *                 if isinstance(f[i], NT):
+ *                     f_[0][i] = -TDConvert(<char *>f[i].cat)
+ */
+  __pyx_t_1 = PyObject_Length(__pyx_v_f); if (unlikely(__pyx_t_1 == -1)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 57; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  for (__pyx_t_2 = 0; __pyx_t_2 < __pyx_t_1; __pyx_t_2+=1) {
+    __pyx_v_i = __pyx_t_2;
+
+    /* "/Users/vchahun/Sandbox/cdec/python/src/grammar.pxi":58
+ *             cdef int idx = 0
+ *             for i in range(len(f)):
+ *                 if isinstance(f[i], NT):             # <<<<<<<<<<<<<<
+ *                     f_[0][i] = -TDConvert(<char *>f[i].cat)
+ *                 else:
+ */
+    __pyx_t_3 = __Pyx_GetItemInt(__pyx_v_f, __pyx_v_i, sizeof(unsigned int)+1, PyLong_FromUnsignedLong); if (!__pyx_t_3) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 58; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_3);
+    __pyx_t_4 = ((PyObject *)((PyObject*)__pyx_ptype_5_cdec_NT));
+    __Pyx_INCREF(__pyx_t_4);
+    __pyx_t_5 = __Pyx_TypeCheck(__pyx_t_3, __pyx_t_4); 
+    __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
+    __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
+    if (__pyx_t_5) {
+
+      /* "/Users/vchahun/Sandbox/cdec/python/src/grammar.pxi":59
+ *             for i in range(len(f)):
+ *                 if isinstance(f[i], NT):
+ *                     f_[0][i] = -TDConvert(<char *>f[i].cat)             # <<<<<<<<<<<<<<
+ *                 else:
+ *                     f_[0][i] = TDConvert(<char *>as_str(f[i]))
+ */
+      __pyx_t_4 = __Pyx_GetItemInt(__pyx_v_f, __pyx_v_i, sizeof(unsigned int)+1, PyLong_FromUnsignedLong); if (!__pyx_t_4) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 59; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __Pyx_GOTREF(__pyx_t_4);
+      __pyx_t_3 = PyObject_GetAttr(__pyx_t_4, __pyx_n_s__cat); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 59; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __Pyx_GOTREF(__pyx_t_3);
+      __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
+      __pyx_t_6 = PyBytes_AsString(__pyx_t_3); if (unlikely((!__pyx_t_6) && PyErr_Occurred())) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 59; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
+      ((__pyx_v_f_[0])[__pyx_v_i]) = (-TD::Convert(((char *)__pyx_t_6)));
+      goto __pyx_L5;
+    }
+    /*else*/ {
+
+      /* "/Users/vchahun/Sandbox/cdec/python/src/grammar.pxi":61
+ *                     f_[0][i] = -TDConvert(<char *>f[i].cat)
+ *                 else:
+ *                     f_[0][i] = TDConvert(<char *>as_str(f[i]))             # <<<<<<<<<<<<<<
  * 
- *     def reweight(self, weights):
+ *     property e:
  */
-  __Pyx_XDECREF(__pyx_r);
-  __pyx_t_1 = __Pyx_Globals(); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 102; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __Pyx_GOTREF(__pyx_t_1);
-  __pyx_t_2 = PyDict_New(); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 102; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __Pyx_GOTREF(((PyObject *)__pyx_t_2));
-  if (((PyObject *)__pyx_v_plf)) {
-    if (PyDict_SetItem(__pyx_t_2, ((PyObject *)__pyx_n_s__plf), ((PyObject *)__pyx_v_plf)) < 0) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 102; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  }
-  if (((PyObject *)__pyx_v_self)) {
-    if (PyDict_SetItem(__pyx_t_2, ((PyObject *)__pyx_n_s__self), ((PyObject *)__pyx_v_self)) < 0) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 102; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __pyx_t_3 = __Pyx_GetItemInt(__pyx_v_f, __pyx_v_i, sizeof(unsigned int)+1, PyLong_FromUnsignedLong); if (!__pyx_t_3) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 61; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __Pyx_GOTREF(__pyx_t_3);
+      ((__pyx_v_f_[0])[__pyx_v_i]) = TD::Convert(((char *)__pyx_f_5_cdec_as_str(__pyx_t_3, NULL)));
+      __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
+    }
+    __pyx_L5:;
   }
-  __pyx_t_3 = PyTuple_New(3); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 102; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __Pyx_GOTREF(__pyx_t_3);
-  __Pyx_INCREF(((PyObject *)__pyx_v_plf));
-  PyTuple_SET_ITEM(__pyx_t_3, 0, ((PyObject *)__pyx_v_plf));
-  __Pyx_GIVEREF(((PyObject *)__pyx_v_plf));
-  PyTuple_SET_ITEM(__pyx_t_3, 1, ((PyObject *)__pyx_t_1));
-  __Pyx_GIVEREF(((PyObject *)__pyx_t_1));
-  PyTuple_SET_ITEM(__pyx_t_3, 2, ((PyObject *)__pyx_t_2));
-  __Pyx_GIVEREF(((PyObject *)__pyx_t_2));
-  __pyx_t_1 = 0;
-  __pyx_t_2 = 0;
-  __pyx_t_2 = PyObject_Call(__pyx_builtin_eval, ((PyObject *)__pyx_t_3), NULL); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 102; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __Pyx_GOTREF(__pyx_t_2);
-  __Pyx_DECREF(((PyObject *)__pyx_t_3)); __pyx_t_3 = 0;
-  __pyx_t_3 = PyTuple_New(1); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 102; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __Pyx_GOTREF(__pyx_t_3);
-  PyTuple_SET_ITEM(__pyx_t_3, 0, __pyx_t_2);
-  __Pyx_GIVEREF(__pyx_t_2);
-  __pyx_t_2 = 0;
-  __pyx_t_2 = PyObject_Call(((PyObject *)((PyObject*)__pyx_ptype_5_cdec_Lattice)), ((PyObject *)__pyx_t_3), NULL); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 102; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __Pyx_GOTREF(__pyx_t_2);
-  __Pyx_DECREF(((PyObject *)__pyx_t_3)); __pyx_t_3 = 0;
-  __pyx_r = __pyx_t_2;
-  __pyx_t_2 = 0;
-  goto __pyx_L0;
 
-  __pyx_r = Py_None; __Pyx_INCREF(Py_None);
+  __pyx_r = 0;
   goto __pyx_L0;
   __pyx_L1_error:;
-  __Pyx_XDECREF(__pyx_t_1);
-  __Pyx_XDECREF(__pyx_t_2);
   __Pyx_XDECREF(__pyx_t_3);
-  __Pyx_AddTraceback("_cdec.Hypergraph.lattice", __pyx_clineno, __pyx_lineno, __pyx_filename);
-  __pyx_r = NULL;
+  __Pyx_XDECREF(__pyx_t_4);
+  __Pyx_AddTraceback("_cdec.BaseTRule.f.__set__", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __pyx_r = -1;
   __pyx_L0:;
-  __Pyx_XDECREF(__pyx_v_plf);
-  __Pyx_XGIVEREF(__pyx_r);
   __Pyx_RefNannyFinishContext();
   return __pyx_r;
 }
 
 /* Python wrapper */
-static PyObject *__pyx_pw_5_cdec_10Hypergraph_29reweight(PyObject *__pyx_v_self, PyObject *__pyx_v_weights); /*proto*/
-static PyObject *__pyx_pw_5_cdec_10Hypergraph_29reweight(PyObject *__pyx_v_self, PyObject *__pyx_v_weights) {
+static PyObject *__pyx_pw_5_cdec_9BaseTRule_1e_1__get__(PyObject *__pyx_v_self); /*proto*/
+static PyObject *__pyx_pw_5_cdec_9BaseTRule_1e_1__get__(PyObject *__pyx_v_self) {
   PyObject *__pyx_r = 0;
   __Pyx_RefNannyDeclarations
-  __Pyx_RefNannySetupContext("reweight (wrapper)", 0);
-  __pyx_r = __pyx_pf_5_cdec_10Hypergraph_28reweight(((struct __pyx_obj_5_cdec_Hypergraph *)__pyx_v_self), ((PyObject *)__pyx_v_weights));
+  __Pyx_RefNannySetupContext("__get__ (wrapper)", 0);
+  __pyx_r = __pyx_pf_5_cdec_9BaseTRule_1e___get__(((struct __pyx_obj_5_cdec_BaseTRule *)__pyx_v_self));
   __Pyx_RefNannyFinishContext();
   return __pyx_r;
 }
 
-/* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":104
- *         return Lattice(eval(plf))
+/* "/Users/vchahun/Sandbox/cdec/python/src/grammar.pxi":64
  * 
- *     def reweight(self, weights):             # <<<<<<<<<<<<<<
- *         if isinstance(weights, SparseVector):
- *             self.hg.Reweight((<SparseVector> weights).vector[0])
+ *     property e:
+ *         def __get__(self):             # <<<<<<<<<<<<<<
+ *             cdef vector[WordID]* e_ = &self.rule.get().e_
+ *             cdef WordID w
  */
 
-static PyObject *__pyx_pf_5_cdec_10Hypergraph_28reweight(struct __pyx_obj_5_cdec_Hypergraph *__pyx_v_self, PyObject *__pyx_v_weights) {
+static PyObject *__pyx_pf_5_cdec_9BaseTRule_1e___get__(struct __pyx_obj_5_cdec_BaseTRule *__pyx_v_self) {
+  std::vector<WordID> *__pyx_v_e_;
+  WordID __pyx_v_w;
+  PyObject *__pyx_v_e = 0;
+  unsigned int __pyx_v_i;
+  int __pyx_v_idx;
   PyObject *__pyx_r = NULL;
   __Pyx_RefNannyDeclarations
   PyObject *__pyx_t_1 = NULL;
-  int __pyx_t_2;
-  PyObject *__pyx_t_3 = NULL;
+  size_t __pyx_t_2;
+  unsigned int __pyx_t_3;
+  int __pyx_t_4;
+  PyObject *__pyx_t_5 = NULL;
+  PyObject *__pyx_t_6 = NULL;
   int __pyx_lineno = 0;
   const char *__pyx_filename = NULL;
   int __pyx_clineno = 0;
-  __Pyx_RefNannySetupContext("reweight", 0);
+  __Pyx_RefNannySetupContext("__get__", 0);
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":105
- * 
- *     def reweight(self, weights):
- *         if isinstance(weights, SparseVector):             # <<<<<<<<<<<<<<
- *             self.hg.Reweight((<SparseVector> weights).vector[0])
- *         elif isinstance(weights, DenseVector):
+  /* "/Users/vchahun/Sandbox/cdec/python/src/grammar.pxi":65
+ *     property e:
+ *         def __get__(self):
+ *             cdef vector[WordID]* e_ = &self.rule.get().e_             # <<<<<<<<<<<<<<
+ *             cdef WordID w
+ *             cdef e = []
  */
-  __pyx_t_1 = ((PyObject *)((PyObject*)__pyx_ptype_5_cdec_SparseVector));
-  __Pyx_INCREF(__pyx_t_1);
-  __pyx_t_2 = __Pyx_TypeCheck(__pyx_v_weights, __pyx_t_1); 
-  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
-  if (__pyx_t_2) {
+  __pyx_v_e_ = (&__pyx_v_self->rule->get()->e_);
 
-    /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":106
- *     def reweight(self, weights):
- *         if isinstance(weights, SparseVector):
- *             self.hg.Reweight((<SparseVector> weights).vector[0])             # <<<<<<<<<<<<<<
- *         elif isinstance(weights, DenseVector):
- *             self.hg.Reweight((<DenseVector> weights).vector[0])
+  /* "/Users/vchahun/Sandbox/cdec/python/src/grammar.pxi":67
+ *             cdef vector[WordID]* e_ = &self.rule.get().e_
+ *             cdef WordID w
+ *             cdef e = []             # <<<<<<<<<<<<<<
+ *             cdef unsigned i
+ *             cdef int idx = 0
  */
-    __pyx_v_self->hg->Reweight((((struct __pyx_obj_5_cdec_SparseVector *)__pyx_v_weights)->vector[0]));
-    goto __pyx_L3;
-  }
+  __pyx_t_1 = PyList_New(0); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 67; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_1);
+  __pyx_v_e = ((PyObject *)__pyx_t_1);
+  __pyx_t_1 = 0;
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":107
- *         if isinstance(weights, SparseVector):
- *             self.hg.Reweight((<SparseVector> weights).vector[0])
- *         elif isinstance(weights, DenseVector):             # <<<<<<<<<<<<<<
- *             self.hg.Reweight((<DenseVector> weights).vector[0])
- *         else:
+  /* "/Users/vchahun/Sandbox/cdec/python/src/grammar.pxi":69
+ *             cdef e = []
+ *             cdef unsigned i
+ *             cdef int idx = 0             # <<<<<<<<<<<<<<
+ *             for i in range(e_.size()):
+ *                 w = e_[0][i]
  */
-  __pyx_t_1 = ((PyObject *)((PyObject*)__pyx_ptype_5_cdec_DenseVector));
-  __Pyx_INCREF(__pyx_t_1);
-  __pyx_t_2 = __Pyx_TypeCheck(__pyx_v_weights, __pyx_t_1); 
-  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
-  if (__pyx_t_2) {
+  __pyx_v_idx = 0;
 
-    /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":108
- *             self.hg.Reweight((<SparseVector> weights).vector[0])
- *         elif isinstance(weights, DenseVector):
- *             self.hg.Reweight((<DenseVector> weights).vector[0])             # <<<<<<<<<<<<<<
- *         else:
- *             raise TypeError('cannot reweight hypergraph with %s' % type(weights))
+  /* "/Users/vchahun/Sandbox/cdec/python/src/grammar.pxi":70
+ *             cdef unsigned i
+ *             cdef int idx = 0
+ *             for i in range(e_.size()):             # <<<<<<<<<<<<<<
+ *                 w = e_[0][i]
+ *                 if w < 1:
  */
-    __pyx_v_self->hg->Reweight((((struct __pyx_obj_5_cdec_DenseVector *)__pyx_v_weights)->vector[0]));
-    goto __pyx_L3;
-  }
-  /*else*/ {
+  __pyx_t_2 = __pyx_v_e_->size();
+  for (__pyx_t_3 = 0; __pyx_t_3 < __pyx_t_2; __pyx_t_3+=1) {
+    __pyx_v_i = __pyx_t_3;
 
-    /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":110
- *             self.hg.Reweight((<DenseVector> weights).vector[0])
- *         else:
- *             raise TypeError('cannot reweight hypergraph with %s' % type(weights))             # <<<<<<<<<<<<<<
+    /* "/Users/vchahun/Sandbox/cdec/python/src/grammar.pxi":71
+ *             cdef int idx = 0
+ *             for i in range(e_.size()):
+ *                 w = e_[0][i]             # <<<<<<<<<<<<<<
+ *                 if w < 1:
+ *                     idx += 1
+ */
+    __pyx_v_w = ((__pyx_v_e_[0])[__pyx_v_i]);
+
+    /* "/Users/vchahun/Sandbox/cdec/python/src/grammar.pxi":72
+ *             for i in range(e_.size()):
+ *                 w = e_[0][i]
+ *                 if w < 1:             # <<<<<<<<<<<<<<
+ *                     idx += 1
+ *                     e.append(NTRef(1-w))
+ */
+    __pyx_t_4 = (__pyx_v_w < 1);
+    if (__pyx_t_4) {
+
+      /* "/Users/vchahun/Sandbox/cdec/python/src/grammar.pxi":73
+ *                 w = e_[0][i]
+ *                 if w < 1:
+ *                     idx += 1             # <<<<<<<<<<<<<<
+ *                     e.append(NTRef(1-w))
+ *                 else:
+ */
+      __pyx_v_idx = (__pyx_v_idx + 1);
+
+      /* "/Users/vchahun/Sandbox/cdec/python/src/grammar.pxi":74
+ *                 if w < 1:
+ *                     idx += 1
+ *                     e.append(NTRef(1-w))             # <<<<<<<<<<<<<<
+ *                 else:
+ *                     e.append(unicode(TDConvert(w), encoding='utf8'))
+ */
+      __pyx_t_1 = PyInt_FromLong((1 - __pyx_v_w)); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 74; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __Pyx_GOTREF(__pyx_t_1);
+      __pyx_t_5 = PyTuple_New(1); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 74; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __Pyx_GOTREF(__pyx_t_5);
+      PyTuple_SET_ITEM(__pyx_t_5, 0, __pyx_t_1);
+      __Pyx_GIVEREF(__pyx_t_1);
+      __pyx_t_1 = 0;
+      __pyx_t_1 = PyObject_Call(((PyObject *)((PyObject*)__pyx_ptype_5_cdec_NTRef)), ((PyObject *)__pyx_t_5), NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 74; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __Pyx_GOTREF(__pyx_t_1);
+      __Pyx_DECREF(((PyObject *)__pyx_t_5)); __pyx_t_5 = 0;
+      __pyx_t_5 = __Pyx_PyObject_Append(__pyx_v_e, __pyx_t_1); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 74; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __Pyx_GOTREF(__pyx_t_5);
+      __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+      __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
+      goto __pyx_L5;
+    }
+    /*else*/ {
+
+      /* "/Users/vchahun/Sandbox/cdec/python/src/grammar.pxi":76
+ *                     e.append(NTRef(1-w))
+ *                 else:
+ *                     e.append(unicode(TDConvert(w), encoding='utf8'))             # <<<<<<<<<<<<<<
+ *             return e
  * 
- *     # TODO get feature expectations, get partition function ("inside" score)
  */
-    __pyx_t_1 = PyNumber_Remainder(((PyObject *)__pyx_kp_s_7), ((PyObject *)Py_TYPE(__pyx_v_weights))); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 110; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-    __Pyx_GOTREF(((PyObject *)__pyx_t_1));
-    __pyx_t_3 = PyTuple_New(1); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 110; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-    __Pyx_GOTREF(__pyx_t_3);
-    PyTuple_SET_ITEM(__pyx_t_3, 0, ((PyObject *)__pyx_t_1));
-    __Pyx_GIVEREF(((PyObject *)__pyx_t_1));
-    __pyx_t_1 = 0;
-    __pyx_t_1 = PyObject_Call(__pyx_builtin_TypeError, ((PyObject *)__pyx_t_3), NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 110; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-    __Pyx_GOTREF(__pyx_t_1);
-    __Pyx_DECREF(((PyObject *)__pyx_t_3)); __pyx_t_3 = 0;
-    __Pyx_Raise(__pyx_t_1, 0, 0, 0);
-    __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
-    {__pyx_filename = __pyx_f[2]; __pyx_lineno = 110; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __pyx_t_5 = PyBytes_FromString(TD::Convert(__pyx_v_w)); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 76; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __Pyx_GOTREF(((PyObject *)__pyx_t_5));
+      __pyx_t_1 = PyTuple_New(1); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 76; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __Pyx_GOTREF(__pyx_t_1);
+      PyTuple_SET_ITEM(__pyx_t_1, 0, ((PyObject *)__pyx_t_5));
+      __Pyx_GIVEREF(((PyObject *)__pyx_t_5));
+      __pyx_t_5 = 0;
+      __pyx_t_5 = PyDict_New(); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 76; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __Pyx_GOTREF(((PyObject *)__pyx_t_5));
+      if (PyDict_SetItem(__pyx_t_5, ((PyObject *)__pyx_n_s__encoding), ((PyObject *)__pyx_n_s__utf8)) < 0) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 76; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __pyx_t_6 = PyObject_Call(((PyObject *)((PyObject*)(&PyUnicode_Type))), ((PyObject *)__pyx_t_1), ((PyObject *)__pyx_t_5)); if (unlikely(!__pyx_t_6)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 76; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __Pyx_GOTREF(__pyx_t_6);
+      __Pyx_DECREF(((PyObject *)__pyx_t_1)); __pyx_t_1 = 0;
+      __Pyx_DECREF(((PyObject *)__pyx_t_5)); __pyx_t_5 = 0;
+      __pyx_t_5 = __Pyx_PyObject_Append(__pyx_v_e, __pyx_t_6); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 76; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __Pyx_GOTREF(__pyx_t_5);
+      __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0;
+      __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
+    }
+    __pyx_L5:;
   }
-  __pyx_L3:;
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/grammar.pxi":77
+ *                 else:
+ *                     e.append(unicode(TDConvert(w), encoding='utf8'))
+ *             return e             # <<<<<<<<<<<<<<
+ * 
+ *         def __set__(self, e):
+ */
+  __Pyx_XDECREF(__pyx_r);
+  __Pyx_INCREF(__pyx_v_e);
+  __pyx_r = __pyx_v_e;
+  goto __pyx_L0;
 
   __pyx_r = Py_None; __Pyx_INCREF(Py_None);
   goto __pyx_L0;
   __pyx_L1_error:;
   __Pyx_XDECREF(__pyx_t_1);
-  __Pyx_XDECREF(__pyx_t_3);
-  __Pyx_AddTraceback("_cdec.Hypergraph.reweight", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __Pyx_XDECREF(__pyx_t_5);
+  __Pyx_XDECREF(__pyx_t_6);
+  __Pyx_AddTraceback("_cdec.BaseTRule.e.__get__", __pyx_clineno, __pyx_lineno, __pyx_filename);
   __pyx_r = NULL;
   __pyx_L0:;
+  __Pyx_XDECREF(__pyx_v_e);
   __Pyx_XGIVEREF(__pyx_r);
   __Pyx_RefNannyFinishContext();
   return __pyx_r;
 }
-static PyObject *__pyx_gb_5_cdec_10Hypergraph_5edges_2generator6(__pyx_GeneratorObject *__pyx_generator, PyObject *__pyx_sent_value); /* proto */
 
 /* Python wrapper */
-static PyObject *__pyx_pw_5_cdec_10Hypergraph_5edges_1__get__(PyObject *__pyx_v_self); /*proto*/
-static PyObject *__pyx_pw_5_cdec_10Hypergraph_5edges_1__get__(PyObject *__pyx_v_self) {
+static int __pyx_pw_5_cdec_9BaseTRule_1e_3__set__(PyObject *__pyx_v_self, PyObject *__pyx_v_e); /*proto*/
+static int __pyx_pw_5_cdec_9BaseTRule_1e_3__set__(PyObject *__pyx_v_self, PyObject *__pyx_v_e) {
+  int __pyx_r;
+  __Pyx_RefNannyDeclarations
+  __Pyx_RefNannySetupContext("__set__ (wrapper)", 0);
+  __pyx_r = __pyx_pf_5_cdec_9BaseTRule_1e_2__set__(((struct __pyx_obj_5_cdec_BaseTRule *)__pyx_v_self), ((PyObject *)__pyx_v_e));
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+/* "/Users/vchahun/Sandbox/cdec/python/src/grammar.pxi":79
+ *             return e
+ * 
+ *         def __set__(self, e):             # <<<<<<<<<<<<<<
+ *             cdef vector[WordID]* e_ = &self.rule.get().e_
+ *             e_.resize(len(e))
+ */
+
+static int __pyx_pf_5_cdec_9BaseTRule_1e_2__set__(struct __pyx_obj_5_cdec_BaseTRule *__pyx_v_self, PyObject *__pyx_v_e) {
+  std::vector<WordID> *__pyx_v_e_;
+  unsigned int __pyx_v_i;
+  int __pyx_r;
+  __Pyx_RefNannyDeclarations
+  Py_ssize_t __pyx_t_1;
+  unsigned int __pyx_t_2;
+  PyObject *__pyx_t_3 = NULL;
+  PyObject *__pyx_t_4 = NULL;
+  int __pyx_t_5;
+  WordID __pyx_t_6;
+  int __pyx_lineno = 0;
+  const char *__pyx_filename = NULL;
+  int __pyx_clineno = 0;
+  __Pyx_RefNannySetupContext("__set__", 0);
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/grammar.pxi":80
+ * 
+ *         def __set__(self, e):
+ *             cdef vector[WordID]* e_ = &self.rule.get().e_             # <<<<<<<<<<<<<<
+ *             e_.resize(len(e))
+ *             cdef unsigned i
+ */
+  __pyx_v_e_ = (&__pyx_v_self->rule->get()->e_);
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/grammar.pxi":81
+ *         def __set__(self, e):
+ *             cdef vector[WordID]* e_ = &self.rule.get().e_
+ *             e_.resize(len(e))             # <<<<<<<<<<<<<<
+ *             cdef unsigned i
+ *             for i in range(len(e)):
+ */
+  __pyx_t_1 = PyObject_Length(__pyx_v_e); if (unlikely(__pyx_t_1 == -1)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 81; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_v_e_->resize(__pyx_t_1);
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/grammar.pxi":83
+ *             e_.resize(len(e))
+ *             cdef unsigned i
+ *             for i in range(len(e)):             # <<<<<<<<<<<<<<
+ *                 if isinstance(e[i], NTRef):
+ *                     e_[0][i] = 1-e[i].ref
+ */
+  __pyx_t_1 = PyObject_Length(__pyx_v_e); if (unlikely(__pyx_t_1 == -1)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 83; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  for (__pyx_t_2 = 0; __pyx_t_2 < __pyx_t_1; __pyx_t_2+=1) {
+    __pyx_v_i = __pyx_t_2;
+
+    /* "/Users/vchahun/Sandbox/cdec/python/src/grammar.pxi":84
+ *             cdef unsigned i
+ *             for i in range(len(e)):
+ *                 if isinstance(e[i], NTRef):             # <<<<<<<<<<<<<<
+ *                     e_[0][i] = 1-e[i].ref
+ *                 else:
+ */
+    __pyx_t_3 = __Pyx_GetItemInt(__pyx_v_e, __pyx_v_i, sizeof(unsigned int)+1, PyLong_FromUnsignedLong); if (!__pyx_t_3) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 84; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_3);
+    __pyx_t_4 = ((PyObject *)((PyObject*)__pyx_ptype_5_cdec_NTRef));
+    __Pyx_INCREF(__pyx_t_4);
+    __pyx_t_5 = __Pyx_TypeCheck(__pyx_t_3, __pyx_t_4); 
+    __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
+    __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
+    if (__pyx_t_5) {
+
+      /* "/Users/vchahun/Sandbox/cdec/python/src/grammar.pxi":85
+ *             for i in range(len(e)):
+ *                 if isinstance(e[i], NTRef):
+ *                     e_[0][i] = 1-e[i].ref             # <<<<<<<<<<<<<<
+ *                 else:
+ *                     e_[0][i] = TDConvert(<char *>as_str(e[i]))
+ */
+      __pyx_t_4 = __Pyx_GetItemInt(__pyx_v_e, __pyx_v_i, sizeof(unsigned int)+1, PyLong_FromUnsignedLong); if (!__pyx_t_4) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 85; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __Pyx_GOTREF(__pyx_t_4);
+      __pyx_t_3 = PyObject_GetAttr(__pyx_t_4, __pyx_n_s__ref); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 85; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __Pyx_GOTREF(__pyx_t_3);
+      __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
+      __pyx_t_4 = PyNumber_Subtract(__pyx_int_1, __pyx_t_3); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 85; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __Pyx_GOTREF(__pyx_t_4);
+      __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
+      __pyx_t_6 = __Pyx_PyInt_from_py_WordID(__pyx_t_4); if (unlikely((__pyx_t_6 == (WordID)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 85; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
+      ((__pyx_v_e_[0])[__pyx_v_i]) = __pyx_t_6;
+      goto __pyx_L5;
+    }
+    /*else*/ {
+
+      /* "/Users/vchahun/Sandbox/cdec/python/src/grammar.pxi":87
+ *                     e_[0][i] = 1-e[i].ref
+ *                 else:
+ *                     e_[0][i] = TDConvert(<char *>as_str(e[i]))             # <<<<<<<<<<<<<<
+ * 
+ *     property a:
+ */
+      __pyx_t_4 = __Pyx_GetItemInt(__pyx_v_e, __pyx_v_i, sizeof(unsigned int)+1, PyLong_FromUnsignedLong); if (!__pyx_t_4) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 87; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __Pyx_GOTREF(__pyx_t_4);
+      ((__pyx_v_e_[0])[__pyx_v_i]) = TD::Convert(((char *)__pyx_f_5_cdec_as_str(__pyx_t_4, NULL)));
+      __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
+    }
+    __pyx_L5:;
+  }
+
+  __pyx_r = 0;
+  goto __pyx_L0;
+  __pyx_L1_error:;
+  __Pyx_XDECREF(__pyx_t_3);
+  __Pyx_XDECREF(__pyx_t_4);
+  __Pyx_AddTraceback("_cdec.BaseTRule.e.__set__", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __pyx_r = -1;
+  __pyx_L0:;
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+static PyObject *__pyx_gb_5_cdec_9BaseTRule_1a_2generator2(__pyx_GeneratorObject *__pyx_generator, PyObject *__pyx_sent_value); /* proto */
+
+/* Python wrapper */
+static PyObject *__pyx_pw_5_cdec_9BaseTRule_1a_1__get__(PyObject *__pyx_v_self); /*proto*/
+static PyObject *__pyx_pw_5_cdec_9BaseTRule_1a_1__get__(PyObject *__pyx_v_self) {
   PyObject *__pyx_r = 0;
   __Pyx_RefNannyDeclarations
   __Pyx_RefNannySetupContext("__get__ (wrapper)", 0);
-  __pyx_r = __pyx_pf_5_cdec_10Hypergraph_5edges___get__(((struct __pyx_obj_5_cdec_Hypergraph *)__pyx_v_self));
+  __pyx_r = __pyx_pf_5_cdec_9BaseTRule_1a___get__(((struct __pyx_obj_5_cdec_BaseTRule *)__pyx_v_self));
   __Pyx_RefNannyFinishContext();
   return __pyx_r;
 }
 
-/* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":115
+/* "/Users/vchahun/Sandbox/cdec/python/src/grammar.pxi":90
  * 
- *     property edges:
+ *     property a:
  *         def __get__(self):             # <<<<<<<<<<<<<<
  *             cdef unsigned i
- *             for i in range(self.hg.edges_.size()):
+ *             cdef vector[grammar.AlignmentPoint]* a = &self.rule.get().a_
  */
 
-static PyObject *__pyx_pf_5_cdec_10Hypergraph_5edges___get__(struct __pyx_obj_5_cdec_Hypergraph *__pyx_v_self) {
-  struct __pyx_obj_5_cdec___pyx_scope_struct_6___get__ *__pyx_cur_scope;
+static PyObject *__pyx_pf_5_cdec_9BaseTRule_1a___get__(struct __pyx_obj_5_cdec_BaseTRule *__pyx_v_self) {
+  struct __pyx_obj_5_cdec___pyx_scope_struct_4___get__ *__pyx_cur_scope;
   PyObject *__pyx_r = NULL;
   __Pyx_RefNannyDeclarations
   int __pyx_lineno = 0;
   const char *__pyx_filename = NULL;
   int __pyx_clineno = 0;
   __Pyx_RefNannySetupContext("__get__", 0);
-  __pyx_cur_scope = (struct __pyx_obj_5_cdec___pyx_scope_struct_6___get__ *)__pyx_ptype_5_cdec___pyx_scope_struct_6___get__->tp_new(__pyx_ptype_5_cdec___pyx_scope_struct_6___get__, __pyx_empty_tuple, NULL);
+  __pyx_cur_scope = (struct __pyx_obj_5_cdec___pyx_scope_struct_4___get__ *)__pyx_ptype_5_cdec___pyx_scope_struct_4___get__->tp_new(__pyx_ptype_5_cdec___pyx_scope_struct_4___get__, __pyx_empty_tuple, NULL);
   if (unlikely(!__pyx_cur_scope)) {
     __Pyx_RefNannyFinishContext();
     return NULL;
@@ -5881,7 +5802,7 @@ static PyObject *__pyx_pf_5_cdec_10Hypergraph_5edges___get__(struct __pyx_obj_5_
   __Pyx_INCREF((PyObject *)__pyx_cur_scope->__pyx_v_self);
   __Pyx_GIVEREF((PyObject *)__pyx_cur_scope->__pyx_v_self);
   {
-    __pyx_GeneratorObject *gen = __Pyx_Generator_New((__pyx_generator_body_t) __pyx_gb_5_cdec_10Hypergraph_5edges_2generator6, (PyObject *) __pyx_cur_scope); if (unlikely(!gen)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 115; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_GeneratorObject *gen = __Pyx_Generator_New((__pyx_generator_body_t) __pyx_gb_5_cdec_9BaseTRule_1a_2generator2, (PyObject *) __pyx_cur_scope); if (unlikely(!gen)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 90; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
     __Pyx_DECREF(__pyx_cur_scope);
     __Pyx_RefNannyFinishContext();
     return (PyObject *) gen;
@@ -5890,7 +5811,7 @@ static PyObject *__pyx_pf_5_cdec_10Hypergraph_5edges___get__(struct __pyx_obj_5_
   __pyx_r = Py_None; __Pyx_INCREF(Py_None);
   goto __pyx_L0;
   __pyx_L1_error:;
-  __Pyx_AddTraceback("_cdec.Hypergraph.edges.__get__", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __Pyx_AddTraceback("_cdec.BaseTRule.a.__get__", __pyx_clineno, __pyx_lineno, __pyx_filename);
   __pyx_r = NULL;
   __pyx_L0:;
   __Pyx_DECREF(((PyObject *)__pyx_cur_scope));
@@ -5899,14 +5820,15 @@ static PyObject *__pyx_pf_5_cdec_10Hypergraph_5edges___get__(struct __pyx_obj_5_
   return __pyx_r;
 }
 
-static PyObject *__pyx_gb_5_cdec_10Hypergraph_5edges_2generator6(__pyx_GeneratorObject *__pyx_generator, PyObject *__pyx_sent_value) /* generator body */
+static PyObject *__pyx_gb_5_cdec_9BaseTRule_1a_2generator2(__pyx_GeneratorObject *__pyx_generator, PyObject *__pyx_sent_value) /* generator body */
 {
-  struct __pyx_obj_5_cdec___pyx_scope_struct_6___get__ *__pyx_cur_scope = ((struct __pyx_obj_5_cdec___pyx_scope_struct_6___get__ *)__pyx_generator->closure);
+  struct __pyx_obj_5_cdec___pyx_scope_struct_4___get__ *__pyx_cur_scope = ((struct __pyx_obj_5_cdec___pyx_scope_struct_4___get__ *)__pyx_generator->closure);
   PyObject *__pyx_r = NULL;
   size_t __pyx_t_1;
   unsigned int __pyx_t_2;
   PyObject *__pyx_t_3 = NULL;
   PyObject *__pyx_t_4 = NULL;
+  PyObject *__pyx_t_5 = NULL;
   __Pyx_RefNannyDeclarations
   __Pyx_RefNannySetupContext("None", 0);
   switch (__pyx_generator->resume_label) {
@@ -5917,33 +5839,49 @@ static PyObject *__pyx_gb_5_cdec_10Hypergraph_5edges_2generator6(__pyx_Generator
     return NULL;
   }
   __pyx_L3_first_run:;
-  if (unlikely(!__pyx_sent_value)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 115; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (unlikely(!__pyx_sent_value)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 90; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":117
+  /* "/Users/vchahun/Sandbox/cdec/python/src/grammar.pxi":92
  *         def __get__(self):
  *             cdef unsigned i
- *             for i in range(self.hg.edges_.size()):             # <<<<<<<<<<<<<<
- *                 yield HypergraphEdge().init(self.hg, i)
+ *             cdef vector[grammar.AlignmentPoint]* a = &self.rule.get().a_             # <<<<<<<<<<<<<<
+ *             for i in range(a.size()):
+ *                 yield (a[0][i].s_, a[0][i].t_)
+ */
+  __pyx_cur_scope->__pyx_v_a = (&__pyx_cur_scope->__pyx_v_self->rule->get()->a_);
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/grammar.pxi":93
+ *             cdef unsigned i
+ *             cdef vector[grammar.AlignmentPoint]* a = &self.rule.get().a_
+ *             for i in range(a.size()):             # <<<<<<<<<<<<<<
+ *                 yield (a[0][i].s_, a[0][i].t_)
  * 
  */
-  __pyx_t_1 = __pyx_cur_scope->__pyx_v_self->hg->edges_.size();
+  __pyx_t_1 = __pyx_cur_scope->__pyx_v_a->size();
   for (__pyx_t_2 = 0; __pyx_t_2 < __pyx_t_1; __pyx_t_2+=1) {
     __pyx_cur_scope->__pyx_v_i = __pyx_t_2;
 
-    /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":118
- *             cdef unsigned i
- *             for i in range(self.hg.edges_.size()):
- *                 yield HypergraphEdge().init(self.hg, i)             # <<<<<<<<<<<<<<
+    /* "/Users/vchahun/Sandbox/cdec/python/src/grammar.pxi":94
+ *             cdef vector[grammar.AlignmentPoint]* a = &self.rule.get().a_
+ *             for i in range(a.size()):
+ *                 yield (a[0][i].s_, a[0][i].t_)             # <<<<<<<<<<<<<<
  * 
- *     property nodes:
+ *         def __set__(self, a):
  */
-    __pyx_t_3 = PyObject_Call(((PyObject *)((PyObject*)__pyx_ptype_5_cdec_HypergraphEdge)), ((PyObject *)__pyx_empty_tuple), NULL); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 118; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_t_3 = PyInt_FromLong(((__pyx_cur_scope->__pyx_v_a[0])[__pyx_cur_scope->__pyx_v_i]).s_); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 94; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
     __Pyx_GOTREF(__pyx_t_3);
-    __pyx_t_4 = ((struct __pyx_vtabstruct_5_cdec_HypergraphEdge *)((struct __pyx_obj_5_cdec_HypergraphEdge *)__pyx_t_3)->__pyx_vtab)->init(((struct __pyx_obj_5_cdec_HypergraphEdge *)__pyx_t_3), __pyx_cur_scope->__pyx_v_self->hg, __pyx_cur_scope->__pyx_v_i); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 118; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_t_4 = PyInt_FromLong(((__pyx_cur_scope->__pyx_v_a[0])[__pyx_cur_scope->__pyx_v_i]).t_); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 94; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
     __Pyx_GOTREF(__pyx_t_4);
-    __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
-    __pyx_r = __pyx_t_4;
+    __pyx_t_5 = PyTuple_New(2); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 94; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_5);
+    PyTuple_SET_ITEM(__pyx_t_5, 0, __pyx_t_3);
+    __Pyx_GIVEREF(__pyx_t_3);
+    PyTuple_SET_ITEM(__pyx_t_5, 1, __pyx_t_4);
+    __Pyx_GIVEREF(__pyx_t_4);
+    __pyx_t_3 = 0;
     __pyx_t_4 = 0;
+    __pyx_r = ((PyObject *)__pyx_t_5);
+    __pyx_t_5 = 0;
     __pyx_cur_scope->__pyx_t_0 = __pyx_t_1;
     __pyx_cur_scope->__pyx_t_1 = __pyx_t_2;
     __Pyx_XGIVEREF(__pyx_r);
@@ -5954,13 +5892,14 @@ static PyObject *__pyx_gb_5_cdec_10Hypergraph_5edges_2generator6(__pyx_Generator
     __pyx_L6_resume_from_yield:;
     __pyx_t_1 = __pyx_cur_scope->__pyx_t_0;
     __pyx_t_2 = __pyx_cur_scope->__pyx_t_1;
-    if (unlikely(!__pyx_sent_value)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 118; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    if (unlikely(!__pyx_sent_value)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 94; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   }
   PyErr_SetNone(PyExc_StopIteration);
   goto __pyx_L0;
   __pyx_L1_error:;
   __Pyx_XDECREF(__pyx_t_3);
   __Pyx_XDECREF(__pyx_t_4);
+  __Pyx_XDECREF(__pyx_t_5);
   __Pyx_AddTraceback("__get__", __pyx_clineno, __pyx_lineno, __pyx_filename);
   __pyx_L0:;
   __Pyx_XDECREF(__pyx_r);
@@ -5968,460 +5907,488 @@ static PyObject *__pyx_gb_5_cdec_10Hypergraph_5edges_2generator6(__pyx_Generator
   __Pyx_RefNannyFinishContext();
   return NULL;
 }
-static PyObject *__pyx_gb_5_cdec_10Hypergraph_5nodes_2generator7(__pyx_GeneratorObject *__pyx_generator, PyObject *__pyx_sent_value); /* proto */
 
 /* Python wrapper */
-static PyObject *__pyx_pw_5_cdec_10Hypergraph_5nodes_1__get__(PyObject *__pyx_v_self); /*proto*/
-static PyObject *__pyx_pw_5_cdec_10Hypergraph_5nodes_1__get__(PyObject *__pyx_v_self) {
-  PyObject *__pyx_r = 0;
+static int __pyx_pw_5_cdec_9BaseTRule_1a_4__set__(PyObject *__pyx_v_self, PyObject *__pyx_v_a); /*proto*/
+static int __pyx_pw_5_cdec_9BaseTRule_1a_4__set__(PyObject *__pyx_v_self, PyObject *__pyx_v_a) {
+  int __pyx_r;
   __Pyx_RefNannyDeclarations
-  __Pyx_RefNannySetupContext("__get__ (wrapper)", 0);
-  __pyx_r = __pyx_pf_5_cdec_10Hypergraph_5nodes___get__(((struct __pyx_obj_5_cdec_Hypergraph *)__pyx_v_self));
+  __Pyx_RefNannySetupContext("__set__ (wrapper)", 0);
+  __pyx_r = __pyx_pf_5_cdec_9BaseTRule_1a_3__set__(((struct __pyx_obj_5_cdec_BaseTRule *)__pyx_v_self), ((PyObject *)__pyx_v_a));
   __Pyx_RefNannyFinishContext();
   return __pyx_r;
 }
 
-/* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":121
+/* "/Users/vchahun/Sandbox/cdec/python/src/grammar.pxi":96
+ *                 yield (a[0][i].s_, a[0][i].t_)
  * 
- *     property nodes:
- *         def __get__(self):             # <<<<<<<<<<<<<<
- *             cdef unsigned i
- *             for i in range(self.hg.nodes_.size()):
+ *         def __set__(self, a):             # <<<<<<<<<<<<<<
+ *             cdef vector[grammar.AlignmentPoint]* a_ = &self.rule.get().a_
+ *             a_.resize(len(a))
  */
 
-static PyObject *__pyx_pf_5_cdec_10Hypergraph_5nodes___get__(struct __pyx_obj_5_cdec_Hypergraph *__pyx_v_self) {
-  struct __pyx_obj_5_cdec___pyx_scope_struct_7___get__ *__pyx_cur_scope;
-  PyObject *__pyx_r = NULL;
+static int __pyx_pf_5_cdec_9BaseTRule_1a_3__set__(struct __pyx_obj_5_cdec_BaseTRule *__pyx_v_self, PyObject *__pyx_v_a) {
+  std::vector<AlignmentPoint> *__pyx_v_a_;
+  unsigned int __pyx_v_i;
+  int __pyx_v_s;
+  int __pyx_v_t;
+  int __pyx_r;
   __Pyx_RefNannyDeclarations
+  Py_ssize_t __pyx_t_1;
+  unsigned int __pyx_t_2;
+  PyObject *__pyx_t_3 = NULL;
+  PyObject *__pyx_t_4 = NULL;
+  PyObject *__pyx_t_5 = NULL;
+  PyObject *__pyx_t_6 = NULL;
+  PyObject *(*__pyx_t_7)(PyObject *);
+  int __pyx_t_8;
+  int __pyx_t_9;
   int __pyx_lineno = 0;
   const char *__pyx_filename = NULL;
   int __pyx_clineno = 0;
-  __Pyx_RefNannySetupContext("__get__", 0);
-  __pyx_cur_scope = (struct __pyx_obj_5_cdec___pyx_scope_struct_7___get__ *)__pyx_ptype_5_cdec___pyx_scope_struct_7___get__->tp_new(__pyx_ptype_5_cdec___pyx_scope_struct_7___get__, __pyx_empty_tuple, NULL);
-  if (unlikely(!__pyx_cur_scope)) {
-    __Pyx_RefNannyFinishContext();
-    return NULL;
-  }
-  __Pyx_GOTREF(__pyx_cur_scope);
-  __pyx_cur_scope->__pyx_v_self = __pyx_v_self;
-  __Pyx_INCREF((PyObject *)__pyx_cur_scope->__pyx_v_self);
-  __Pyx_GIVEREF((PyObject *)__pyx_cur_scope->__pyx_v_self);
-  {
-    __pyx_GeneratorObject *gen = __Pyx_Generator_New((__pyx_generator_body_t) __pyx_gb_5_cdec_10Hypergraph_5nodes_2generator7, (PyObject *) __pyx_cur_scope); if (unlikely(!gen)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 121; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-    __Pyx_DECREF(__pyx_cur_scope);
-    __Pyx_RefNannyFinishContext();
-    return (PyObject *) gen;
-  }
+  __Pyx_RefNannySetupContext("__set__", 0);
 
-  __pyx_r = Py_None; __Pyx_INCREF(Py_None);
-  goto __pyx_L0;
-  __pyx_L1_error:;
-  __Pyx_AddTraceback("_cdec.Hypergraph.nodes.__get__", __pyx_clineno, __pyx_lineno, __pyx_filename);
-  __pyx_r = NULL;
-  __pyx_L0:;
-  __Pyx_DECREF(((PyObject *)__pyx_cur_scope));
-  __Pyx_XGIVEREF(__pyx_r);
-  __Pyx_RefNannyFinishContext();
-  return __pyx_r;
-}
+  /* "/Users/vchahun/Sandbox/cdec/python/src/grammar.pxi":97
+ * 
+ *         def __set__(self, a):
+ *             cdef vector[grammar.AlignmentPoint]* a_ = &self.rule.get().a_             # <<<<<<<<<<<<<<
+ *             a_.resize(len(a))
+ *             cdef unsigned i
+ */
+  __pyx_v_a_ = (&__pyx_v_self->rule->get()->a_);
 
-static PyObject *__pyx_gb_5_cdec_10Hypergraph_5nodes_2generator7(__pyx_GeneratorObject *__pyx_generator, PyObject *__pyx_sent_value) /* generator body */
-{
-  struct __pyx_obj_5_cdec___pyx_scope_struct_7___get__ *__pyx_cur_scope = ((struct __pyx_obj_5_cdec___pyx_scope_struct_7___get__ *)__pyx_generator->closure);
-  PyObject *__pyx_r = NULL;
-  size_t __pyx_t_1;
-  unsigned int __pyx_t_2;
-  PyObject *__pyx_t_3 = NULL;
-  PyObject *__pyx_t_4 = NULL;
-  __Pyx_RefNannyDeclarations
-  __Pyx_RefNannySetupContext("None", 0);
-  switch (__pyx_generator->resume_label) {
-    case 0: goto __pyx_L3_first_run;
-    case 1: goto __pyx_L6_resume_from_yield;
-    default: /* CPython raises the right error here */
-    __Pyx_RefNannyFinishContext();
-    return NULL;
-  }
-  __pyx_L3_first_run:;
-  if (unlikely(!__pyx_sent_value)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 121; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  /* "/Users/vchahun/Sandbox/cdec/python/src/grammar.pxi":98
+ *         def __set__(self, a):
+ *             cdef vector[grammar.AlignmentPoint]* a_ = &self.rule.get().a_
+ *             a_.resize(len(a))             # <<<<<<<<<<<<<<
+ *             cdef unsigned i
+ *             cdef int s, t
+ */
+  __pyx_t_1 = PyObject_Length(__pyx_v_a); if (unlikely(__pyx_t_1 == -1)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 98; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_v_a_->resize(__pyx_t_1);
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":123
- *         def __get__(self):
+  /* "/Users/vchahun/Sandbox/cdec/python/src/grammar.pxi":101
  *             cdef unsigned i
- *             for i in range(self.hg.nodes_.size()):             # <<<<<<<<<<<<<<
- *                 yield HypergraphNode().init(self.hg, i)
- * 
+ *             cdef int s, t
+ *             for i in range(len(a)):             # <<<<<<<<<<<<<<
+ *                 s, t = a[i]
+ *                 a_[0][i] = grammar.AlignmentPoint(s, t)
  */
-  __pyx_t_1 = __pyx_cur_scope->__pyx_v_self->hg->nodes_.size();
+  __pyx_t_1 = PyObject_Length(__pyx_v_a); if (unlikely(__pyx_t_1 == -1)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 101; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   for (__pyx_t_2 = 0; __pyx_t_2 < __pyx_t_1; __pyx_t_2+=1) {
-    __pyx_cur_scope->__pyx_v_i = __pyx_t_2;
+    __pyx_v_i = __pyx_t_2;
 
-    /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":124
- *             cdef unsigned i
- *             for i in range(self.hg.nodes_.size()):
- *                 yield HypergraphNode().init(self.hg, i)             # <<<<<<<<<<<<<<
+    /* "/Users/vchahun/Sandbox/cdec/python/src/grammar.pxi":102
+ *             cdef int s, t
+ *             for i in range(len(a)):
+ *                 s, t = a[i]             # <<<<<<<<<<<<<<
+ *                 a_[0][i] = grammar.AlignmentPoint(s, t)
  * 
- *     property goal:
  */
-    __pyx_t_3 = PyObject_Call(((PyObject *)((PyObject*)__pyx_ptype_5_cdec_HypergraphNode)), ((PyObject *)__pyx_empty_tuple), NULL); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 124; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_t_3 = __Pyx_GetItemInt(__pyx_v_a, __pyx_v_i, sizeof(unsigned int)+1, PyLong_FromUnsignedLong); if (!__pyx_t_3) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 102; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
     __Pyx_GOTREF(__pyx_t_3);
-    __pyx_t_4 = ((struct __pyx_vtabstruct_5_cdec_HypergraphNode *)((struct __pyx_obj_5_cdec_HypergraphNode *)__pyx_t_3)->__pyx_vtab)->init(((struct __pyx_obj_5_cdec_HypergraphNode *)__pyx_t_3), __pyx_cur_scope->__pyx_v_self->hg, __pyx_cur_scope->__pyx_v_i); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 124; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-    __Pyx_GOTREF(__pyx_t_4);
-    __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
-    __pyx_r = __pyx_t_4;
-    __pyx_t_4 = 0;
-    __pyx_cur_scope->__pyx_t_0 = __pyx_t_1;
-    __pyx_cur_scope->__pyx_t_1 = __pyx_t_2;
-    __Pyx_XGIVEREF(__pyx_r);
-    __Pyx_RefNannyFinishContext();
-    /* return from generator, yielding value */
-    __pyx_generator->resume_label = 1;
-    return __pyx_r;
-    __pyx_L6_resume_from_yield:;
-    __pyx_t_1 = __pyx_cur_scope->__pyx_t_0;
-    __pyx_t_2 = __pyx_cur_scope->__pyx_t_1;
-    if (unlikely(!__pyx_sent_value)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 124; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    if ((likely(PyTuple_CheckExact(__pyx_t_3))) || (PyList_CheckExact(__pyx_t_3))) {
+      PyObject* sequence = __pyx_t_3;
+      if (likely(PyTuple_CheckExact(sequence))) {
+        if (unlikely(PyTuple_GET_SIZE(sequence) != 2)) {
+          if (PyTuple_GET_SIZE(sequence) > 2) __Pyx_RaiseTooManyValuesError(2);
+          else __Pyx_RaiseNeedMoreValuesError(PyTuple_GET_SIZE(sequence));
+          {__pyx_filename = __pyx_f[2]; __pyx_lineno = 102; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+        }
+        __pyx_t_4 = PyTuple_GET_ITEM(sequence, 0); 
+        __pyx_t_5 = PyTuple_GET_ITEM(sequence, 1); 
+      } else {
+        if (unlikely(PyList_GET_SIZE(sequence) != 2)) {
+          if (PyList_GET_SIZE(sequence) > 2) __Pyx_RaiseTooManyValuesError(2);
+          else __Pyx_RaiseNeedMoreValuesError(PyList_GET_SIZE(sequence));
+          {__pyx_filename = __pyx_f[2]; __pyx_lineno = 102; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+        }
+        __pyx_t_4 = PyList_GET_ITEM(sequence, 0); 
+        __pyx_t_5 = PyList_GET_ITEM(sequence, 1); 
+      }
+      __Pyx_INCREF(__pyx_t_4);
+      __Pyx_INCREF(__pyx_t_5);
+      __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
+    } else {
+      Py_ssize_t index = -1;
+      __pyx_t_6 = PyObject_GetIter(__pyx_t_3); if (unlikely(!__pyx_t_6)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 102; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __Pyx_GOTREF(__pyx_t_6);
+      __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
+      __pyx_t_7 = Py_TYPE(__pyx_t_6)->tp_iternext;
+      index = 0; __pyx_t_4 = __pyx_t_7(__pyx_t_6); if (unlikely(!__pyx_t_4)) goto __pyx_L5_unpacking_failed;
+      __Pyx_GOTREF(__pyx_t_4);
+      index = 1; __pyx_t_5 = __pyx_t_7(__pyx_t_6); if (unlikely(!__pyx_t_5)) goto __pyx_L5_unpacking_failed;
+      __Pyx_GOTREF(__pyx_t_5);
+      if (__Pyx_IternextUnpackEndCheck(__pyx_t_7(__pyx_t_6), 2) < 0) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 102; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0;
+      goto __pyx_L6_unpacking_done;
+      __pyx_L5_unpacking_failed:;
+      __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0;
+      if (PyErr_Occurred() && PyErr_ExceptionMatches(PyExc_StopIteration)) PyErr_Clear();
+      if (!PyErr_Occurred()) __Pyx_RaiseNeedMoreValuesError(index);
+      {__pyx_filename = __pyx_f[2]; __pyx_lineno = 102; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __pyx_L6_unpacking_done:;
+    }
+    __pyx_t_8 = __Pyx_PyInt_AsInt(__pyx_t_4); if (unlikely((__pyx_t_8 == (int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 102; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
+    __pyx_t_9 = __Pyx_PyInt_AsInt(__pyx_t_5); if (unlikely((__pyx_t_9 == (int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 102; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
+    __pyx_v_s = __pyx_t_8;
+    __pyx_v_t = __pyx_t_9;
+
+    /* "/Users/vchahun/Sandbox/cdec/python/src/grammar.pxi":103
+ *             for i in range(len(a)):
+ *                 s, t = a[i]
+ *                 a_[0][i] = grammar.AlignmentPoint(s, t)             # <<<<<<<<<<<<<<
+ * 
+ *     property scores:
+ */
+    ((__pyx_v_a_[0])[__pyx_v_i]) = AlignmentPoint(__pyx_v_s, __pyx_v_t);
   }
-  PyErr_SetNone(PyExc_StopIteration);
+
+  __pyx_r = 0;
   goto __pyx_L0;
   __pyx_L1_error:;
   __Pyx_XDECREF(__pyx_t_3);
   __Pyx_XDECREF(__pyx_t_4);
-  __Pyx_AddTraceback("__get__", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __Pyx_XDECREF(__pyx_t_5);
+  __Pyx_XDECREF(__pyx_t_6);
+  __Pyx_AddTraceback("_cdec.BaseTRule.a.__set__", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __pyx_r = -1;
   __pyx_L0:;
-  __Pyx_XDECREF(__pyx_r);
-  __pyx_generator->resume_label = -1;
   __Pyx_RefNannyFinishContext();
-  return NULL;
+  return __pyx_r;
 }
 
 /* Python wrapper */
-static PyObject *__pyx_pw_5_cdec_10Hypergraph_4goal_1__get__(PyObject *__pyx_v_self); /*proto*/
-static PyObject *__pyx_pw_5_cdec_10Hypergraph_4goal_1__get__(PyObject *__pyx_v_self) {
+static PyObject *__pyx_pw_5_cdec_9BaseTRule_6scores_1__get__(PyObject *__pyx_v_self); /*proto*/
+static PyObject *__pyx_pw_5_cdec_9BaseTRule_6scores_1__get__(PyObject *__pyx_v_self) {
   PyObject *__pyx_r = 0;
   __Pyx_RefNannyDeclarations
   __Pyx_RefNannySetupContext("__get__ (wrapper)", 0);
-  __pyx_r = __pyx_pf_5_cdec_10Hypergraph_4goal___get__(((struct __pyx_obj_5_cdec_Hypergraph *)__pyx_v_self));
+  __pyx_r = __pyx_pf_5_cdec_9BaseTRule_6scores___get__(((struct __pyx_obj_5_cdec_BaseTRule *)__pyx_v_self));
   __Pyx_RefNannyFinishContext();
   return __pyx_r;
 }
 
-/* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":127
+/* "/Users/vchahun/Sandbox/cdec/python/src/grammar.pxi":106
  * 
- *     property goal:
+ *     property scores:
  *         def __get__(self):             # <<<<<<<<<<<<<<
- *             return HypergraphNode().init(self.hg, self.hg.GoalNode())
- * 
+ *             cdef SparseVector scores = SparseVector()
+ *             scores.vector = new FastSparseVector[double](self.rule.get().scores_)
  */
 
-static PyObject *__pyx_pf_5_cdec_10Hypergraph_4goal___get__(struct __pyx_obj_5_cdec_Hypergraph *__pyx_v_self) {
+static PyObject *__pyx_pf_5_cdec_9BaseTRule_6scores___get__(struct __pyx_obj_5_cdec_BaseTRule *__pyx_v_self) {
+  struct __pyx_obj_5_cdec_SparseVector *__pyx_v_scores = 0;
   PyObject *__pyx_r = NULL;
   __Pyx_RefNannyDeclarations
   PyObject *__pyx_t_1 = NULL;
-  PyObject *__pyx_t_2 = NULL;
   int __pyx_lineno = 0;
   const char *__pyx_filename = NULL;
   int __pyx_clineno = 0;
   __Pyx_RefNannySetupContext("__get__", 0);
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":128
- *     property goal:
+  /* "/Users/vchahun/Sandbox/cdec/python/src/grammar.pxi":107
+ *     property scores:
  *         def __get__(self):
- *             return HypergraphNode().init(self.hg, self.hg.GoalNode())             # <<<<<<<<<<<<<<
+ *             cdef SparseVector scores = SparseVector()             # <<<<<<<<<<<<<<
+ *             scores.vector = new FastSparseVector[double](self.rule.get().scores_)
+ *             return scores
+ */
+  __pyx_t_1 = PyObject_Call(((PyObject *)((PyObject*)__pyx_ptype_5_cdec_SparseVector)), ((PyObject *)__pyx_empty_tuple), NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 107; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_1);
+  __pyx_v_scores = ((struct __pyx_obj_5_cdec_SparseVector *)__pyx_t_1);
+  __pyx_t_1 = 0;
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/grammar.pxi":108
+ *         def __get__(self):
+ *             cdef SparseVector scores = SparseVector()
+ *             scores.vector = new FastSparseVector[double](self.rule.get().scores_)             # <<<<<<<<<<<<<<
+ *             return scores
  * 
+ */
+  __pyx_v_scores->vector = new FastSparseVector<double>(__pyx_v_self->rule->get()->scores_);
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/grammar.pxi":109
+ *             cdef SparseVector scores = SparseVector()
+ *             scores.vector = new FastSparseVector[double](self.rule.get().scores_)
+ *             return scores             # <<<<<<<<<<<<<<
  * 
+ *         def __set__(self, scores):
  */
   __Pyx_XDECREF(__pyx_r);
-  __pyx_t_1 = PyObject_Call(((PyObject *)((PyObject*)__pyx_ptype_5_cdec_HypergraphNode)), ((PyObject *)__pyx_empty_tuple), NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 128; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __Pyx_GOTREF(__pyx_t_1);
-  __pyx_t_2 = ((struct __pyx_vtabstruct_5_cdec_HypergraphNode *)((struct __pyx_obj_5_cdec_HypergraphNode *)__pyx_t_1)->__pyx_vtab)->init(((struct __pyx_obj_5_cdec_HypergraphNode *)__pyx_t_1), __pyx_v_self->hg, __pyx_v_self->hg->GoalNode()); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 128; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __Pyx_GOTREF(__pyx_t_2);
-  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
-  __pyx_r = __pyx_t_2;
-  __pyx_t_2 = 0;
+  __Pyx_INCREF(((PyObject *)__pyx_v_scores));
+  __pyx_r = ((PyObject *)__pyx_v_scores);
   goto __pyx_L0;
 
   __pyx_r = Py_None; __Pyx_INCREF(Py_None);
   goto __pyx_L0;
   __pyx_L1_error:;
   __Pyx_XDECREF(__pyx_t_1);
-  __Pyx_XDECREF(__pyx_t_2);
-  __Pyx_AddTraceback("_cdec.Hypergraph.goal.__get__", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __Pyx_AddTraceback("_cdec.BaseTRule.scores.__get__", __pyx_clineno, __pyx_lineno, __pyx_filename);
   __pyx_r = NULL;
   __pyx_L0:;
+  __Pyx_XDECREF((PyObject *)__pyx_v_scores);
   __Pyx_XGIVEREF(__pyx_r);
   __Pyx_RefNannyFinishContext();
   return __pyx_r;
 }
 
 /* Python wrapper */
-static PyObject *__pyx_pw_5_cdec_1_phrase(PyObject *__pyx_self, PyObject *__pyx_v_phrase); /*proto*/
-static PyMethodDef __pyx_mdef_5_cdec_1_phrase = {__Pyx_NAMESTR("_phrase"), (PyCFunction)__pyx_pw_5_cdec_1_phrase, METH_O, __Pyx_DOCSTR(0)};
-static PyObject *__pyx_pw_5_cdec_1_phrase(PyObject *__pyx_self, PyObject *__pyx_v_phrase) {
-  PyObject *__pyx_r = 0;
+static int __pyx_pw_5_cdec_9BaseTRule_6scores_3__set__(PyObject *__pyx_v_self, PyObject *__pyx_v_scores); /*proto*/
+static int __pyx_pw_5_cdec_9BaseTRule_6scores_3__set__(PyObject *__pyx_v_self, PyObject *__pyx_v_scores) {
+  int __pyx_r;
   __Pyx_RefNannyDeclarations
-  __Pyx_RefNannySetupContext("_phrase (wrapper)", 0);
-  __pyx_self = __pyx_self;
-  __pyx_r = __pyx_pf_5_cdec__phrase(__pyx_self, ((PyObject *)__pyx_v_phrase));
+  __Pyx_RefNannySetupContext("__set__ (wrapper)", 0);
+  __pyx_r = __pyx_pf_5_cdec_9BaseTRule_6scores_2__set__(((struct __pyx_obj_5_cdec_BaseTRule *)__pyx_v_self), ((PyObject *)__pyx_v_scores));
   __Pyx_RefNannyFinishContext();
   return __pyx_r;
 }
-static PyObject *__pyx_gb_5_cdec_7_phrase_2generator15(__pyx_GeneratorObject *__pyx_generator, PyObject *__pyx_sent_value); /* proto */
 
-/* "/Users/vchahun/Sandbox/cdec/python/src/trule.pxi":2
- * def _phrase(phrase):
- *     return ' '.join('[%s,%d]' % w if isinstance(w, tuple) else w.encode('utf8') for w in phrase)             # <<<<<<<<<<<<<<
+/* "/Users/vchahun/Sandbox/cdec/python/src/grammar.pxi":111
+ *             return scores
  * 
- * cdef class TRule:
+ *         def __set__(self, scores):             # <<<<<<<<<<<<<<
+ *             cdef FastSparseVector[double]* scores_ = &self.rule.get().scores_
+ *             scores_.clear()
  */
 
-static PyObject *__pyx_pf_5_cdec_7_phrase_genexpr(PyObject *__pyx_self) {
-  struct __pyx_obj_5_cdec___pyx_scope_struct_9_genexpr *__pyx_cur_scope;
-  PyObject *__pyx_r = NULL;
+static int __pyx_pf_5_cdec_9BaseTRule_6scores_2__set__(struct __pyx_obj_5_cdec_BaseTRule *__pyx_v_self, PyObject *__pyx_v_scores) {
+  FastSparseVector<double> *__pyx_v_scores_;
+  int __pyx_v_fid;
+  float __pyx_v_fval;
+  PyObject *__pyx_v_fname = NULL;
+  int __pyx_r;
   __Pyx_RefNannyDeclarations
+  PyObject *__pyx_t_1 = NULL;
+  PyObject *__pyx_t_2 = NULL;
+  Py_ssize_t __pyx_t_3;
+  PyObject *(*__pyx_t_4)(PyObject *);
+  PyObject *__pyx_t_5 = NULL;
+  PyObject *__pyx_t_6 = NULL;
+  PyObject *__pyx_t_7 = NULL;
+  PyObject *(*__pyx_t_8)(PyObject *);
+  float __pyx_t_9;
+  int __pyx_t_10;
   int __pyx_lineno = 0;
   const char *__pyx_filename = NULL;
   int __pyx_clineno = 0;
-  __Pyx_RefNannySetupContext("genexpr", 0);
-  __pyx_cur_scope = (struct __pyx_obj_5_cdec___pyx_scope_struct_9_genexpr *)__pyx_ptype_5_cdec___pyx_scope_struct_9_genexpr->tp_new(__pyx_ptype_5_cdec___pyx_scope_struct_9_genexpr, __pyx_empty_tuple, NULL);
-  if (unlikely(!__pyx_cur_scope)) {
-    __Pyx_RefNannyFinishContext();
-    return NULL;
-  }
-  __Pyx_GOTREF(__pyx_cur_scope);
-  __pyx_cur_scope->__pyx_outer_scope = (struct __pyx_obj_5_cdec___pyx_scope_struct_8__phrase *) __pyx_self;
-  __Pyx_INCREF(((PyObject *)__pyx_cur_scope->__pyx_outer_scope));
-  __Pyx_GIVEREF(__pyx_cur_scope->__pyx_outer_scope);
-  {
-    __pyx_GeneratorObject *gen = __Pyx_Generator_New((__pyx_generator_body_t) __pyx_gb_5_cdec_7_phrase_2generator15, (PyObject *) __pyx_cur_scope); if (unlikely(!gen)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 2; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-    __Pyx_DECREF(__pyx_cur_scope);
-    __Pyx_RefNannyFinishContext();
-    return (PyObject *) gen;
-  }
+  __Pyx_RefNannySetupContext("__set__", 0);
 
-  __pyx_r = Py_None; __Pyx_INCREF(Py_None);
-  goto __pyx_L0;
-  __pyx_L1_error:;
-  __Pyx_AddTraceback("_cdec._phrase.genexpr", __pyx_clineno, __pyx_lineno, __pyx_filename);
-  __pyx_r = NULL;
-  __pyx_L0:;
-  __Pyx_DECREF(((PyObject *)__pyx_cur_scope));
-  __Pyx_XGIVEREF(__pyx_r);
-  __Pyx_RefNannyFinishContext();
-  return __pyx_r;
-}
+  /* "/Users/vchahun/Sandbox/cdec/python/src/grammar.pxi":112
+ * 
+ *         def __set__(self, scores):
+ *             cdef FastSparseVector[double]* scores_ = &self.rule.get().scores_             # <<<<<<<<<<<<<<
+ *             scores_.clear()
+ *             cdef int fid
+ */
+  __pyx_v_scores_ = (&__pyx_v_self->rule->get()->scores_);
 
-static PyObject *__pyx_gb_5_cdec_7_phrase_2generator15(__pyx_GeneratorObject *__pyx_generator, PyObject *__pyx_sent_value) /* generator body */
-{
-  struct __pyx_obj_5_cdec___pyx_scope_struct_9_genexpr *__pyx_cur_scope = ((struct __pyx_obj_5_cdec___pyx_scope_struct_9_genexpr *)__pyx_generator->closure);
-  PyObject *__pyx_r = NULL;
-  PyObject *__pyx_t_1 = NULL;
-  Py_ssize_t __pyx_t_2;
-  PyObject *(*__pyx_t_3)(PyObject *);
-  PyObject *__pyx_t_4 = NULL;
-  PyObject *__pyx_t_5 = NULL;
-  int __pyx_t_6;
-  PyObject *__pyx_t_7 = NULL;
-  __Pyx_RefNannyDeclarations
-  __Pyx_RefNannySetupContext("None", 0);
-  switch (__pyx_generator->resume_label) {
-    case 0: goto __pyx_L3_first_run;
-    case 1: goto __pyx_L6_resume_from_yield;
-    default: /* CPython raises the right error here */
-    __Pyx_RefNannyFinishContext();
-    return NULL;
-  }
-  __pyx_L3_first_run:;
-  if (unlikely(!__pyx_sent_value)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 2; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  if (unlikely(!__pyx_cur_scope->__pyx_outer_scope->__pyx_v_phrase)) { __Pyx_RaiseClosureNameError("phrase"); {__pyx_filename = __pyx_f[4]; __pyx_lineno = 2; __pyx_clineno = __LINE__; goto __pyx_L1_error;} }
-  if (PyList_CheckExact(__pyx_cur_scope->__pyx_outer_scope->__pyx_v_phrase) || PyTuple_CheckExact(__pyx_cur_scope->__pyx_outer_scope->__pyx_v_phrase)) {
-    __pyx_t_1 = __pyx_cur_scope->__pyx_outer_scope->__pyx_v_phrase; __Pyx_INCREF(__pyx_t_1); __pyx_t_2 = 0;
-    __pyx_t_3 = NULL;
+  /* "/Users/vchahun/Sandbox/cdec/python/src/grammar.pxi":113
+ *         def __set__(self, scores):
+ *             cdef FastSparseVector[double]* scores_ = &self.rule.get().scores_
+ *             scores_.clear()             # <<<<<<<<<<<<<<
+ *             cdef int fid
+ *             cdef float fval
+ */
+  __pyx_v_scores_->clear();
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/grammar.pxi":116
+ *             cdef int fid
+ *             cdef float fval
+ *             for fname, fval in scores.items():             # <<<<<<<<<<<<<<
+ *                 fid = FDConvert(<char *>as_str(fname))
+ *                 if fid < 0: raise KeyError(fname)
+ */
+  __pyx_t_1 = PyObject_GetAttr(__pyx_v_scores, __pyx_n_s__items); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 116; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_1);
+  __pyx_t_2 = PyObject_Call(__pyx_t_1, ((PyObject *)__pyx_empty_tuple), NULL); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 116; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_2);
+  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+  if (PyList_CheckExact(__pyx_t_2) || PyTuple_CheckExact(__pyx_t_2)) {
+    __pyx_t_1 = __pyx_t_2; __Pyx_INCREF(__pyx_t_1); __pyx_t_3 = 0;
+    __pyx_t_4 = NULL;
   } else {
-    __pyx_t_2 = -1; __pyx_t_1 = PyObject_GetIter(__pyx_cur_scope->__pyx_outer_scope->__pyx_v_phrase); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 2; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_t_3 = -1; __pyx_t_1 = PyObject_GetIter(__pyx_t_2); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 116; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
     __Pyx_GOTREF(__pyx_t_1);
-    __pyx_t_3 = Py_TYPE(__pyx_t_1)->tp_iternext;
+    __pyx_t_4 = Py_TYPE(__pyx_t_1)->tp_iternext;
   }
+  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
   for (;;) {
-    if (!__pyx_t_3 && PyList_CheckExact(__pyx_t_1)) {
-      if (__pyx_t_2 >= PyList_GET_SIZE(__pyx_t_1)) break;
-      __pyx_t_4 = PyList_GET_ITEM(__pyx_t_1, __pyx_t_2); __Pyx_INCREF(__pyx_t_4); __pyx_t_2++;
-    } else if (!__pyx_t_3 && PyTuple_CheckExact(__pyx_t_1)) {
-      if (__pyx_t_2 >= PyTuple_GET_SIZE(__pyx_t_1)) break;
-      __pyx_t_4 = PyTuple_GET_ITEM(__pyx_t_1, __pyx_t_2); __Pyx_INCREF(__pyx_t_4); __pyx_t_2++;
+    if (!__pyx_t_4 && PyList_CheckExact(__pyx_t_1)) {
+      if (__pyx_t_3 >= PyList_GET_SIZE(__pyx_t_1)) break;
+      __pyx_t_2 = PyList_GET_ITEM(__pyx_t_1, __pyx_t_3); __Pyx_INCREF(__pyx_t_2); __pyx_t_3++;
+    } else if (!__pyx_t_4 && PyTuple_CheckExact(__pyx_t_1)) {
+      if (__pyx_t_3 >= PyTuple_GET_SIZE(__pyx_t_1)) break;
+      __pyx_t_2 = PyTuple_GET_ITEM(__pyx_t_1, __pyx_t_3); __Pyx_INCREF(__pyx_t_2); __pyx_t_3++;
     } else {
-      __pyx_t_4 = __pyx_t_3(__pyx_t_1);
-      if (unlikely(!__pyx_t_4)) {
+      __pyx_t_2 = __pyx_t_4(__pyx_t_1);
+      if (unlikely(!__pyx_t_2)) {
         if (PyErr_Occurred()) {
           if (likely(PyErr_ExceptionMatches(PyExc_StopIteration))) PyErr_Clear();
-          else {__pyx_filename = __pyx_f[4]; __pyx_lineno = 2; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+          else {__pyx_filename = __pyx_f[2]; __pyx_lineno = 116; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
         }
         break;
       }
-      __Pyx_GOTREF(__pyx_t_4);
+      __Pyx_GOTREF(__pyx_t_2);
     }
-    __Pyx_XGOTREF(__pyx_cur_scope->__pyx_v_w);
-    __Pyx_XDECREF(__pyx_cur_scope->__pyx_v_w);
-    __Pyx_GIVEREF(__pyx_t_4);
-    __pyx_cur_scope->__pyx_v_w = __pyx_t_4;
-    __pyx_t_4 = 0;
-    __pyx_t_5 = ((PyObject *)((PyObject*)(&PyTuple_Type)));
-    __Pyx_INCREF(__pyx_t_5);
-    __pyx_t_6 = __Pyx_TypeCheck(__pyx_cur_scope->__pyx_v_w, __pyx_t_5); 
-    __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
-    if (__pyx_t_6) {
-      __pyx_t_5 = PyNumber_Remainder(((PyObject *)__pyx_kp_s_8), __pyx_cur_scope->__pyx_v_w); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 2; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-      __Pyx_GOTREF(((PyObject *)__pyx_t_5));
-      __pyx_t_4 = ((PyObject *)__pyx_t_5);
-      __pyx_t_5 = 0;
+    if ((likely(PyTuple_CheckExact(__pyx_t_2))) || (PyList_CheckExact(__pyx_t_2))) {
+      PyObject* sequence = __pyx_t_2;
+      if (likely(PyTuple_CheckExact(sequence))) {
+        if (unlikely(PyTuple_GET_SIZE(sequence) != 2)) {
+          if (PyTuple_GET_SIZE(sequence) > 2) __Pyx_RaiseTooManyValuesError(2);
+          else __Pyx_RaiseNeedMoreValuesError(PyTuple_GET_SIZE(sequence));
+          {__pyx_filename = __pyx_f[2]; __pyx_lineno = 116; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+        }
+        __pyx_t_5 = PyTuple_GET_ITEM(sequence, 0); 
+        __pyx_t_6 = PyTuple_GET_ITEM(sequence, 1); 
+      } else {
+        if (unlikely(PyList_GET_SIZE(sequence) != 2)) {
+          if (PyList_GET_SIZE(sequence) > 2) __Pyx_RaiseTooManyValuesError(2);
+          else __Pyx_RaiseNeedMoreValuesError(PyList_GET_SIZE(sequence));
+          {__pyx_filename = __pyx_f[2]; __pyx_lineno = 116; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+        }
+        __pyx_t_5 = PyList_GET_ITEM(sequence, 0); 
+        __pyx_t_6 = PyList_GET_ITEM(sequence, 1); 
+      }
+      __Pyx_INCREF(__pyx_t_5);
+      __Pyx_INCREF(__pyx_t_6);
+      __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
     } else {
-      __pyx_t_5 = PyObject_GetAttr(__pyx_cur_scope->__pyx_v_w, __pyx_n_s__encode); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 2; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-      __Pyx_GOTREF(__pyx_t_5);
-      __pyx_t_7 = PyObject_Call(__pyx_t_5, ((PyObject *)__pyx_k_tuple_9), NULL); if (unlikely(!__pyx_t_7)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 2; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      Py_ssize_t index = -1;
+      __pyx_t_7 = PyObject_GetIter(__pyx_t_2); if (unlikely(!__pyx_t_7)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 116; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
       __Pyx_GOTREF(__pyx_t_7);
-      __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
-      __pyx_t_4 = __pyx_t_7;
-      __pyx_t_7 = 0;
+      __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+      __pyx_t_8 = Py_TYPE(__pyx_t_7)->tp_iternext;
+      index = 0; __pyx_t_5 = __pyx_t_8(__pyx_t_7); if (unlikely(!__pyx_t_5)) goto __pyx_L5_unpacking_failed;
+      __Pyx_GOTREF(__pyx_t_5);
+      index = 1; __pyx_t_6 = __pyx_t_8(__pyx_t_7); if (unlikely(!__pyx_t_6)) goto __pyx_L5_unpacking_failed;
+      __Pyx_GOTREF(__pyx_t_6);
+      if (__Pyx_IternextUnpackEndCheck(__pyx_t_8(__pyx_t_7), 2) < 0) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 116; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;
+      goto __pyx_L6_unpacking_done;
+      __pyx_L5_unpacking_failed:;
+      __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;
+      if (PyErr_Occurred() && PyErr_ExceptionMatches(PyExc_StopIteration)) PyErr_Clear();
+      if (!PyErr_Occurred()) __Pyx_RaiseNeedMoreValuesError(index);
+      {__pyx_filename = __pyx_f[2]; __pyx_lineno = 116; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __pyx_L6_unpacking_done:;
     }
-    __pyx_r = __pyx_t_4;
-    __pyx_t_4 = 0;
-    __Pyx_XGIVEREF(__pyx_t_1);
-    __pyx_cur_scope->__pyx_t_0 = __pyx_t_1;
-    __pyx_cur_scope->__pyx_t_1 = __pyx_t_2;
-    __pyx_cur_scope->__pyx_t_2 = __pyx_t_3;
-    __Pyx_XGIVEREF(__pyx_r);
-    __Pyx_RefNannyFinishContext();
-    /* return from generator, yielding value */
-    __pyx_generator->resume_label = 1;
-    return __pyx_r;
-    __pyx_L6_resume_from_yield:;
-    __pyx_t_1 = __pyx_cur_scope->__pyx_t_0;
-    __pyx_cur_scope->__pyx_t_0 = 0;
-    __Pyx_XGOTREF(__pyx_t_1);
-    __pyx_t_2 = __pyx_cur_scope->__pyx_t_1;
-    __pyx_t_3 = __pyx_cur_scope->__pyx_t_2;
-    if (unlikely(!__pyx_sent_value)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 2; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  }
-  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
-  PyErr_SetNone(PyExc_StopIteration);
-  goto __pyx_L0;
-  __pyx_L1_error:;
-  __Pyx_XDECREF(__pyx_t_1);
-  __Pyx_XDECREF(__pyx_t_4);
-  __Pyx_XDECREF(__pyx_t_5);
-  __Pyx_XDECREF(__pyx_t_7);
-  __Pyx_AddTraceback("genexpr", __pyx_clineno, __pyx_lineno, __pyx_filename);
-  __pyx_L0:;
-  __Pyx_XDECREF(__pyx_r);
-  __pyx_generator->resume_label = -1;
-  __Pyx_RefNannyFinishContext();
-  return NULL;
-}
+    __pyx_t_9 = __pyx_PyFloat_AsFloat(__pyx_t_6); if (unlikely((__pyx_t_9 == (float)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 116; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0;
+    __Pyx_XDECREF(__pyx_v_fname);
+    __pyx_v_fname = __pyx_t_5;
+    __pyx_t_5 = 0;
+    __pyx_v_fval = __pyx_t_9;
 
-/* "/Users/vchahun/Sandbox/cdec/python/src/trule.pxi":1
- * def _phrase(phrase):             # <<<<<<<<<<<<<<
- *     return ' '.join('[%s,%d]' % w if isinstance(w, tuple) else w.encode('utf8') for w in phrase)
- * 
+    /* "/Users/vchahun/Sandbox/cdec/python/src/grammar.pxi":117
+ *             cdef float fval
+ *             for fname, fval in scores.items():
+ *                 fid = FDConvert(<char *>as_str(fname))             # <<<<<<<<<<<<<<
+ *                 if fid < 0: raise KeyError(fname)
+ *                 scores_.set_value(fid, fval)
  */
+    __pyx_v_fid = FD::Convert(((char *)__pyx_f_5_cdec_as_str(__pyx_v_fname, NULL)));
 
-static PyObject *__pyx_pf_5_cdec__phrase(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_phrase) {
-  struct __pyx_obj_5_cdec___pyx_scope_struct_8__phrase *__pyx_cur_scope;
-  PyObject *__pyx_r = NULL;
-  __Pyx_RefNannyDeclarations
-  PyObject *__pyx_t_1 = NULL;
-  PyObject *__pyx_t_2 = NULL;
-  PyObject *__pyx_t_3 = NULL;
-  int __pyx_lineno = 0;
-  const char *__pyx_filename = NULL;
-  int __pyx_clineno = 0;
-  __Pyx_RefNannySetupContext("_phrase", 0);
-  __pyx_cur_scope = (struct __pyx_obj_5_cdec___pyx_scope_struct_8__phrase *)__pyx_ptype_5_cdec___pyx_scope_struct_8__phrase->tp_new(__pyx_ptype_5_cdec___pyx_scope_struct_8__phrase, __pyx_empty_tuple, NULL);
-  if (unlikely(!__pyx_cur_scope)) {
-    __Pyx_RefNannyFinishContext();
-    return NULL;
-  }
-  __Pyx_GOTREF(__pyx_cur_scope);
-  __pyx_cur_scope->__pyx_v_phrase = __pyx_v_phrase;
-  __Pyx_INCREF(__pyx_cur_scope->__pyx_v_phrase);
-  __Pyx_GIVEREF(__pyx_cur_scope->__pyx_v_phrase);
+    /* "/Users/vchahun/Sandbox/cdec/python/src/grammar.pxi":118
+ *             for fname, fval in scores.items():
+ *                 fid = FDConvert(<char *>as_str(fname))
+ *                 if fid < 0: raise KeyError(fname)             # <<<<<<<<<<<<<<
+ *                 scores_.set_value(fid, fval)
+ * 
+ */
+    __pyx_t_10 = (__pyx_v_fid < 0);
+    if (__pyx_t_10) {
+      __pyx_t_2 = PyTuple_New(1); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 118; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __Pyx_GOTREF(__pyx_t_2);
+      __Pyx_INCREF(__pyx_v_fname);
+      PyTuple_SET_ITEM(__pyx_t_2, 0, __pyx_v_fname);
+      __Pyx_GIVEREF(__pyx_v_fname);
+      __pyx_t_6 = PyObject_Call(__pyx_builtin_KeyError, ((PyObject *)__pyx_t_2), NULL); if (unlikely(!__pyx_t_6)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 118; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __Pyx_GOTREF(__pyx_t_6);
+      __Pyx_DECREF(((PyObject *)__pyx_t_2)); __pyx_t_2 = 0;
+      __Pyx_Raise(__pyx_t_6, 0, 0, 0);
+      __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0;
+      {__pyx_filename = __pyx_f[2]; __pyx_lineno = 118; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      goto __pyx_L7;
+    }
+    __pyx_L7:;
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/trule.pxi":2
- * def _phrase(phrase):
- *     return ' '.join('[%s,%d]' % w if isinstance(w, tuple) else w.encode('utf8') for w in phrase)             # <<<<<<<<<<<<<<
+    /* "/Users/vchahun/Sandbox/cdec/python/src/grammar.pxi":119
+ *                 fid = FDConvert(<char *>as_str(fname))
+ *                 if fid < 0: raise KeyError(fname)
+ *                 scores_.set_value(fid, fval)             # <<<<<<<<<<<<<<
  * 
- * cdef class TRule:
+ *     property lhs:
  */
-  __Pyx_XDECREF(__pyx_r);
-  __pyx_t_1 = PyObject_GetAttr(((PyObject *)__pyx_kp_s_10), __pyx_n_s__join); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 2; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __Pyx_GOTREF(__pyx_t_1);
-  __pyx_t_2 = __pyx_pf_5_cdec_7_phrase_genexpr(((PyObject*)__pyx_cur_scope)); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 2; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __Pyx_GOTREF(__pyx_t_2);
-  __pyx_t_3 = PyTuple_New(1); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 2; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __Pyx_GOTREF(__pyx_t_3);
-  PyTuple_SET_ITEM(__pyx_t_3, 0, __pyx_t_2);
-  __Pyx_GIVEREF(__pyx_t_2);
-  __pyx_t_2 = 0;
-  __pyx_t_2 = PyObject_Call(__pyx_t_1, ((PyObject *)__pyx_t_3), NULL); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 2; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __Pyx_GOTREF(__pyx_t_2);
+    __pyx_v_scores_->set_value(__pyx_v_fid, __pyx_v_fval);
+  }
   __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
-  __Pyx_DECREF(((PyObject *)__pyx_t_3)); __pyx_t_3 = 0;
-  __pyx_r = __pyx_t_2;
-  __pyx_t_2 = 0;
-  goto __pyx_L0;
 
-  __pyx_r = Py_None; __Pyx_INCREF(Py_None);
+  __pyx_r = 0;
   goto __pyx_L0;
   __pyx_L1_error:;
   __Pyx_XDECREF(__pyx_t_1);
   __Pyx_XDECREF(__pyx_t_2);
-  __Pyx_XDECREF(__pyx_t_3);
-  __Pyx_AddTraceback("_cdec._phrase", __pyx_clineno, __pyx_lineno, __pyx_filename);
-  __pyx_r = NULL;
+  __Pyx_XDECREF(__pyx_t_5);
+  __Pyx_XDECREF(__pyx_t_6);
+  __Pyx_XDECREF(__pyx_t_7);
+  __Pyx_AddTraceback("_cdec.BaseTRule.scores.__set__", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __pyx_r = -1;
   __pyx_L0:;
-  __Pyx_DECREF(((PyObject *)__pyx_cur_scope));
-  __Pyx_XGIVEREF(__pyx_r);
+  __Pyx_XDECREF(__pyx_v_fname);
   __Pyx_RefNannyFinishContext();
   return __pyx_r;
 }
 
 /* Python wrapper */
-static PyObject *__pyx_pw_5_cdec_5TRule_5arity_1__get__(PyObject *__pyx_v_self); /*proto*/
-static PyObject *__pyx_pw_5_cdec_5TRule_5arity_1__get__(PyObject *__pyx_v_self) {
+static PyObject *__pyx_pw_5_cdec_9BaseTRule_3lhs_1__get__(PyObject *__pyx_v_self); /*proto*/
+static PyObject *__pyx_pw_5_cdec_9BaseTRule_3lhs_1__get__(PyObject *__pyx_v_self) {
   PyObject *__pyx_r = 0;
   __Pyx_RefNannyDeclarations
   __Pyx_RefNannySetupContext("__get__ (wrapper)", 0);
-  __pyx_r = __pyx_pf_5_cdec_5TRule_5arity___get__(((struct __pyx_obj_5_cdec_TRule *)__pyx_v_self));
+  __pyx_r = __pyx_pf_5_cdec_9BaseTRule_3lhs___get__(((struct __pyx_obj_5_cdec_BaseTRule *)__pyx_v_self));
   __Pyx_RefNannyFinishContext();
   return __pyx_r;
 }
 
-/* "/Users/vchahun/Sandbox/cdec/python/src/trule.pxi":8
+/* "/Users/vchahun/Sandbox/cdec/python/src/grammar.pxi":122
  * 
- *     property arity:
+ *     property lhs:
  *         def __get__(self):             # <<<<<<<<<<<<<<
- *             return self.rule.arity_
+ *             return NT(TDConvert(-self.rule.get().lhs_))
  * 
  */
 
-static PyObject *__pyx_pf_5_cdec_5TRule_5arity___get__(struct __pyx_obj_5_cdec_TRule *__pyx_v_self) {
+static PyObject *__pyx_pf_5_cdec_9BaseTRule_3lhs___get__(struct __pyx_obj_5_cdec_BaseTRule *__pyx_v_self) {
   PyObject *__pyx_r = NULL;
   __Pyx_RefNannyDeclarations
   PyObject *__pyx_t_1 = NULL;
+  PyObject *__pyx_t_2 = NULL;
   int __pyx_lineno = 0;
   const char *__pyx_filename = NULL;
   int __pyx_clineno = 0;
   __Pyx_RefNannySetupContext("__get__", 0);
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/trule.pxi":9
- *     property arity:
+  /* "/Users/vchahun/Sandbox/cdec/python/src/grammar.pxi":123
+ *     property lhs:
  *         def __get__(self):
- *             return self.rule.arity_             # <<<<<<<<<<<<<<
+ *             return NT(TDConvert(-self.rule.get().lhs_))             # <<<<<<<<<<<<<<
  * 
- *     property f:
+ *         def __set__(self, lhs):
  */
   __Pyx_XDECREF(__pyx_r);
-  __pyx_t_1 = PyInt_FromLong(__pyx_v_self->rule->arity_); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 9; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_1 = PyBytes_FromString(TD::Convert((-__pyx_v_self->rule->get()->lhs_))); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 123; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(((PyObject *)__pyx_t_1));
+  __pyx_t_2 = PyTuple_New(1); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 123; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_2);
+  PyTuple_SET_ITEM(__pyx_t_2, 0, ((PyObject *)__pyx_t_1));
+  __Pyx_GIVEREF(((PyObject *)__pyx_t_1));
+  __pyx_t_1 = 0;
+  __pyx_t_1 = PyObject_Call(((PyObject *)((PyObject*)__pyx_ptype_5_cdec_NT)), ((PyObject *)__pyx_t_2), NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 123; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __Pyx_GOTREF(__pyx_t_1);
+  __Pyx_DECREF(((PyObject *)__pyx_t_2)); __pyx_t_2 = 0;
   __pyx_r = __pyx_t_1;
   __pyx_t_1 = 0;
   goto __pyx_L0;
@@ -6430,7 +6397,8 @@ static PyObject *__pyx_pf_5_cdec_5TRule_5arity___get__(struct __pyx_obj_5_cdec_T
   goto __pyx_L0;
   __pyx_L1_error:;
   __Pyx_XDECREF(__pyx_t_1);
-  __Pyx_AddTraceback("_cdec.TRule.arity.__get__", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __Pyx_XDECREF(__pyx_t_2);
+  __Pyx_AddTraceback("_cdec.BaseTRule.lhs.__get__", __pyx_clineno, __pyx_lineno, __pyx_filename);
   __pyx_r = NULL;
   __pyx_L0:;
   __Pyx_XGIVEREF(__pyx_r);
@@ -6439,552 +6407,648 @@ static PyObject *__pyx_pf_5_cdec_5TRule_5arity___get__(struct __pyx_obj_5_cdec_T
 }
 
 /* Python wrapper */
-static PyObject *__pyx_pw_5_cdec_5TRule_1f_1__get__(PyObject *__pyx_v_self); /*proto*/
-static PyObject *__pyx_pw_5_cdec_5TRule_1f_1__get__(PyObject *__pyx_v_self) {
-  PyObject *__pyx_r = 0;
+static int __pyx_pw_5_cdec_9BaseTRule_3lhs_3__set__(PyObject *__pyx_v_self, PyObject *__pyx_v_lhs); /*proto*/
+static int __pyx_pw_5_cdec_9BaseTRule_3lhs_3__set__(PyObject *__pyx_v_self, PyObject *__pyx_v_lhs) {
+  int __pyx_r;
   __Pyx_RefNannyDeclarations
-  __Pyx_RefNannySetupContext("__get__ (wrapper)", 0);
-  __pyx_r = __pyx_pf_5_cdec_5TRule_1f___get__(((struct __pyx_obj_5_cdec_TRule *)__pyx_v_self));
+  __Pyx_RefNannySetupContext("__set__ (wrapper)", 0);
+  __pyx_r = __pyx_pf_5_cdec_9BaseTRule_3lhs_2__set__(((struct __pyx_obj_5_cdec_BaseTRule *)__pyx_v_self), ((PyObject *)__pyx_v_lhs));
   __Pyx_RefNannyFinishContext();
   return __pyx_r;
 }
 
-/* "/Users/vchahun/Sandbox/cdec/python/src/trule.pxi":12
+/* "/Users/vchahun/Sandbox/cdec/python/src/grammar.pxi":125
+ *             return NT(TDConvert(-self.rule.get().lhs_))
  * 
- *     property f:
- *         def __get__(self):             # <<<<<<<<<<<<<<
- *             cdef vector[WordID]* f = &self.rule.f_
- *             cdef WordID w
+ *         def __set__(self, lhs):             # <<<<<<<<<<<<<<
+ *             if not isinstance(lhs, NT):
+ *                 lhs = NT(lhs)
  */
 
-static PyObject *__pyx_pf_5_cdec_5TRule_1f___get__(struct __pyx_obj_5_cdec_TRule *__pyx_v_self) {
-  std::vector<WordID> *__pyx_v_f;
-  WordID __pyx_v_w;
-  PyObject *__pyx_v_words = 0;
-  unsigned int __pyx_v_i;
-  int __pyx_v_idx;
-  PyObject *__pyx_r = NULL;
+static int __pyx_pf_5_cdec_9BaseTRule_3lhs_2__set__(struct __pyx_obj_5_cdec_BaseTRule *__pyx_v_self, PyObject *__pyx_v_lhs) {
+  int __pyx_r;
   __Pyx_RefNannyDeclarations
   PyObject *__pyx_t_1 = NULL;
-  size_t __pyx_t_2;
-  unsigned int __pyx_t_3;
-  int __pyx_t_4;
-  PyObject *__pyx_t_5 = NULL;
-  PyObject *__pyx_t_6 = NULL;
+  int __pyx_t_2;
+  int __pyx_t_3;
+  PyObject *__pyx_t_4 = NULL;
+  char *__pyx_t_5;
   int __pyx_lineno = 0;
   const char *__pyx_filename = NULL;
   int __pyx_clineno = 0;
-  __Pyx_RefNannySetupContext("__get__", 0);
-
-  /* "/Users/vchahun/Sandbox/cdec/python/src/trule.pxi":13
- *     property f:
- *         def __get__(self):
- *             cdef vector[WordID]* f = &self.rule.f_             # <<<<<<<<<<<<<<
- *             cdef WordID w
- *             cdef words = []
- */
-  __pyx_v_f = (&__pyx_v_self->rule->f_);
+  __Pyx_RefNannySetupContext("__set__", 0);
+  __Pyx_INCREF(__pyx_v_lhs);
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/trule.pxi":15
- *             cdef vector[WordID]* f = &self.rule.f_
- *             cdef WordID w
- *             cdef words = []             # <<<<<<<<<<<<<<
- *             cdef unsigned i
- *             cdef int idx = 0
+  /* "/Users/vchahun/Sandbox/cdec/python/src/grammar.pxi":126
+ * 
+ *         def __set__(self, lhs):
+ *             if not isinstance(lhs, NT):             # <<<<<<<<<<<<<<
+ *                 lhs = NT(lhs)
+ *             self.rule.get().lhs_ = -TDConvert(<char *>lhs.cat)
  */
-  __pyx_t_1 = PyList_New(0); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 15; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __Pyx_GOTREF(__pyx_t_1);
-  __pyx_v_words = ((PyObject *)__pyx_t_1);
-  __pyx_t_1 = 0;
+  __pyx_t_1 = ((PyObject *)((PyObject*)__pyx_ptype_5_cdec_NT));
+  __Pyx_INCREF(__pyx_t_1);
+  __pyx_t_2 = __Pyx_TypeCheck(__pyx_v_lhs, __pyx_t_1); 
+  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+  __pyx_t_3 = (!__pyx_t_2);
+  if (__pyx_t_3) {
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/trule.pxi":17
- *             cdef words = []
- *             cdef unsigned i
- *             cdef int idx = 0             # <<<<<<<<<<<<<<
- *             for i in range(f.size()):
- *                 w = f[0][i]
+    /* "/Users/vchahun/Sandbox/cdec/python/src/grammar.pxi":127
+ *         def __set__(self, lhs):
+ *             if not isinstance(lhs, NT):
+ *                 lhs = NT(lhs)             # <<<<<<<<<<<<<<
+ *             self.rule.get().lhs_ = -TDConvert(<char *>lhs.cat)
+ * 
  */
-  __pyx_v_idx = 0;
+    __pyx_t_1 = PyTuple_New(1); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 127; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_1);
+    __Pyx_INCREF(__pyx_v_lhs);
+    PyTuple_SET_ITEM(__pyx_t_1, 0, __pyx_v_lhs);
+    __Pyx_GIVEREF(__pyx_v_lhs);
+    __pyx_t_4 = PyObject_Call(((PyObject *)((PyObject*)__pyx_ptype_5_cdec_NT)), ((PyObject *)__pyx_t_1), NULL); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 127; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_4);
+    __Pyx_DECREF(((PyObject *)__pyx_t_1)); __pyx_t_1 = 0;
+    __Pyx_DECREF(__pyx_v_lhs);
+    __pyx_v_lhs = __pyx_t_4;
+    __pyx_t_4 = 0;
+    goto __pyx_L3;
+  }
+  __pyx_L3:;
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/trule.pxi":18
- *             cdef unsigned i
- *             cdef int idx = 0
- *             for i in range(f.size()):             # <<<<<<<<<<<<<<
- *                 w = f[0][i]
- *                 if w < 0:
+  /* "/Users/vchahun/Sandbox/cdec/python/src/grammar.pxi":128
+ *             if not isinstance(lhs, NT):
+ *                 lhs = NT(lhs)
+ *             self.rule.get().lhs_ = -TDConvert(<char *>lhs.cat)             # <<<<<<<<<<<<<<
+ * 
+ *     def __str__(self):
  */
-  __pyx_t_2 = __pyx_v_f->size();
-  for (__pyx_t_3 = 0; __pyx_t_3 < __pyx_t_2; __pyx_t_3+=1) {
-    __pyx_v_i = __pyx_t_3;
+  __pyx_t_4 = PyObject_GetAttr(__pyx_v_lhs, __pyx_n_s__cat); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 128; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_4);
+  __pyx_t_5 = PyBytes_AsString(__pyx_t_4); if (unlikely((!__pyx_t_5) && PyErr_Occurred())) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 128; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
+  __pyx_v_self->rule->get()->lhs_ = (-TD::Convert(((char *)__pyx_t_5)));
 
-    /* "/Users/vchahun/Sandbox/cdec/python/src/trule.pxi":19
- *             cdef int idx = 0
- *             for i in range(f.size()):
- *                 w = f[0][i]             # <<<<<<<<<<<<<<
- *                 if w < 0:
- *                     idx += 1
- */
-    __pyx_v_w = ((__pyx_v_f[0])[__pyx_v_i]);
+  __pyx_r = 0;
+  goto __pyx_L0;
+  __pyx_L1_error:;
+  __Pyx_XDECREF(__pyx_t_1);
+  __Pyx_XDECREF(__pyx_t_4);
+  __Pyx_AddTraceback("_cdec.BaseTRule.lhs.__set__", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __pyx_r = -1;
+  __pyx_L0:;
+  __Pyx_XDECREF(__pyx_v_lhs);
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
 
-    /* "/Users/vchahun/Sandbox/cdec/python/src/trule.pxi":20
- *             for i in range(f.size()):
- *                 w = f[0][i]
- *                 if w < 0:             # <<<<<<<<<<<<<<
- *                     idx += 1
- *                     words.append((TDConvert(-w), idx))
- */
-    __pyx_t_4 = (__pyx_v_w < 0);
-    if (__pyx_t_4) {
+/* Python wrapper */
+static PyObject *__pyx_pw_5_cdec_9BaseTRule_3__str__(PyObject *__pyx_v_self); /*proto*/
+static PyObject *__pyx_pw_5_cdec_9BaseTRule_3__str__(PyObject *__pyx_v_self) {
+  PyObject *__pyx_r = 0;
+  __Pyx_RefNannyDeclarations
+  __Pyx_RefNannySetupContext("__str__ (wrapper)", 0);
+  __pyx_r = __pyx_pf_5_cdec_9BaseTRule_2__str__(((struct __pyx_obj_5_cdec_BaseTRule *)__pyx_v_self));
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+static PyObject *__pyx_gb_5_cdec_9BaseTRule_7__str___2generator18(__pyx_GeneratorObject *__pyx_generator, PyObject *__pyx_sent_value); /* proto */
 
-      /* "/Users/vchahun/Sandbox/cdec/python/src/trule.pxi":21
- *                 w = f[0][i]
- *                 if w < 0:
- *                     idx += 1             # <<<<<<<<<<<<<<
- *                     words.append((TDConvert(-w), idx))
- *                 else:
+/* "/Users/vchahun/Sandbox/cdec/python/src/grammar.pxi":131
+ * 
+ *     def __str__(self):
+ *         scores = ' '.join('%s=%s' % feat for feat in self.scores)             # <<<<<<<<<<<<<<
+ *         return '%s ||| %s ||| %s ||| %s' % (self.lhs,
+ *                 _phrase(self.f), _phrase(self.e), scores)
  */
-      __pyx_v_idx = (__pyx_v_idx + 1);
 
-      /* "/Users/vchahun/Sandbox/cdec/python/src/trule.pxi":22
- *                 if w < 0:
- *                     idx += 1
- *                     words.append((TDConvert(-w), idx))             # <<<<<<<<<<<<<<
- *                 else:
- *                     words.append(unicode(TDConvert(w), encoding='utf8'))
- */
-      __pyx_t_1 = PyBytes_FromString(TD::Convert((-__pyx_v_w))); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 22; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-      __Pyx_GOTREF(((PyObject *)__pyx_t_1));
-      __pyx_t_5 = PyInt_FromLong(__pyx_v_idx); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 22; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-      __Pyx_GOTREF(__pyx_t_5);
-      __pyx_t_6 = PyTuple_New(2); if (unlikely(!__pyx_t_6)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 22; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-      __Pyx_GOTREF(__pyx_t_6);
-      PyTuple_SET_ITEM(__pyx_t_6, 0, ((PyObject *)__pyx_t_1));
-      __Pyx_GIVEREF(((PyObject *)__pyx_t_1));
-      PyTuple_SET_ITEM(__pyx_t_6, 1, __pyx_t_5);
-      __Pyx_GIVEREF(__pyx_t_5);
-      __pyx_t_1 = 0;
-      __pyx_t_5 = 0;
-      __pyx_t_5 = __Pyx_PyObject_Append(__pyx_v_words, ((PyObject *)__pyx_t_6)); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 22; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-      __Pyx_GOTREF(__pyx_t_5);
-      __Pyx_DECREF(((PyObject *)__pyx_t_6)); __pyx_t_6 = 0;
-      __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
-      goto __pyx_L5;
-    }
-    /*else*/ {
-
-      /* "/Users/vchahun/Sandbox/cdec/python/src/trule.pxi":24
- *                     words.append((TDConvert(-w), idx))
- *                 else:
- *                     words.append(unicode(TDConvert(w), encoding='utf8'))             # <<<<<<<<<<<<<<
- *             return words
- * 
- */
-      __pyx_t_5 = PyBytes_FromString(TD::Convert(__pyx_v_w)); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 24; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-      __Pyx_GOTREF(((PyObject *)__pyx_t_5));
-      __pyx_t_6 = PyTuple_New(1); if (unlikely(!__pyx_t_6)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 24; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-      __Pyx_GOTREF(__pyx_t_6);
-      PyTuple_SET_ITEM(__pyx_t_6, 0, ((PyObject *)__pyx_t_5));
-      __Pyx_GIVEREF(((PyObject *)__pyx_t_5));
-      __pyx_t_5 = 0;
-      __pyx_t_5 = PyDict_New(); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 24; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-      __Pyx_GOTREF(((PyObject *)__pyx_t_5));
-      if (PyDict_SetItem(__pyx_t_5, ((PyObject *)__pyx_n_s__encoding), ((PyObject *)__pyx_n_s__utf8)) < 0) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 24; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-      __pyx_t_1 = PyObject_Call(((PyObject *)((PyObject*)(&PyUnicode_Type))), ((PyObject *)__pyx_t_6), ((PyObject *)__pyx_t_5)); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 24; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-      __Pyx_GOTREF(__pyx_t_1);
-      __Pyx_DECREF(((PyObject *)__pyx_t_6)); __pyx_t_6 = 0;
-      __Pyx_DECREF(((PyObject *)__pyx_t_5)); __pyx_t_5 = 0;
-      __pyx_t_5 = __Pyx_PyObject_Append(__pyx_v_words, __pyx_t_1); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 24; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-      __Pyx_GOTREF(__pyx_t_5);
-      __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
-      __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
-    }
-    __pyx_L5:;
+static PyObject *__pyx_pf_5_cdec_9BaseTRule_7__str___genexpr(PyObject *__pyx_self) {
+  struct __pyx_obj_5_cdec___pyx_scope_struct_6_genexpr *__pyx_cur_scope;
+  PyObject *__pyx_r = NULL;
+  __Pyx_RefNannyDeclarations
+  int __pyx_lineno = 0;
+  const char *__pyx_filename = NULL;
+  int __pyx_clineno = 0;
+  __Pyx_RefNannySetupContext("genexpr", 0);
+  __pyx_cur_scope = (struct __pyx_obj_5_cdec___pyx_scope_struct_6_genexpr *)__pyx_ptype_5_cdec___pyx_scope_struct_6_genexpr->tp_new(__pyx_ptype_5_cdec___pyx_scope_struct_6_genexpr, __pyx_empty_tuple, NULL);
+  if (unlikely(!__pyx_cur_scope)) {
+    __Pyx_RefNannyFinishContext();
+    return NULL;
+  }
+  __Pyx_GOTREF(__pyx_cur_scope);
+  __pyx_cur_scope->__pyx_outer_scope = (struct __pyx_obj_5_cdec___pyx_scope_struct_5___str__ *) __pyx_self;
+  __Pyx_INCREF(((PyObject *)__pyx_cur_scope->__pyx_outer_scope));
+  __Pyx_GIVEREF(__pyx_cur_scope->__pyx_outer_scope);
+  {
+    __pyx_GeneratorObject *gen = __Pyx_Generator_New((__pyx_generator_body_t) __pyx_gb_5_cdec_9BaseTRule_7__str___2generator18, (PyObject *) __pyx_cur_scope); if (unlikely(!gen)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 131; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_DECREF(__pyx_cur_scope);
+    __Pyx_RefNannyFinishContext();
+    return (PyObject *) gen;
   }
-
-  /* "/Users/vchahun/Sandbox/cdec/python/src/trule.pxi":25
- *                 else:
- *                     words.append(unicode(TDConvert(w), encoding='utf8'))
- *             return words             # <<<<<<<<<<<<<<
- * 
- *     property e:
- */
-  __Pyx_XDECREF(__pyx_r);
-  __Pyx_INCREF(__pyx_v_words);
-  __pyx_r = __pyx_v_words;
-  goto __pyx_L0;
 
   __pyx_r = Py_None; __Pyx_INCREF(Py_None);
   goto __pyx_L0;
   __pyx_L1_error:;
-  __Pyx_XDECREF(__pyx_t_1);
-  __Pyx_XDECREF(__pyx_t_5);
-  __Pyx_XDECREF(__pyx_t_6);
-  __Pyx_AddTraceback("_cdec.TRule.f.__get__", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __Pyx_AddTraceback("_cdec.BaseTRule.__str__.genexpr", __pyx_clineno, __pyx_lineno, __pyx_filename);
   __pyx_r = NULL;
   __pyx_L0:;
-  __Pyx_XDECREF(__pyx_v_words);
+  __Pyx_DECREF(((PyObject *)__pyx_cur_scope));
   __Pyx_XGIVEREF(__pyx_r);
   __Pyx_RefNannyFinishContext();
   return __pyx_r;
 }
 
-/* Python wrapper */
-static PyObject *__pyx_pw_5_cdec_5TRule_1e_1__get__(PyObject *__pyx_v_self); /*proto*/
-static PyObject *__pyx_pw_5_cdec_5TRule_1e_1__get__(PyObject *__pyx_v_self) {
-  PyObject *__pyx_r = 0;
+static PyObject *__pyx_gb_5_cdec_9BaseTRule_7__str___2generator18(__pyx_GeneratorObject *__pyx_generator, PyObject *__pyx_sent_value) /* generator body */
+{
+  struct __pyx_obj_5_cdec___pyx_scope_struct_6_genexpr *__pyx_cur_scope = ((struct __pyx_obj_5_cdec___pyx_scope_struct_6_genexpr *)__pyx_generator->closure);
+  PyObject *__pyx_r = NULL;
+  PyObject *__pyx_t_1 = NULL;
+  PyObject *__pyx_t_2 = NULL;
+  Py_ssize_t __pyx_t_3;
+  PyObject *(*__pyx_t_4)(PyObject *);
   __Pyx_RefNannyDeclarations
-  __Pyx_RefNannySetupContext("__get__ (wrapper)", 0);
-  __pyx_r = __pyx_pf_5_cdec_5TRule_1e___get__(((struct __pyx_obj_5_cdec_TRule *)__pyx_v_self));
+  __Pyx_RefNannySetupContext("None", 0);
+  switch (__pyx_generator->resume_label) {
+    case 0: goto __pyx_L3_first_run;
+    case 1: goto __pyx_L6_resume_from_yield;
+    default: /* CPython raises the right error here */
+    __Pyx_RefNannyFinishContext();
+    return NULL;
+  }
+  __pyx_L3_first_run:;
+  if (unlikely(!__pyx_sent_value)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 131; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (unlikely(!__pyx_cur_scope->__pyx_outer_scope->__pyx_v_self)) { __Pyx_RaiseClosureNameError("self"); {__pyx_filename = __pyx_f[2]; __pyx_lineno = 131; __pyx_clineno = __LINE__; goto __pyx_L1_error;} }
+  __pyx_t_1 = PyObject_GetAttr(((PyObject *)__pyx_cur_scope->__pyx_outer_scope->__pyx_v_self), __pyx_n_s__scores); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 131; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_1);
+  if (PyList_CheckExact(__pyx_t_1) || PyTuple_CheckExact(__pyx_t_1)) {
+    __pyx_t_2 = __pyx_t_1; __Pyx_INCREF(__pyx_t_2); __pyx_t_3 = 0;
+    __pyx_t_4 = NULL;
+  } else {
+    __pyx_t_3 = -1; __pyx_t_2 = PyObject_GetIter(__pyx_t_1); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 131; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_2);
+    __pyx_t_4 = Py_TYPE(__pyx_t_2)->tp_iternext;
+  }
+  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+  for (;;) {
+    if (!__pyx_t_4 && PyList_CheckExact(__pyx_t_2)) {
+      if (__pyx_t_3 >= PyList_GET_SIZE(__pyx_t_2)) break;
+      __pyx_t_1 = PyList_GET_ITEM(__pyx_t_2, __pyx_t_3); __Pyx_INCREF(__pyx_t_1); __pyx_t_3++;
+    } else if (!__pyx_t_4 && PyTuple_CheckExact(__pyx_t_2)) {
+      if (__pyx_t_3 >= PyTuple_GET_SIZE(__pyx_t_2)) break;
+      __pyx_t_1 = PyTuple_GET_ITEM(__pyx_t_2, __pyx_t_3); __Pyx_INCREF(__pyx_t_1); __pyx_t_3++;
+    } else {
+      __pyx_t_1 = __pyx_t_4(__pyx_t_2);
+      if (unlikely(!__pyx_t_1)) {
+        if (PyErr_Occurred()) {
+          if (likely(PyErr_ExceptionMatches(PyExc_StopIteration))) PyErr_Clear();
+          else {__pyx_filename = __pyx_f[2]; __pyx_lineno = 131; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+        }
+        break;
+      }
+      __Pyx_GOTREF(__pyx_t_1);
+    }
+    __Pyx_XGOTREF(__pyx_cur_scope->__pyx_v_feat);
+    __Pyx_XDECREF(__pyx_cur_scope->__pyx_v_feat);
+    __Pyx_GIVEREF(__pyx_t_1);
+    __pyx_cur_scope->__pyx_v_feat = __pyx_t_1;
+    __pyx_t_1 = 0;
+    __pyx_t_1 = PyNumber_Remainder(((PyObject *)__pyx_kp_s_11), __pyx_cur_scope->__pyx_v_feat); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 131; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(((PyObject *)__pyx_t_1));
+    __pyx_r = ((PyObject *)__pyx_t_1);
+    __pyx_t_1 = 0;
+    __Pyx_XGIVEREF(__pyx_t_2);
+    __pyx_cur_scope->__pyx_t_0 = __pyx_t_2;
+    __pyx_cur_scope->__pyx_t_1 = __pyx_t_3;
+    __pyx_cur_scope->__pyx_t_2 = __pyx_t_4;
+    __Pyx_XGIVEREF(__pyx_r);
+    __Pyx_RefNannyFinishContext();
+    /* return from generator, yielding value */
+    __pyx_generator->resume_label = 1;
+    return __pyx_r;
+    __pyx_L6_resume_from_yield:;
+    __pyx_t_2 = __pyx_cur_scope->__pyx_t_0;
+    __pyx_cur_scope->__pyx_t_0 = 0;
+    __Pyx_XGOTREF(__pyx_t_2);
+    __pyx_t_3 = __pyx_cur_scope->__pyx_t_1;
+    __pyx_t_4 = __pyx_cur_scope->__pyx_t_2;
+    if (unlikely(!__pyx_sent_value)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 131; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  }
+  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+  PyErr_SetNone(PyExc_StopIteration);
+  goto __pyx_L0;
+  __pyx_L1_error:;
+  __Pyx_XDECREF(__pyx_t_1);
+  __Pyx_XDECREF(__pyx_t_2);
+  __Pyx_AddTraceback("genexpr", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __pyx_L0:;
+  __Pyx_XDECREF(__pyx_r);
+  __pyx_generator->resume_label = -1;
   __Pyx_RefNannyFinishContext();
-  return __pyx_r;
+  return NULL;
 }
 
-/* "/Users/vchahun/Sandbox/cdec/python/src/trule.pxi":28
+/* "/Users/vchahun/Sandbox/cdec/python/src/grammar.pxi":130
+ *             self.rule.get().lhs_ = -TDConvert(<char *>lhs.cat)
  * 
- *     property e:
- *         def __get__(self):             # <<<<<<<<<<<<<<
- *             cdef vector[WordID]* e = &self.rule.e_
- *             cdef WordID w
+ *     def __str__(self):             # <<<<<<<<<<<<<<
+ *         scores = ' '.join('%s=%s' % feat for feat in self.scores)
+ *         return '%s ||| %s ||| %s ||| %s' % (self.lhs,
  */
 
-static PyObject *__pyx_pf_5_cdec_5TRule_1e___get__(struct __pyx_obj_5_cdec_TRule *__pyx_v_self) {
-  std::vector<WordID> *__pyx_v_e;
-  WordID __pyx_v_w;
-  PyObject *__pyx_v_words = 0;
-  unsigned int __pyx_v_i;
-  int __pyx_v_idx;
+static PyObject *__pyx_pf_5_cdec_9BaseTRule_2__str__(struct __pyx_obj_5_cdec_BaseTRule *__pyx_v_self) {
+  struct __pyx_obj_5_cdec___pyx_scope_struct_5___str__ *__pyx_cur_scope;
+  PyObject *__pyx_v_scores = NULL;
   PyObject *__pyx_r = NULL;
   __Pyx_RefNannyDeclarations
   PyObject *__pyx_t_1 = NULL;
-  size_t __pyx_t_2;
-  unsigned int __pyx_t_3;
-  int __pyx_t_4;
+  PyObject *__pyx_t_2 = NULL;
+  PyObject *__pyx_t_3 = NULL;
+  PyObject *__pyx_t_4 = NULL;
   PyObject *__pyx_t_5 = NULL;
-  PyObject *__pyx_t_6 = NULL;
   int __pyx_lineno = 0;
   const char *__pyx_filename = NULL;
   int __pyx_clineno = 0;
-  __Pyx_RefNannySetupContext("__get__", 0);
-
-  /* "/Users/vchahun/Sandbox/cdec/python/src/trule.pxi":29
- *     property e:
- *         def __get__(self):
- *             cdef vector[WordID]* e = &self.rule.e_             # <<<<<<<<<<<<<<
- *             cdef WordID w
- *             cdef words = []
- */
-  __pyx_v_e = (&__pyx_v_self->rule->e_);
+  __Pyx_RefNannySetupContext("__str__", 0);
+  __pyx_cur_scope = (struct __pyx_obj_5_cdec___pyx_scope_struct_5___str__ *)__pyx_ptype_5_cdec___pyx_scope_struct_5___str__->tp_new(__pyx_ptype_5_cdec___pyx_scope_struct_5___str__, __pyx_empty_tuple, NULL);
+  if (unlikely(!__pyx_cur_scope)) {
+    __Pyx_RefNannyFinishContext();
+    return NULL;
+  }
+  __Pyx_GOTREF(__pyx_cur_scope);
+  __pyx_cur_scope->__pyx_v_self = __pyx_v_self;
+  __Pyx_INCREF((PyObject *)__pyx_cur_scope->__pyx_v_self);
+  __Pyx_GIVEREF((PyObject *)__pyx_cur_scope->__pyx_v_self);
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/trule.pxi":31
- *             cdef vector[WordID]* e = &self.rule.e_
- *             cdef WordID w
- *             cdef words = []             # <<<<<<<<<<<<<<
- *             cdef unsigned i
- *             cdef int idx = 0
+  /* "/Users/vchahun/Sandbox/cdec/python/src/grammar.pxi":131
+ * 
+ *     def __str__(self):
+ *         scores = ' '.join('%s=%s' % feat for feat in self.scores)             # <<<<<<<<<<<<<<
+ *         return '%s ||| %s ||| %s ||| %s' % (self.lhs,
+ *                 _phrase(self.f), _phrase(self.e), scores)
  */
-  __pyx_t_1 = PyList_New(0); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 31; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_1 = PyObject_GetAttr(((PyObject *)__pyx_kp_s_7), __pyx_n_s__join); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 131; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __Pyx_GOTREF(__pyx_t_1);
-  __pyx_v_words = ((PyObject *)__pyx_t_1);
-  __pyx_t_1 = 0;
-
-  /* "/Users/vchahun/Sandbox/cdec/python/src/trule.pxi":33
- *             cdef words = []
- *             cdef unsigned i
- *             cdef int idx = 0             # <<<<<<<<<<<<<<
- *             for i in range(e.size()):
- *                 w = e[0][i]
- */
-  __pyx_v_idx = 0;
-
-  /* "/Users/vchahun/Sandbox/cdec/python/src/trule.pxi":34
- *             cdef unsigned i
- *             cdef int idx = 0
- *             for i in range(e.size()):             # <<<<<<<<<<<<<<
- *                 w = e[0][i]
- *                 if w < 1:
- */
-  __pyx_t_2 = __pyx_v_e->size();
-  for (__pyx_t_3 = 0; __pyx_t_3 < __pyx_t_2; __pyx_t_3+=1) {
-    __pyx_v_i = __pyx_t_3;
-
-    /* "/Users/vchahun/Sandbox/cdec/python/src/trule.pxi":35
- *             cdef int idx = 0
- *             for i in range(e.size()):
- *                 w = e[0][i]             # <<<<<<<<<<<<<<
- *                 if w < 1:
- *                     idx += 1
- */
-    __pyx_v_w = ((__pyx_v_e[0])[__pyx_v_i]);
-
-    /* "/Users/vchahun/Sandbox/cdec/python/src/trule.pxi":36
- *             for i in range(e.size()):
- *                 w = e[0][i]
- *                 if w < 1:             # <<<<<<<<<<<<<<
- *                     idx += 1
- *                     words.append((TDConvert(1-w), idx))
- */
-    __pyx_t_4 = (__pyx_v_w < 1);
-    if (__pyx_t_4) {
-
-      /* "/Users/vchahun/Sandbox/cdec/python/src/trule.pxi":37
- *                 w = e[0][i]
- *                 if w < 1:
- *                     idx += 1             # <<<<<<<<<<<<<<
- *                     words.append((TDConvert(1-w), idx))
- *                 else:
- */
-      __pyx_v_idx = (__pyx_v_idx + 1);
+  __pyx_t_2 = __pyx_pf_5_cdec_9BaseTRule_7__str___genexpr(((PyObject*)__pyx_cur_scope)); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 131; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_2);
+  __pyx_t_3 = PyTuple_New(1); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 131; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_3);
+  PyTuple_SET_ITEM(__pyx_t_3, 0, __pyx_t_2);
+  __Pyx_GIVEREF(__pyx_t_2);
+  __pyx_t_2 = 0;
+  __pyx_t_2 = PyObject_Call(__pyx_t_1, ((PyObject *)__pyx_t_3), NULL); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 131; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_2);
+  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+  __Pyx_DECREF(((PyObject *)__pyx_t_3)); __pyx_t_3 = 0;
+  __pyx_v_scores = __pyx_t_2;
+  __pyx_t_2 = 0;
 
-      /* "/Users/vchahun/Sandbox/cdec/python/src/trule.pxi":38
- *                 if w < 1:
- *                     idx += 1
- *                     words.append((TDConvert(1-w), idx))             # <<<<<<<<<<<<<<
- *                 else:
- *                     words.append(unicode(TDConvert(w), encoding='utf8'))
+  /* "/Users/vchahun/Sandbox/cdec/python/src/grammar.pxi":132
+ *     def __str__(self):
+ *         scores = ' '.join('%s=%s' % feat for feat in self.scores)
+ *         return '%s ||| %s ||| %s ||| %s' % (self.lhs,             # <<<<<<<<<<<<<<
+ *                 _phrase(self.f), _phrase(self.e), scores)
+ * 
  */
-      __pyx_t_1 = PyBytes_FromString(TD::Convert((1 - __pyx_v_w))); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 38; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-      __Pyx_GOTREF(((PyObject *)__pyx_t_1));
-      __pyx_t_5 = PyInt_FromLong(__pyx_v_idx); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 38; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-      __Pyx_GOTREF(__pyx_t_5);
-      __pyx_t_6 = PyTuple_New(2); if (unlikely(!__pyx_t_6)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 38; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-      __Pyx_GOTREF(__pyx_t_6);
-      PyTuple_SET_ITEM(__pyx_t_6, 0, ((PyObject *)__pyx_t_1));
-      __Pyx_GIVEREF(((PyObject *)__pyx_t_1));
-      PyTuple_SET_ITEM(__pyx_t_6, 1, __pyx_t_5);
-      __Pyx_GIVEREF(__pyx_t_5);
-      __pyx_t_1 = 0;
-      __pyx_t_5 = 0;
-      __pyx_t_5 = __Pyx_PyObject_Append(__pyx_v_words, ((PyObject *)__pyx_t_6)); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 38; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-      __Pyx_GOTREF(__pyx_t_5);
-      __Pyx_DECREF(((PyObject *)__pyx_t_6)); __pyx_t_6 = 0;
-      __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
-      goto __pyx_L5;
-    }
-    /*else*/ {
+  __Pyx_XDECREF(__pyx_r);
+  __pyx_t_2 = PyObject_GetAttr(((PyObject *)__pyx_cur_scope->__pyx_v_self), __pyx_n_s__lhs); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 132; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_2);
 
-      /* "/Users/vchahun/Sandbox/cdec/python/src/trule.pxi":40
- *                     words.append((TDConvert(1-w), idx))
- *                 else:
- *                     words.append(unicode(TDConvert(w), encoding='utf8'))             # <<<<<<<<<<<<<<
- *             return words
+  /* "/Users/vchahun/Sandbox/cdec/python/src/grammar.pxi":133
+ *         scores = ' '.join('%s=%s' % feat for feat in self.scores)
+ *         return '%s ||| %s ||| %s ||| %s' % (self.lhs,
+ *                 _phrase(self.f), _phrase(self.e), scores)             # <<<<<<<<<<<<<<
  * 
+ * cdef class TRule(BaseTRule):
  */
-      __pyx_t_5 = PyBytes_FromString(TD::Convert(__pyx_v_w)); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 40; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-      __Pyx_GOTREF(((PyObject *)__pyx_t_5));
-      __pyx_t_6 = PyTuple_New(1); if (unlikely(!__pyx_t_6)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 40; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-      __Pyx_GOTREF(__pyx_t_6);
-      PyTuple_SET_ITEM(__pyx_t_6, 0, ((PyObject *)__pyx_t_5));
-      __Pyx_GIVEREF(((PyObject *)__pyx_t_5));
-      __pyx_t_5 = 0;
-      __pyx_t_5 = PyDict_New(); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 40; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-      __Pyx_GOTREF(((PyObject *)__pyx_t_5));
-      if (PyDict_SetItem(__pyx_t_5, ((PyObject *)__pyx_n_s__encoding), ((PyObject *)__pyx_n_s__utf8)) < 0) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 40; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-      __pyx_t_1 = PyObject_Call(((PyObject *)((PyObject*)(&PyUnicode_Type))), ((PyObject *)__pyx_t_6), ((PyObject *)__pyx_t_5)); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 40; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-      __Pyx_GOTREF(__pyx_t_1);
-      __Pyx_DECREF(((PyObject *)__pyx_t_6)); __pyx_t_6 = 0;
-      __Pyx_DECREF(((PyObject *)__pyx_t_5)); __pyx_t_5 = 0;
-      __pyx_t_5 = __Pyx_PyObject_Append(__pyx_v_words, __pyx_t_1); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 40; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-      __Pyx_GOTREF(__pyx_t_5);
-      __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
-      __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
-    }
-    __pyx_L5:;
-  }
-
-  /* "/Users/vchahun/Sandbox/cdec/python/src/trule.pxi":41
- *                 else:
- *                     words.append(unicode(TDConvert(w), encoding='utf8'))
- *             return words             # <<<<<<<<<<<<<<
- * 
- *     property scores:
- */
-  __Pyx_XDECREF(__pyx_r);
-  __Pyx_INCREF(__pyx_v_words);
-  __pyx_r = __pyx_v_words;
+  __pyx_t_3 = __Pyx_GetName(__pyx_m, __pyx_n_s___phrase); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 133; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_3);
+  __pyx_t_1 = PyObject_GetAttr(((PyObject *)__pyx_cur_scope->__pyx_v_self), __pyx_n_s__f); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 133; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_1);
+  __pyx_t_4 = PyTuple_New(1); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 133; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_4);
+  PyTuple_SET_ITEM(__pyx_t_4, 0, __pyx_t_1);
+  __Pyx_GIVEREF(__pyx_t_1);
+  __pyx_t_1 = 0;
+  __pyx_t_1 = PyObject_Call(__pyx_t_3, ((PyObject *)__pyx_t_4), NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 133; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_1);
+  __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
+  __Pyx_DECREF(((PyObject *)__pyx_t_4)); __pyx_t_4 = 0;
+  __pyx_t_4 = __Pyx_GetName(__pyx_m, __pyx_n_s___phrase); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 133; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_4);
+  __pyx_t_3 = PyObject_GetAttr(((PyObject *)__pyx_cur_scope->__pyx_v_self), __pyx_n_s__e); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 133; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_3);
+  __pyx_t_5 = PyTuple_New(1); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 133; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_5);
+  PyTuple_SET_ITEM(__pyx_t_5, 0, __pyx_t_3);
+  __Pyx_GIVEREF(__pyx_t_3);
+  __pyx_t_3 = 0;
+  __pyx_t_3 = PyObject_Call(__pyx_t_4, ((PyObject *)__pyx_t_5), NULL); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 133; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_3);
+  __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
+  __Pyx_DECREF(((PyObject *)__pyx_t_5)); __pyx_t_5 = 0;
+  __pyx_t_5 = PyTuple_New(4); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 132; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_5);
+  PyTuple_SET_ITEM(__pyx_t_5, 0, __pyx_t_2);
+  __Pyx_GIVEREF(__pyx_t_2);
+  PyTuple_SET_ITEM(__pyx_t_5, 1, __pyx_t_1);
+  __Pyx_GIVEREF(__pyx_t_1);
+  PyTuple_SET_ITEM(__pyx_t_5, 2, __pyx_t_3);
+  __Pyx_GIVEREF(__pyx_t_3);
+  __Pyx_INCREF(__pyx_v_scores);
+  PyTuple_SET_ITEM(__pyx_t_5, 3, __pyx_v_scores);
+  __Pyx_GIVEREF(__pyx_v_scores);
+  __pyx_t_2 = 0;
+  __pyx_t_1 = 0;
+  __pyx_t_3 = 0;
+  __pyx_t_3 = PyNumber_Remainder(((PyObject *)__pyx_kp_s_12), ((PyObject *)__pyx_t_5)); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 132; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(((PyObject *)__pyx_t_3));
+  __Pyx_DECREF(((PyObject *)__pyx_t_5)); __pyx_t_5 = 0;
+  __pyx_r = ((PyObject *)__pyx_t_3);
+  __pyx_t_3 = 0;
   goto __pyx_L0;
 
   __pyx_r = Py_None; __Pyx_INCREF(Py_None);
   goto __pyx_L0;
   __pyx_L1_error:;
   __Pyx_XDECREF(__pyx_t_1);
+  __Pyx_XDECREF(__pyx_t_2);
+  __Pyx_XDECREF(__pyx_t_3);
+  __Pyx_XDECREF(__pyx_t_4);
   __Pyx_XDECREF(__pyx_t_5);
-  __Pyx_XDECREF(__pyx_t_6);
-  __Pyx_AddTraceback("_cdec.TRule.e.__get__", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __Pyx_AddTraceback("_cdec.BaseTRule.__str__", __pyx_clineno, __pyx_lineno, __pyx_filename);
   __pyx_r = NULL;
   __pyx_L0:;
-  __Pyx_XDECREF(__pyx_v_words);
+  __Pyx_XDECREF(__pyx_v_scores);
+  __Pyx_DECREF(((PyObject *)__pyx_cur_scope));
   __Pyx_XGIVEREF(__pyx_r);
   __Pyx_RefNannyFinishContext();
   return __pyx_r;
 }
 
 /* Python wrapper */
-static PyObject *__pyx_pw_5_cdec_5TRule_6scores_1__get__(PyObject *__pyx_v_self); /*proto*/
-static PyObject *__pyx_pw_5_cdec_5TRule_6scores_1__get__(PyObject *__pyx_v_self) {
-  PyObject *__pyx_r = 0;
+static int __pyx_pw_5_cdec_5TRule_1__cinit__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/
+static int __pyx_pw_5_cdec_5TRule_1__cinit__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) {
+  PyObject *__pyx_v_lhs = 0;
+  PyObject *__pyx_v_f = 0;
+  PyObject *__pyx_v_e = 0;
+  PyObject *__pyx_v_scores = 0;
+  PyObject *__pyx_v_a = 0;
+  static PyObject **__pyx_pyargnames[] = {&__pyx_n_s__lhs,&__pyx_n_s__f,&__pyx_n_s__e,&__pyx_n_s__scores,&__pyx_n_s__a,0};
+  int __pyx_r;
   __Pyx_RefNannyDeclarations
-  __Pyx_RefNannySetupContext("__get__ (wrapper)", 0);
-  __pyx_r = __pyx_pf_5_cdec_5TRule_6scores___get__(((struct __pyx_obj_5_cdec_TRule *)__pyx_v_self));
-  __Pyx_RefNannyFinishContext();
-  return __pyx_r;
-}
+  __Pyx_RefNannySetupContext("__cinit__ (wrapper)", 0);
+  {
+    PyObject* values[5] = {0,0,0,0,0};
 
-/* "/Users/vchahun/Sandbox/cdec/python/src/trule.pxi":44
+    /* "/Users/vchahun/Sandbox/cdec/python/src/grammar.pxi":136
  * 
- *     property scores:
- *         def __get__(self):             # <<<<<<<<<<<<<<
- *             cdef SparseVector scores = SparseVector()
- *             scores.vector = new FastSparseVector[double](self.rule.scores_)
+ * cdef class TRule(BaseTRule):
+ *     def __cinit__(self, lhs, f, e, scores, a=None):             # <<<<<<<<<<<<<<
+ *         self.rule = new shared_ptr[grammar.TRule](new grammar.TRule())
+ *         self.lhs = lhs
  */
+    values[4] = ((PyObject *)Py_None);
+    if (unlikely(__pyx_kwds)) {
+      Py_ssize_t kw_args;
+      const Py_ssize_t pos_args = PyTuple_GET_SIZE(__pyx_args);
+      switch (pos_args) {
+        case  5: values[4] = PyTuple_GET_ITEM(__pyx_args, 4);
+        case  4: values[3] = PyTuple_GET_ITEM(__pyx_args, 3);
+        case  3: values[2] = PyTuple_GET_ITEM(__pyx_args, 2);
+        case  2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1);
+        case  1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0);
+        case  0: break;
+        default: goto __pyx_L5_argtuple_error;
+      }
+      kw_args = PyDict_Size(__pyx_kwds);
+      switch (pos_args) {
+        case  0:
+        values[0] = PyDict_GetItem(__pyx_kwds, __pyx_n_s__lhs);
+        if (likely(values[0])) kw_args--;
+        else goto __pyx_L5_argtuple_error;
+        case  1:
+        values[1] = PyDict_GetItem(__pyx_kwds, __pyx_n_s__f);
+        if (likely(values[1])) kw_args--;
+        else {
+          __Pyx_RaiseArgtupleInvalid("__cinit__", 0, 4, 5, 1); {__pyx_filename = __pyx_f[2]; __pyx_lineno = 136; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+        }
+        case  2:
+        values[2] = PyDict_GetItem(__pyx_kwds, __pyx_n_s__e);
+        if (likely(values[2])) kw_args--;
+        else {
+          __Pyx_RaiseArgtupleInvalid("__cinit__", 0, 4, 5, 2); {__pyx_filename = __pyx_f[2]; __pyx_lineno = 136; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+        }
+        case  3:
+        values[3] = PyDict_GetItem(__pyx_kwds, __pyx_n_s__scores);
+        if (likely(values[3])) kw_args--;
+        else {
+          __Pyx_RaiseArgtupleInvalid("__cinit__", 0, 4, 5, 3); {__pyx_filename = __pyx_f[2]; __pyx_lineno = 136; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+        }
+        case  4:
+        if (kw_args > 0) {
+          PyObject* value = PyDict_GetItem(__pyx_kwds, __pyx_n_s__a);
+          if (value) { values[4] = value; kw_args--; }
+        }
+      }
+      if (unlikely(kw_args > 0)) {
+        if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "__cinit__") < 0)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 136; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+      }
+    } else {
+      switch (PyTuple_GET_SIZE(__pyx_args)) {
+        case  5: values[4] = PyTuple_GET_ITEM(__pyx_args, 4);
+        case  4: values[3] = PyTuple_GET_ITEM(__pyx_args, 3);
+        values[2] = PyTuple_GET_ITEM(__pyx_args, 2);
+        values[1] = PyTuple_GET_ITEM(__pyx_args, 1);
+        values[0] = PyTuple_GET_ITEM(__pyx_args, 0);
+        break;
+        default: goto __pyx_L5_argtuple_error;
+      }
+    }
+    __pyx_v_lhs = values[0];
+    __pyx_v_f = values[1];
+    __pyx_v_e = values[2];
+    __pyx_v_scores = values[3];
+    __pyx_v_a = values[4];
+  }
+  goto __pyx_L4_argument_unpacking_done;
+  __pyx_L5_argtuple_error:;
+  __Pyx_RaiseArgtupleInvalid("__cinit__", 0, 4, 5, PyTuple_GET_SIZE(__pyx_args)); {__pyx_filename = __pyx_f[2]; __pyx_lineno = 136; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+  __pyx_L3_error:;
+  __Pyx_AddTraceback("_cdec.TRule.__cinit__", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __Pyx_RefNannyFinishContext();
+  return -1;
+  __pyx_L4_argument_unpacking_done:;
+  __pyx_r = __pyx_pf_5_cdec_5TRule___cinit__(((struct __pyx_obj_5_cdec_TRule *)__pyx_v_self), __pyx_v_lhs, __pyx_v_f, __pyx_v_e, __pyx_v_scores, __pyx_v_a);
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
 
-static PyObject *__pyx_pf_5_cdec_5TRule_6scores___get__(struct __pyx_obj_5_cdec_TRule *__pyx_v_self) {
-  struct __pyx_obj_5_cdec_SparseVector *__pyx_v_scores = 0;
-  PyObject *__pyx_r = NULL;
+static int __pyx_pf_5_cdec_5TRule___cinit__(struct __pyx_obj_5_cdec_TRule *__pyx_v_self, PyObject *__pyx_v_lhs, PyObject *__pyx_v_f, PyObject *__pyx_v_e, PyObject *__pyx_v_scores, PyObject *__pyx_v_a) {
+  int __pyx_r;
   __Pyx_RefNannyDeclarations
-  PyObject *__pyx_t_1 = NULL;
+  int __pyx_t_1;
   int __pyx_lineno = 0;
   const char *__pyx_filename = NULL;
   int __pyx_clineno = 0;
-  __Pyx_RefNannySetupContext("__get__", 0);
+  __Pyx_RefNannySetupContext("__cinit__", 0);
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/trule.pxi":45
- *     property scores:
- *         def __get__(self):
- *             cdef SparseVector scores = SparseVector()             # <<<<<<<<<<<<<<
- *             scores.vector = new FastSparseVector[double](self.rule.scores_)
- *             return scores
- */
-  __pyx_t_1 = PyObject_Call(((PyObject *)((PyObject*)__pyx_ptype_5_cdec_SparseVector)), ((PyObject *)__pyx_empty_tuple), NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 45; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __Pyx_GOTREF(__pyx_t_1);
-  __pyx_v_scores = ((struct __pyx_obj_5_cdec_SparseVector *)__pyx_t_1);
-  __pyx_t_1 = 0;
+  /* "/Users/vchahun/Sandbox/cdec/python/src/grammar.pxi":137
+ * cdef class TRule(BaseTRule):
+ *     def __cinit__(self, lhs, f, e, scores, a=None):
+ *         self.rule = new shared_ptr[grammar.TRule](new grammar.TRule())             # <<<<<<<<<<<<<<
+ *         self.lhs = lhs
+ *         self.e = e
+ */
+  __pyx_v_self->__pyx_base.rule = new boost::shared_ptr<TRule>(new TRule());
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/grammar.pxi":138
+ *     def __cinit__(self, lhs, f, e, scores, a=None):
+ *         self.rule = new shared_ptr[grammar.TRule](new grammar.TRule())
+ *         self.lhs = lhs             # <<<<<<<<<<<<<<
+ *         self.e = e
+ *         self.f = f
+ */
+  if (PyObject_SetAttr(((PyObject *)__pyx_v_self), __pyx_n_s__lhs, __pyx_v_lhs) < 0) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 138; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/grammar.pxi":139
+ *         self.rule = new shared_ptr[grammar.TRule](new grammar.TRule())
+ *         self.lhs = lhs
+ *         self.e = e             # <<<<<<<<<<<<<<
+ *         self.f = f
+ *         self.scores = scores
+ */
+  if (PyObject_SetAttr(((PyObject *)__pyx_v_self), __pyx_n_s__e, __pyx_v_e) < 0) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 139; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/grammar.pxi":140
+ *         self.lhs = lhs
+ *         self.e = e
+ *         self.f = f             # <<<<<<<<<<<<<<
+ *         self.scores = scores
+ *         if a:
+ */
+  if (PyObject_SetAttr(((PyObject *)__pyx_v_self), __pyx_n_s__f, __pyx_v_f) < 0) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 140; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/grammar.pxi":141
+ *         self.e = e
+ *         self.f = f
+ *         self.scores = scores             # <<<<<<<<<<<<<<
+ *         if a:
+ *             self.a = a
+ */
+  if (PyObject_SetAttr(((PyObject *)__pyx_v_self), __pyx_n_s__scores, __pyx_v_scores) < 0) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 141; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/grammar.pxi":142
+ *         self.f = f
+ *         self.scores = scores
+ *         if a:             # <<<<<<<<<<<<<<
+ *             self.a = a
+ *         self.rule.get().ComputeArity()
+ */
+  __pyx_t_1 = __Pyx_PyObject_IsTrue(__pyx_v_a); if (unlikely(__pyx_t_1 < 0)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 142; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (__pyx_t_1) {
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/trule.pxi":46
- *         def __get__(self):
- *             cdef SparseVector scores = SparseVector()
- *             scores.vector = new FastSparseVector[double](self.rule.scores_)             # <<<<<<<<<<<<<<
- *             return scores
+    /* "/Users/vchahun/Sandbox/cdec/python/src/grammar.pxi":143
+ *         self.scores = scores
+ *         if a:
+ *             self.a = a             # <<<<<<<<<<<<<<
+ *         self.rule.get().ComputeArity()
  * 
  */
-  __pyx_v_scores->vector = new FastSparseVector<double>(__pyx_v_self->rule->scores_);
+    if (PyObject_SetAttr(((PyObject *)__pyx_v_self), __pyx_n_s__a, __pyx_v_a) < 0) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 143; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    goto __pyx_L3;
+  }
+  __pyx_L3:;
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/trule.pxi":47
- *             cdef SparseVector scores = SparseVector()
- *             scores.vector = new FastSparseVector[double](self.rule.scores_)
- *             return scores             # <<<<<<<<<<<<<<
+  /* "/Users/vchahun/Sandbox/cdec/python/src/grammar.pxi":144
+ *         if a:
+ *             self.a = a
+ *         self.rule.get().ComputeArity()             # <<<<<<<<<<<<<<
  * 
- *     property lhs:
+ * cdef class Grammar:
  */
-  __Pyx_XDECREF(__pyx_r);
-  __Pyx_INCREF(((PyObject *)__pyx_v_scores));
-  __pyx_r = ((PyObject *)__pyx_v_scores);
-  goto __pyx_L0;
+  __pyx_v_self->__pyx_base.rule->get()->ComputeArity();
 
-  __pyx_r = Py_None; __Pyx_INCREF(Py_None);
+  __pyx_r = 0;
   goto __pyx_L0;
   __pyx_L1_error:;
-  __Pyx_XDECREF(__pyx_t_1);
-  __Pyx_AddTraceback("_cdec.TRule.scores.__get__", __pyx_clineno, __pyx_lineno, __pyx_filename);
-  __pyx_r = NULL;
+  __Pyx_AddTraceback("_cdec.TRule.__cinit__", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __pyx_r = -1;
   __pyx_L0:;
-  __Pyx_XDECREF((PyObject *)__pyx_v_scores);
-  __Pyx_XGIVEREF(__pyx_r);
   __Pyx_RefNannyFinishContext();
   return __pyx_r;
 }
 
 /* Python wrapper */
-static PyObject *__pyx_pw_5_cdec_5TRule_3lhs_1__get__(PyObject *__pyx_v_self); /*proto*/
-static PyObject *__pyx_pw_5_cdec_5TRule_3lhs_1__get__(PyObject *__pyx_v_self) {
-  PyObject *__pyx_r = 0;
+static void __pyx_pw_5_cdec_7Grammar_1__dealloc__(PyObject *__pyx_v_self); /*proto*/
+static void __pyx_pw_5_cdec_7Grammar_1__dealloc__(PyObject *__pyx_v_self) {
   __Pyx_RefNannyDeclarations
-  __Pyx_RefNannySetupContext("__get__ (wrapper)", 0);
-  __pyx_r = __pyx_pf_5_cdec_5TRule_3lhs___get__(((struct __pyx_obj_5_cdec_TRule *)__pyx_v_self));
+  __Pyx_RefNannySetupContext("__dealloc__ (wrapper)", 0);
+  __pyx_pf_5_cdec_7Grammar___dealloc__(((struct __pyx_obj_5_cdec_Grammar *)__pyx_v_self));
   __Pyx_RefNannyFinishContext();
-  return __pyx_r;
 }
 
-/* "/Users/vchahun/Sandbox/cdec/python/src/trule.pxi":50
+/* "/Users/vchahun/Sandbox/cdec/python/src/grammar.pxi":149
+ *     cdef shared_ptr[grammar.Grammar]* grammar
  * 
- *     property lhs:
- *         def __get__(self):             # <<<<<<<<<<<<<<
- *             return TDConvert(-self.rule.lhs_)
+ *     def __dealloc__(self):             # <<<<<<<<<<<<<<
+ *         del self.grammar
  * 
  */
 
-static PyObject *__pyx_pf_5_cdec_5TRule_3lhs___get__(struct __pyx_obj_5_cdec_TRule *__pyx_v_self) {
-  PyObject *__pyx_r = NULL;
+static void __pyx_pf_5_cdec_7Grammar___dealloc__(CYTHON_UNUSED struct __pyx_obj_5_cdec_Grammar *__pyx_v_self) {
   __Pyx_RefNannyDeclarations
-  PyObject *__pyx_t_1 = NULL;
-  int __pyx_lineno = 0;
-  const char *__pyx_filename = NULL;
-  int __pyx_clineno = 0;
-  __Pyx_RefNannySetupContext("__get__", 0);
+  __Pyx_RefNannySetupContext("__dealloc__", 0);
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/trule.pxi":51
- *     property lhs:
- *         def __get__(self):
- *             return TDConvert(-self.rule.lhs_)             # <<<<<<<<<<<<<<
+  /* "/Users/vchahun/Sandbox/cdec/python/src/grammar.pxi":150
  * 
- *     def __str__(self):
+ *     def __dealloc__(self):
+ *         del self.grammar             # <<<<<<<<<<<<<<
+ * 
+ *     def __iter__(self):
  */
-  __Pyx_XDECREF(__pyx_r);
-  __pyx_t_1 = PyBytes_FromString(TD::Convert((-__pyx_v_self->rule->lhs_))); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 51; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __Pyx_GOTREF(((PyObject *)__pyx_t_1));
-  __pyx_r = ((PyObject *)__pyx_t_1);
-  __pyx_t_1 = 0;
-  goto __pyx_L0;
+  delete __pyx_v_self->grammar;
 
-  __pyx_r = Py_None; __Pyx_INCREF(Py_None);
-  goto __pyx_L0;
-  __pyx_L1_error:;
-  __Pyx_XDECREF(__pyx_t_1);
-  __Pyx_AddTraceback("_cdec.TRule.lhs.__get__", __pyx_clineno, __pyx_lineno, __pyx_filename);
-  __pyx_r = NULL;
-  __pyx_L0:;
-  __Pyx_XGIVEREF(__pyx_r);
   __Pyx_RefNannyFinishContext();
-  return __pyx_r;
 }
+static PyObject *__pyx_gb_5_cdec_7Grammar_4generator3(__pyx_GeneratorObject *__pyx_generator, PyObject *__pyx_sent_value); /* proto */
 
 /* Python wrapper */
-static PyObject *__pyx_pw_5_cdec_5TRule_1__str__(PyObject *__pyx_v_self); /*proto*/
-static PyObject *__pyx_pw_5_cdec_5TRule_1__str__(PyObject *__pyx_v_self) {
+static PyObject *__pyx_pw_5_cdec_7Grammar_3__iter__(PyObject *__pyx_v_self); /*proto*/
+static PyObject *__pyx_pw_5_cdec_7Grammar_3__iter__(PyObject *__pyx_v_self) {
   PyObject *__pyx_r = 0;
   __Pyx_RefNannyDeclarations
-  __Pyx_RefNannySetupContext("__str__ (wrapper)", 0);
-  __pyx_r = __pyx_pf_5_cdec_5TRule___str__(((struct __pyx_obj_5_cdec_TRule *)__pyx_v_self));
+  __Pyx_RefNannySetupContext("__iter__ (wrapper)", 0);
+  __pyx_r = __pyx_pf_5_cdec_7Grammar_2__iter__(((struct __pyx_obj_5_cdec_Grammar *)__pyx_v_self));
   __Pyx_RefNannyFinishContext();
   return __pyx_r;
 }
-static PyObject *__pyx_gb_5_cdec_5TRule_7__str___2generator16(__pyx_GeneratorObject *__pyx_generator, PyObject *__pyx_sent_value); /* proto */
 
-/* "/Users/vchahun/Sandbox/cdec/python/src/trule.pxi":54
+/* "/Users/vchahun/Sandbox/cdec/python/src/grammar.pxi":152
+ *         del self.grammar
  * 
- *     def __str__(self):
- *         scores = ' '.join('%s=%s' % feat for feat in self.scores)             # <<<<<<<<<<<<<<
- *         return '[%s] ||| %s ||| %s ||| %s' % (self.lhs, _phrase(self.f), _phrase(self.e), scores)
+ *     def __iter__(self):             # <<<<<<<<<<<<<<
+ *         cdef grammar.GrammarIter* root = self.grammar.get().GetRoot()
+ *         cdef grammar.RuleBin* rbin = root.GetRules()
  */
 
-static PyObject *__pyx_pf_5_cdec_5TRule_7__str___genexpr(PyObject *__pyx_self) {
-  struct __pyx_obj_5_cdec___pyx_scope_struct_11_genexpr *__pyx_cur_scope;
+static PyObject *__pyx_pf_5_cdec_7Grammar_2__iter__(struct __pyx_obj_5_cdec_Grammar *__pyx_v_self) {
+  struct __pyx_obj_5_cdec___pyx_scope_struct_7___iter__ *__pyx_cur_scope;
   PyObject *__pyx_r = NULL;
   __Pyx_RefNannyDeclarations
   int __pyx_lineno = 0;
   const char *__pyx_filename = NULL;
   int __pyx_clineno = 0;
-  __Pyx_RefNannySetupContext("genexpr", 0);
-  __pyx_cur_scope = (struct __pyx_obj_5_cdec___pyx_scope_struct_11_genexpr *)__pyx_ptype_5_cdec___pyx_scope_struct_11_genexpr->tp_new(__pyx_ptype_5_cdec___pyx_scope_struct_11_genexpr, __pyx_empty_tuple, NULL);
+  __Pyx_RefNannySetupContext("__iter__", 0);
+  __pyx_cur_scope = (struct __pyx_obj_5_cdec___pyx_scope_struct_7___iter__ *)__pyx_ptype_5_cdec___pyx_scope_struct_7___iter__->tp_new(__pyx_ptype_5_cdec___pyx_scope_struct_7___iter__, __pyx_empty_tuple, NULL);
   if (unlikely(!__pyx_cur_scope)) {
     __Pyx_RefNannyFinishContext();
     return NULL;
   }
   __Pyx_GOTREF(__pyx_cur_scope);
-  __pyx_cur_scope->__pyx_outer_scope = (struct __pyx_obj_5_cdec___pyx_scope_struct_10___str__ *) __pyx_self;
-  __Pyx_INCREF(((PyObject *)__pyx_cur_scope->__pyx_outer_scope));
-  __Pyx_GIVEREF(__pyx_cur_scope->__pyx_outer_scope);
+  __pyx_cur_scope->__pyx_v_self = __pyx_v_self;
+  __Pyx_INCREF((PyObject *)__pyx_cur_scope->__pyx_v_self);
+  __Pyx_GIVEREF((PyObject *)__pyx_cur_scope->__pyx_v_self);
   {
-    __pyx_GeneratorObject *gen = __Pyx_Generator_New((__pyx_generator_body_t) __pyx_gb_5_cdec_5TRule_7__str___2generator16, (PyObject *) __pyx_cur_scope); if (unlikely(!gen)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 54; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_GeneratorObject *gen = __Pyx_Generator_New((__pyx_generator_body_t) __pyx_gb_5_cdec_7Grammar_4generator3, (PyObject *) __pyx_cur_scope); if (unlikely(!gen)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 152; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
     __Pyx_DECREF(__pyx_cur_scope);
     __Pyx_RefNannyFinishContext();
     return (PyObject *) gen;
@@ -6993,7 +7057,7 @@ static PyObject *__pyx_pf_5_cdec_5TRule_7__str___genexpr(PyObject *__pyx_self) {
   __pyx_r = Py_None; __Pyx_INCREF(Py_None);
   goto __pyx_L0;
   __pyx_L1_error:;
-  __Pyx_AddTraceback("_cdec.TRule.__str__.genexpr", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __Pyx_AddTraceback("_cdec.Grammar.__iter__", __pyx_clineno, __pyx_lineno, __pyx_filename);
   __pyx_r = NULL;
   __pyx_L0:;
   __Pyx_DECREF(((PyObject *)__pyx_cur_scope));
@@ -7002,14 +7066,13 @@ static PyObject *__pyx_pf_5_cdec_5TRule_7__str___genexpr(PyObject *__pyx_self) {
   return __pyx_r;
 }
 
-static PyObject *__pyx_gb_5_cdec_5TRule_7__str___2generator16(__pyx_GeneratorObject *__pyx_generator, PyObject *__pyx_sent_value) /* generator body */
+static PyObject *__pyx_gb_5_cdec_7Grammar_4generator3(__pyx_GeneratorObject *__pyx_generator, PyObject *__pyx_sent_value) /* generator body */
 {
-  struct __pyx_obj_5_cdec___pyx_scope_struct_11_genexpr *__pyx_cur_scope = ((struct __pyx_obj_5_cdec___pyx_scope_struct_11_genexpr *)__pyx_generator->closure);
+  struct __pyx_obj_5_cdec___pyx_scope_struct_7___iter__ *__pyx_cur_scope = ((struct __pyx_obj_5_cdec___pyx_scope_struct_7___iter__ *)__pyx_generator->closure);
   PyObject *__pyx_r = NULL;
-  PyObject *__pyx_t_1 = NULL;
-  PyObject *__pyx_t_2 = NULL;
-  Py_ssize_t __pyx_t_3;
-  PyObject *(*__pyx_t_4)(PyObject *);
+  int __pyx_t_1;
+  unsigned int __pyx_t_2;
+  PyObject *__pyx_t_3 = NULL;
   __Pyx_RefNannyDeclarations
   __Pyx_RefNannySetupContext("None", 0);
   switch (__pyx_generator->resume_label) {
@@ -7020,564 +7083,477 @@ static PyObject *__pyx_gb_5_cdec_5TRule_7__str___2generator16(__pyx_GeneratorObj
     return NULL;
   }
   __pyx_L3_first_run:;
-  if (unlikely(!__pyx_sent_value)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 54; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  if (unlikely(!__pyx_cur_scope->__pyx_outer_scope->__pyx_v_self)) { __Pyx_RaiseClosureNameError("self"); {__pyx_filename = __pyx_f[4]; __pyx_lineno = 54; __pyx_clineno = __LINE__; goto __pyx_L1_error;} }
-  __pyx_t_1 = PyObject_GetAttr(((PyObject *)__pyx_cur_scope->__pyx_outer_scope->__pyx_v_self), __pyx_n_s__scores); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 54; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __Pyx_GOTREF(__pyx_t_1);
-  if (PyList_CheckExact(__pyx_t_1) || PyTuple_CheckExact(__pyx_t_1)) {
-    __pyx_t_2 = __pyx_t_1; __Pyx_INCREF(__pyx_t_2); __pyx_t_3 = 0;
-    __pyx_t_4 = NULL;
-  } else {
-    __pyx_t_3 = -1; __pyx_t_2 = PyObject_GetIter(__pyx_t_1); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 54; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-    __Pyx_GOTREF(__pyx_t_2);
-    __pyx_t_4 = Py_TYPE(__pyx_t_2)->tp_iternext;
-  }
-  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
-  for (;;) {
-    if (!__pyx_t_4 && PyList_CheckExact(__pyx_t_2)) {
-      if (__pyx_t_3 >= PyList_GET_SIZE(__pyx_t_2)) break;
-      __pyx_t_1 = PyList_GET_ITEM(__pyx_t_2, __pyx_t_3); __Pyx_INCREF(__pyx_t_1); __pyx_t_3++;
-    } else if (!__pyx_t_4 && PyTuple_CheckExact(__pyx_t_2)) {
-      if (__pyx_t_3 >= PyTuple_GET_SIZE(__pyx_t_2)) break;
-      __pyx_t_1 = PyTuple_GET_ITEM(__pyx_t_2, __pyx_t_3); __Pyx_INCREF(__pyx_t_1); __pyx_t_3++;
-    } else {
-      __pyx_t_1 = __pyx_t_4(__pyx_t_2);
-      if (unlikely(!__pyx_t_1)) {
-        if (PyErr_Occurred()) {
-          if (likely(PyErr_ExceptionMatches(PyExc_StopIteration))) PyErr_Clear();
-          else {__pyx_filename = __pyx_f[4]; __pyx_lineno = 54; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-        }
-        break;
-      }
-      __Pyx_GOTREF(__pyx_t_1);
-    }
-    __Pyx_XGOTREF(__pyx_cur_scope->__pyx_v_feat);
-    __Pyx_XDECREF(__pyx_cur_scope->__pyx_v_feat);
-    __Pyx_GIVEREF(__pyx_t_1);
-    __pyx_cur_scope->__pyx_v_feat = __pyx_t_1;
-    __pyx_t_1 = 0;
-    __pyx_t_1 = PyNumber_Remainder(((PyObject *)__pyx_kp_s_11), __pyx_cur_scope->__pyx_v_feat); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 54; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-    __Pyx_GOTREF(((PyObject *)__pyx_t_1));
-    __pyx_r = ((PyObject *)__pyx_t_1);
-    __pyx_t_1 = 0;
-    __Pyx_XGIVEREF(__pyx_t_2);
-    __pyx_cur_scope->__pyx_t_0 = __pyx_t_2;
-    __pyx_cur_scope->__pyx_t_1 = __pyx_t_3;
-    __pyx_cur_scope->__pyx_t_2 = __pyx_t_4;
-    __Pyx_XGIVEREF(__pyx_r);
-    __Pyx_RefNannyFinishContext();
-    /* return from generator, yielding value */
-    __pyx_generator->resume_label = 1;
-    return __pyx_r;
-    __pyx_L6_resume_from_yield:;
-    __pyx_t_2 = __pyx_cur_scope->__pyx_t_0;
-    __pyx_cur_scope->__pyx_t_0 = 0;
-    __Pyx_XGOTREF(__pyx_t_2);
-    __pyx_t_3 = __pyx_cur_scope->__pyx_t_1;
-    __pyx_t_4 = __pyx_cur_scope->__pyx_t_2;
-    if (unlikely(!__pyx_sent_value)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 54; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  }
-  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
-  PyErr_SetNone(PyExc_StopIteration);
-  goto __pyx_L0;
-  __pyx_L1_error:;
-  __Pyx_XDECREF(__pyx_t_1);
-  __Pyx_XDECREF(__pyx_t_2);
-  __Pyx_AddTraceback("genexpr", __pyx_clineno, __pyx_lineno, __pyx_filename);
-  __pyx_L0:;
-  __Pyx_XDECREF(__pyx_r);
-  __pyx_generator->resume_label = -1;
-  __Pyx_RefNannyFinishContext();
-  return NULL;
-}
+  if (unlikely(!__pyx_sent_value)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 152; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
 
-/* "/Users/vchahun/Sandbox/cdec/python/src/trule.pxi":53
- *             return TDConvert(-self.rule.lhs_)
+  /* "/Users/vchahun/Sandbox/cdec/python/src/grammar.pxi":153
  * 
- *     def __str__(self):             # <<<<<<<<<<<<<<
- *         scores = ' '.join('%s=%s' % feat for feat in self.scores)
- *         return '[%s] ||| %s ||| %s ||| %s' % (self.lhs, _phrase(self.f), _phrase(self.e), scores)
+ *     def __iter__(self):
+ *         cdef grammar.GrammarIter* root = self.grammar.get().GetRoot()             # <<<<<<<<<<<<<<
+ *         cdef grammar.RuleBin* rbin = root.GetRules()
+ *         cdef TRule trule
  */
+  __pyx_cur_scope->__pyx_v_root = __pyx_cur_scope->__pyx_v_self->grammar->get()->GetRoot();
 
-static PyObject *__pyx_pf_5_cdec_5TRule___str__(struct __pyx_obj_5_cdec_TRule *__pyx_v_self) {
-  struct __pyx_obj_5_cdec___pyx_scope_struct_10___str__ *__pyx_cur_scope;
-  PyObject *__pyx_v_scores = NULL;
-  PyObject *__pyx_r = NULL;
-  __Pyx_RefNannyDeclarations
-  PyObject *__pyx_t_1 = NULL;
-  PyObject *__pyx_t_2 = NULL;
-  PyObject *__pyx_t_3 = NULL;
-  PyObject *__pyx_t_4 = NULL;
-  PyObject *__pyx_t_5 = NULL;
-  int __pyx_lineno = 0;
-  const char *__pyx_filename = NULL;
-  int __pyx_clineno = 0;
-  __Pyx_RefNannySetupContext("__str__", 0);
-  __pyx_cur_scope = (struct __pyx_obj_5_cdec___pyx_scope_struct_10___str__ *)__pyx_ptype_5_cdec___pyx_scope_struct_10___str__->tp_new(__pyx_ptype_5_cdec___pyx_scope_struct_10___str__, __pyx_empty_tuple, NULL);
-  if (unlikely(!__pyx_cur_scope)) {
-    __Pyx_RefNannyFinishContext();
-    return NULL;
-  }
-  __Pyx_GOTREF(__pyx_cur_scope);
-  __pyx_cur_scope->__pyx_v_self = __pyx_v_self;
-  __Pyx_INCREF((PyObject *)__pyx_cur_scope->__pyx_v_self);
-  __Pyx_GIVEREF((PyObject *)__pyx_cur_scope->__pyx_v_self);
+  /* "/Users/vchahun/Sandbox/cdec/python/src/grammar.pxi":154
+ *     def __iter__(self):
+ *         cdef grammar.GrammarIter* root = self.grammar.get().GetRoot()
+ *         cdef grammar.RuleBin* rbin = root.GetRules()             # <<<<<<<<<<<<<<
+ *         cdef TRule trule
+ *         cdef unsigned i
+ */
+  __pyx_cur_scope->__pyx_v_rbin = __pyx_cur_scope->__pyx_v_root->GetRules();
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/trule.pxi":54
- * 
- *     def __str__(self):
- *         scores = ' '.join('%s=%s' % feat for feat in self.scores)             # <<<<<<<<<<<<<<
- *         return '[%s] ||| %s ||| %s ||| %s' % (self.lhs, _phrase(self.f), _phrase(self.e), scores)
+  /* "/Users/vchahun/Sandbox/cdec/python/src/grammar.pxi":157
+ *         cdef TRule trule
+ *         cdef unsigned i
+ *         for i in range(rbin.GetNumRules()):             # <<<<<<<<<<<<<<
+ *             trule = TRule()
+ *             trule.rule = new shared_ptr[grammar.TRule](rbin.GetIthRule(i))
  */
-  __pyx_t_1 = PyObject_GetAttr(((PyObject *)__pyx_kp_s_10), __pyx_n_s__join); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 54; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __Pyx_GOTREF(__pyx_t_1);
-  __pyx_t_2 = __pyx_pf_5_cdec_5TRule_7__str___genexpr(((PyObject*)__pyx_cur_scope)); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 54; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __Pyx_GOTREF(__pyx_t_2);
-  __pyx_t_3 = PyTuple_New(1); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 54; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __Pyx_GOTREF(__pyx_t_3);
-  PyTuple_SET_ITEM(__pyx_t_3, 0, __pyx_t_2);
-  __Pyx_GIVEREF(__pyx_t_2);
-  __pyx_t_2 = 0;
-  __pyx_t_2 = PyObject_Call(__pyx_t_1, ((PyObject *)__pyx_t_3), NULL); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 54; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __Pyx_GOTREF(__pyx_t_2);
-  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
-  __Pyx_DECREF(((PyObject *)__pyx_t_3)); __pyx_t_3 = 0;
-  __pyx_v_scores = __pyx_t_2;
-  __pyx_t_2 = 0;
+  __pyx_t_1 = __pyx_cur_scope->__pyx_v_rbin->GetNumRules();
+  for (__pyx_t_2 = 0; __pyx_t_2 < __pyx_t_1; __pyx_t_2+=1) {
+    __pyx_cur_scope->__pyx_v_i = __pyx_t_2;
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/trule.pxi":55
- *     def __str__(self):
- *         scores = ' '.join('%s=%s' % feat for feat in self.scores)
- *         return '[%s] ||| %s ||| %s ||| %s' % (self.lhs, _phrase(self.f), _phrase(self.e), scores)             # <<<<<<<<<<<<<<
+    /* "/Users/vchahun/Sandbox/cdec/python/src/grammar.pxi":158
+ *         cdef unsigned i
+ *         for i in range(rbin.GetNumRules()):
+ *             trule = TRule()             # <<<<<<<<<<<<<<
+ *             trule.rule = new shared_ptr[grammar.TRule](rbin.GetIthRule(i))
+ *             yield trule
  */
-  __Pyx_XDECREF(__pyx_r);
-  __pyx_t_2 = PyObject_GetAttr(((PyObject *)__pyx_cur_scope->__pyx_v_self), __pyx_n_s__lhs); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 55; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __Pyx_GOTREF(__pyx_t_2);
-  __pyx_t_3 = __Pyx_GetName(__pyx_m, __pyx_n_s___phrase); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 55; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __Pyx_GOTREF(__pyx_t_3);
-  __pyx_t_1 = PyObject_GetAttr(((PyObject *)__pyx_cur_scope->__pyx_v_self), __pyx_n_s__f); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 55; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __Pyx_GOTREF(__pyx_t_1);
-  __pyx_t_4 = PyTuple_New(1); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 55; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __Pyx_GOTREF(__pyx_t_4);
-  PyTuple_SET_ITEM(__pyx_t_4, 0, __pyx_t_1);
-  __Pyx_GIVEREF(__pyx_t_1);
-  __pyx_t_1 = 0;
-  __pyx_t_1 = PyObject_Call(__pyx_t_3, ((PyObject *)__pyx_t_4), NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 55; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __Pyx_GOTREF(__pyx_t_1);
-  __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
-  __Pyx_DECREF(((PyObject *)__pyx_t_4)); __pyx_t_4 = 0;
-  __pyx_t_4 = __Pyx_GetName(__pyx_m, __pyx_n_s___phrase); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 55; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __Pyx_GOTREF(__pyx_t_4);
-  __pyx_t_3 = PyObject_GetAttr(((PyObject *)__pyx_cur_scope->__pyx_v_self), __pyx_n_s__e); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 55; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __Pyx_GOTREF(__pyx_t_3);
-  __pyx_t_5 = PyTuple_New(1); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 55; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __Pyx_GOTREF(__pyx_t_5);
-  PyTuple_SET_ITEM(__pyx_t_5, 0, __pyx_t_3);
-  __Pyx_GIVEREF(__pyx_t_3);
-  __pyx_t_3 = 0;
-  __pyx_t_3 = PyObject_Call(__pyx_t_4, ((PyObject *)__pyx_t_5), NULL); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 55; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __Pyx_GOTREF(__pyx_t_3);
-  __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
-  __Pyx_DECREF(((PyObject *)__pyx_t_5)); __pyx_t_5 = 0;
-  __pyx_t_5 = PyTuple_New(4); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 55; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __Pyx_GOTREF(__pyx_t_5);
-  PyTuple_SET_ITEM(__pyx_t_5, 0, __pyx_t_2);
-  __Pyx_GIVEREF(__pyx_t_2);
-  PyTuple_SET_ITEM(__pyx_t_5, 1, __pyx_t_1);
-  __Pyx_GIVEREF(__pyx_t_1);
-  PyTuple_SET_ITEM(__pyx_t_5, 2, __pyx_t_3);
-  __Pyx_GIVEREF(__pyx_t_3);
-  __Pyx_INCREF(__pyx_v_scores);
-  PyTuple_SET_ITEM(__pyx_t_5, 3, __pyx_v_scores);
-  __Pyx_GIVEREF(__pyx_v_scores);
-  __pyx_t_2 = 0;
-  __pyx_t_1 = 0;
-  __pyx_t_3 = 0;
-  __pyx_t_3 = PyNumber_Remainder(((PyObject *)__pyx_kp_s_12), ((PyObject *)__pyx_t_5)); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 55; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __Pyx_GOTREF(((PyObject *)__pyx_t_3));
-  __Pyx_DECREF(((PyObject *)__pyx_t_5)); __pyx_t_5 = 0;
-  __pyx_r = ((PyObject *)__pyx_t_3);
-  __pyx_t_3 = 0;
-  goto __pyx_L0;
+    __pyx_t_3 = PyObject_Call(((PyObject *)((PyObject*)__pyx_ptype_5_cdec_TRule)), ((PyObject *)__pyx_empty_tuple), NULL); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 158; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_3);
+    __Pyx_XGOTREF(((PyObject *)__pyx_cur_scope->__pyx_v_trule));
+    __Pyx_XDECREF(((PyObject *)__pyx_cur_scope->__pyx_v_trule));
+    __Pyx_GIVEREF(__pyx_t_3);
+    __pyx_cur_scope->__pyx_v_trule = ((struct __pyx_obj_5_cdec_TRule *)__pyx_t_3);
+    __pyx_t_3 = 0;
 
-  __pyx_r = Py_None; __Pyx_INCREF(Py_None);
+    /* "/Users/vchahun/Sandbox/cdec/python/src/grammar.pxi":159
+ *         for i in range(rbin.GetNumRules()):
+ *             trule = TRule()
+ *             trule.rule = new shared_ptr[grammar.TRule](rbin.GetIthRule(i))             # <<<<<<<<<<<<<<
+ *             yield trule
+ * 
+ */
+    __pyx_cur_scope->__pyx_v_trule->__pyx_base.rule = new boost::shared_ptr<TRule>(__pyx_cur_scope->__pyx_v_rbin->GetIthRule(__pyx_cur_scope->__pyx_v_i));
+
+    /* "/Users/vchahun/Sandbox/cdec/python/src/grammar.pxi":160
+ *             trule = TRule()
+ *             trule.rule = new shared_ptr[grammar.TRule](rbin.GetIthRule(i))
+ *             yield trule             # <<<<<<<<<<<<<<
+ * 
+ *     property name:
+ */
+    __Pyx_INCREF(((PyObject *)__pyx_cur_scope->__pyx_v_trule));
+    __pyx_r = ((PyObject *)__pyx_cur_scope->__pyx_v_trule);
+    __pyx_cur_scope->__pyx_t_0 = __pyx_t_1;
+    __pyx_cur_scope->__pyx_t_1 = __pyx_t_2;
+    __Pyx_XGIVEREF(__pyx_r);
+    __Pyx_RefNannyFinishContext();
+    /* return from generator, yielding value */
+    __pyx_generator->resume_label = 1;
+    return __pyx_r;
+    __pyx_L6_resume_from_yield:;
+    __pyx_t_1 = __pyx_cur_scope->__pyx_t_0;
+    __pyx_t_2 = __pyx_cur_scope->__pyx_t_1;
+    if (unlikely(!__pyx_sent_value)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 160; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  }
+  PyErr_SetNone(PyExc_StopIteration);
   goto __pyx_L0;
   __pyx_L1_error:;
-  __Pyx_XDECREF(__pyx_t_1);
-  __Pyx_XDECREF(__pyx_t_2);
   __Pyx_XDECREF(__pyx_t_3);
-  __Pyx_XDECREF(__pyx_t_4);
-  __Pyx_XDECREF(__pyx_t_5);
-  __Pyx_AddTraceback("_cdec.TRule.__str__", __pyx_clineno, __pyx_lineno, __pyx_filename);
-  __pyx_r = NULL;
+  __Pyx_AddTraceback("__iter__", __pyx_clineno, __pyx_lineno, __pyx_filename);
   __pyx_L0:;
-  __Pyx_XDECREF(__pyx_v_scores);
-  __Pyx_DECREF(((PyObject *)__pyx_cur_scope));
-  __Pyx_XGIVEREF(__pyx_r);
+  __Pyx_XDECREF(__pyx_r);
+  __pyx_generator->resume_label = -1;
+  __Pyx_RefNannyFinishContext();
+  return NULL;
+}
+
+/* Python wrapper */
+static PyObject *__pyx_pw_5_cdec_7Grammar_4name_1__get__(PyObject *__pyx_v_self); /*proto*/
+static PyObject *__pyx_pw_5_cdec_7Grammar_4name_1__get__(PyObject *__pyx_v_self) {
+  PyObject *__pyx_r = 0;
+  __Pyx_RefNannyDeclarations
+  __Pyx_RefNannySetupContext("__get__ (wrapper)", 0);
+  __pyx_r = __pyx_pf_5_cdec_7Grammar_4name___get__(((struct __pyx_obj_5_cdec_Grammar *)__pyx_v_self));
   __Pyx_RefNannyFinishContext();
   return __pyx_r;
 }
 
-/* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":138
- *     cdef public TRule trule
+/* "/Users/vchahun/Sandbox/cdec/python/src/grammar.pxi":163
+ * 
+ *     property name:
+ *         def __get__(self):             # <<<<<<<<<<<<<<
+ *             self.grammar.get().GetGrammarName().c_str()
  * 
- *     cdef init(self, hypergraph.Hypergraph* hg, unsigned i):             # <<<<<<<<<<<<<<
- *         self.hg = hg
- *         self.edge = &hg.edges_[i]
  */
 
-static PyObject *__pyx_f_5_cdec_14HypergraphEdge_init(struct __pyx_obj_5_cdec_HypergraphEdge *__pyx_v_self, Hypergraph *__pyx_v_hg, unsigned int __pyx_v_i) {
+static PyObject *__pyx_pf_5_cdec_7Grammar_4name___get__(struct __pyx_obj_5_cdec_Grammar *__pyx_v_self) {
   PyObject *__pyx_r = NULL;
   __Pyx_RefNannyDeclarations
-  PyObject *__pyx_t_1 = NULL;
-  int __pyx_lineno = 0;
-  const char *__pyx_filename = NULL;
-  int __pyx_clineno = 0;
-  __Pyx_RefNannySetupContext("init", 0);
-
-  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":139
- * 
- *     cdef init(self, hypergraph.Hypergraph* hg, unsigned i):
- *         self.hg = hg             # <<<<<<<<<<<<<<
- *         self.edge = &hg.edges_[i]
- *         self.trule = TRule()
- */
-  __pyx_v_self->hg = __pyx_v_hg;
-
-  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":140
- *     cdef init(self, hypergraph.Hypergraph* hg, unsigned i):
- *         self.hg = hg
- *         self.edge = &hg.edges_[i]             # <<<<<<<<<<<<<<
- *         self.trule = TRule()
- *         self.trule.rule = self.edge.rule_.get()
- */
-  __pyx_v_self->edge = (&(__pyx_v_hg->edges_[__pyx_v_i]));
-
-  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":141
- *         self.hg = hg
- *         self.edge = &hg.edges_[i]
- *         self.trule = TRule()             # <<<<<<<<<<<<<<
- *         self.trule.rule = self.edge.rule_.get()
- *         return self
- */
-  __pyx_t_1 = PyObject_Call(((PyObject *)((PyObject*)__pyx_ptype_5_cdec_TRule)), ((PyObject *)__pyx_empty_tuple), NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 141; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __Pyx_GOTREF(__pyx_t_1);
-  __Pyx_GIVEREF(__pyx_t_1);
-  __Pyx_GOTREF(__pyx_v_self->trule);
-  __Pyx_DECREF(((PyObject *)__pyx_v_self->trule));
-  __pyx_v_self->trule = ((struct __pyx_obj_5_cdec_TRule *)__pyx_t_1);
-  __pyx_t_1 = 0;
-
-  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":142
- *         self.edge = &hg.edges_[i]
- *         self.trule = TRule()
- *         self.trule.rule = self.edge.rule_.get()             # <<<<<<<<<<<<<<
- *         return self
- * 
- */
-  __pyx_v_self->trule->rule = __pyx_v_self->edge->rule_.get();
+  __Pyx_RefNannySetupContext("__get__", 0);
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":143
- *         self.trule = TRule()
- *         self.trule.rule = self.edge.rule_.get()
- *         return self             # <<<<<<<<<<<<<<
+  /* "/Users/vchahun/Sandbox/cdec/python/src/grammar.pxi":164
+ *     property name:
+ *         def __get__(self):
+ *             self.grammar.get().GetGrammarName().c_str()             # <<<<<<<<<<<<<<
  * 
- *     def __len__(self):
+ *         def __set__(self, name):
  */
-  __Pyx_XDECREF(__pyx_r);
-  __Pyx_INCREF(((PyObject *)__pyx_v_self));
-  __pyx_r = ((PyObject *)__pyx_v_self);
-  goto __pyx_L0;
+  __pyx_v_self->grammar->get()->GetGrammarName().c_str();
 
   __pyx_r = Py_None; __Pyx_INCREF(Py_None);
-  goto __pyx_L0;
-  __pyx_L1_error:;
-  __Pyx_XDECREF(__pyx_t_1);
-  __Pyx_AddTraceback("_cdec.HypergraphEdge.init", __pyx_clineno, __pyx_lineno, __pyx_filename);
-  __pyx_r = 0;
-  __pyx_L0:;
   __Pyx_XGIVEREF(__pyx_r);
   __Pyx_RefNannyFinishContext();
   return __pyx_r;
 }
 
 /* Python wrapper */
-static Py_ssize_t __pyx_pw_5_cdec_14HypergraphEdge_1__len__(PyObject *__pyx_v_self); /*proto*/
-static Py_ssize_t __pyx_pw_5_cdec_14HypergraphEdge_1__len__(PyObject *__pyx_v_self) {
-  Py_ssize_t __pyx_r;
+static int __pyx_pw_5_cdec_7Grammar_4name_3__set__(PyObject *__pyx_v_self, PyObject *__pyx_v_name); /*proto*/
+static int __pyx_pw_5_cdec_7Grammar_4name_3__set__(PyObject *__pyx_v_self, PyObject *__pyx_v_name) {
+  int __pyx_r;
   __Pyx_RefNannyDeclarations
-  __Pyx_RefNannySetupContext("__len__ (wrapper)", 0);
-  __pyx_r = __pyx_pf_5_cdec_14HypergraphEdge___len__(((struct __pyx_obj_5_cdec_HypergraphEdge *)__pyx_v_self));
+  __Pyx_RefNannySetupContext("__set__ (wrapper)", 0);
+  __pyx_r = __pyx_pf_5_cdec_7Grammar_4name_2__set__(((struct __pyx_obj_5_cdec_Grammar *)__pyx_v_self), ((PyObject *)__pyx_v_name));
   __Pyx_RefNannyFinishContext();
   return __pyx_r;
 }
 
-/* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":145
- *         return self
+/* "/Users/vchahun/Sandbox/cdec/python/src/grammar.pxi":166
+ *             self.grammar.get().GetGrammarName().c_str()
  * 
- *     def __len__(self):             # <<<<<<<<<<<<<<
- *         return self.edge.tail_nodes_.size()
+ *         def __set__(self, name):             # <<<<<<<<<<<<<<
+ *             self.grammar.get().SetGrammarName(string(<char *>name))
  * 
  */
 
-static Py_ssize_t __pyx_pf_5_cdec_14HypergraphEdge___len__(struct __pyx_obj_5_cdec_HypergraphEdge *__pyx_v_self) {
-  Py_ssize_t __pyx_r;
+static int __pyx_pf_5_cdec_7Grammar_4name_2__set__(struct __pyx_obj_5_cdec_Grammar *__pyx_v_self, PyObject *__pyx_v_name) {
+  int __pyx_r;
   __Pyx_RefNannyDeclarations
-  __Pyx_RefNannySetupContext("__len__", 0);
+  char *__pyx_t_1;
+  int __pyx_lineno = 0;
+  const char *__pyx_filename = NULL;
+  int __pyx_clineno = 0;
+  __Pyx_RefNannySetupContext("__set__", 0);
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":146
+  /* "/Users/vchahun/Sandbox/cdec/python/src/grammar.pxi":167
  * 
- *     def __len__(self):
- *         return self.edge.tail_nodes_.size()             # <<<<<<<<<<<<<<
+ *         def __set__(self, name):
+ *             self.grammar.get().SetGrammarName(string(<char *>name))             # <<<<<<<<<<<<<<
  * 
- *     property head_node:
+ * cdef class TextGrammar(Grammar):
  */
-  __pyx_r = __pyx_v_self->edge->tail_nodes_.size();
-  goto __pyx_L0;
+  __pyx_t_1 = PyBytes_AsString(__pyx_v_name); if (unlikely((!__pyx_t_1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 167; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_v_self->grammar->get()->SetGrammarName(std::string(((char *)__pyx_t_1)));
 
   __pyx_r = 0;
+  goto __pyx_L0;
+  __pyx_L1_error:;
+  __Pyx_AddTraceback("_cdec.Grammar.name.__set__", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __pyx_r = -1;
   __pyx_L0:;
   __Pyx_RefNannyFinishContext();
   return __pyx_r;
 }
 
 /* Python wrapper */
-static PyObject *__pyx_pw_5_cdec_14HypergraphEdge_9head_node_1__get__(PyObject *__pyx_v_self); /*proto*/
-static PyObject *__pyx_pw_5_cdec_14HypergraphEdge_9head_node_1__get__(PyObject *__pyx_v_self) {
-  PyObject *__pyx_r = 0;
+static int __pyx_pw_5_cdec_11TextGrammar_1__cinit__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/
+static int __pyx_pw_5_cdec_11TextGrammar_1__cinit__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) {
+  PyObject *__pyx_v_rules = 0;
+  static PyObject **__pyx_pyargnames[] = {&__pyx_n_s__rules,0};
+  int __pyx_r;
   __Pyx_RefNannyDeclarations
-  __Pyx_RefNannySetupContext("__get__ (wrapper)", 0);
-  __pyx_r = __pyx_pf_5_cdec_14HypergraphEdge_9head_node___get__(((struct __pyx_obj_5_cdec_HypergraphEdge *)__pyx_v_self));
+  __Pyx_RefNannySetupContext("__cinit__ (wrapper)", 0);
+  {
+    PyObject* values[1] = {0};
+    if (unlikely(__pyx_kwds)) {
+      Py_ssize_t kw_args;
+      const Py_ssize_t pos_args = PyTuple_GET_SIZE(__pyx_args);
+      switch (pos_args) {
+        case  1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0);
+        case  0: break;
+        default: goto __pyx_L5_argtuple_error;
+      }
+      kw_args = PyDict_Size(__pyx_kwds);
+      switch (pos_args) {
+        case  0:
+        values[0] = PyDict_GetItem(__pyx_kwds, __pyx_n_s__rules);
+        if (likely(values[0])) kw_args--;
+        else goto __pyx_L5_argtuple_error;
+      }
+      if (unlikely(kw_args > 0)) {
+        if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "__cinit__") < 0)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 170; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+      }
+    } else if (PyTuple_GET_SIZE(__pyx_args) != 1) {
+      goto __pyx_L5_argtuple_error;
+    } else {
+      values[0] = PyTuple_GET_ITEM(__pyx_args, 0);
+    }
+    __pyx_v_rules = values[0];
+  }
+  goto __pyx_L4_argument_unpacking_done;
+  __pyx_L5_argtuple_error:;
+  __Pyx_RaiseArgtupleInvalid("__cinit__", 1, 1, 1, PyTuple_GET_SIZE(__pyx_args)); {__pyx_filename = __pyx_f[2]; __pyx_lineno = 170; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+  __pyx_L3_error:;
+  __Pyx_AddTraceback("_cdec.TextGrammar.__cinit__", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __Pyx_RefNannyFinishContext();
+  return -1;
+  __pyx_L4_argument_unpacking_done:;
+  __pyx_r = __pyx_pf_5_cdec_11TextGrammar___cinit__(((struct __pyx_obj_5_cdec_TextGrammar *)__pyx_v_self), __pyx_v_rules);
   __Pyx_RefNannyFinishContext();
   return __pyx_r;
 }
 
-/* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":149
- * 
- *     property head_node:
- *         def __get__(self):             # <<<<<<<<<<<<<<
- *             return HypergraphNode().init(self.hg, self.edge.head_node_)
+/* "/Users/vchahun/Sandbox/cdec/python/src/grammar.pxi":170
  * 
+ * cdef class TextGrammar(Grammar):
+ *     def __cinit__(self, rules):             # <<<<<<<<<<<<<<
+ *         self.grammar = new shared_ptr[grammar.Grammar](new grammar.TextGrammar())
+ *         cdef grammar.TextGrammar* _g = <grammar.TextGrammar*> self.grammar.get()
  */
 
-static PyObject *__pyx_pf_5_cdec_14HypergraphEdge_9head_node___get__(struct __pyx_obj_5_cdec_HypergraphEdge *__pyx_v_self) {
-  PyObject *__pyx_r = NULL;
+static int __pyx_pf_5_cdec_11TextGrammar___cinit__(struct __pyx_obj_5_cdec_TextGrammar *__pyx_v_self, PyObject *__pyx_v_rules) {
+  TextGrammar *__pyx_v__g;
+  PyObject *__pyx_v_trule = NULL;
+  int __pyx_r;
   __Pyx_RefNannyDeclarations
   PyObject *__pyx_t_1 = NULL;
-  PyObject *__pyx_t_2 = NULL;
+  Py_ssize_t __pyx_t_2;
+  PyObject *(*__pyx_t_3)(PyObject *);
+  PyObject *__pyx_t_4 = NULL;
+  int __pyx_t_5;
+  int __pyx_t_6;
   int __pyx_lineno = 0;
   const char *__pyx_filename = NULL;
   int __pyx_clineno = 0;
-  __Pyx_RefNannySetupContext("__get__", 0);
+  __Pyx_RefNannySetupContext("__cinit__", 0);
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":150
- *     property head_node:
- *         def __get__(self):
- *             return HypergraphNode().init(self.hg, self.edge.head_node_)             # <<<<<<<<<<<<<<
- * 
- *     property tail_nodes:
+  /* "/Users/vchahun/Sandbox/cdec/python/src/grammar.pxi":171
+ * cdef class TextGrammar(Grammar):
+ *     def __cinit__(self, rules):
+ *         self.grammar = new shared_ptr[grammar.Grammar](new grammar.TextGrammar())             # <<<<<<<<<<<<<<
+ *         cdef grammar.TextGrammar* _g = <grammar.TextGrammar*> self.grammar.get()
+ *         for trule in rules:
+ */
+  __pyx_v_self->__pyx_base.grammar = new boost::shared_ptr<Grammar>(new TextGrammar());
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/grammar.pxi":172
+ *     def __cinit__(self, rules):
+ *         self.grammar = new shared_ptr[grammar.Grammar](new grammar.TextGrammar())
+ *         cdef grammar.TextGrammar* _g = <grammar.TextGrammar*> self.grammar.get()             # <<<<<<<<<<<<<<
+ *         for trule in rules:
+ *             if not isinstance(trule, BaseTRule):
+ */
+  __pyx_v__g = ((TextGrammar *)__pyx_v_self->__pyx_base.grammar->get());
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/grammar.pxi":173
+ *         self.grammar = new shared_ptr[grammar.Grammar](new grammar.TextGrammar())
+ *         cdef grammar.TextGrammar* _g = <grammar.TextGrammar*> self.grammar.get()
+ *         for trule in rules:             # <<<<<<<<<<<<<<
+ *             if not isinstance(trule, BaseTRule):
+ *                 raise ValueError('the grammar should contain TRule objects')
+ */
+  if (PyList_CheckExact(__pyx_v_rules) || PyTuple_CheckExact(__pyx_v_rules)) {
+    __pyx_t_1 = __pyx_v_rules; __Pyx_INCREF(__pyx_t_1); __pyx_t_2 = 0;
+    __pyx_t_3 = NULL;
+  } else {
+    __pyx_t_2 = -1; __pyx_t_1 = PyObject_GetIter(__pyx_v_rules); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 173; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_1);
+    __pyx_t_3 = Py_TYPE(__pyx_t_1)->tp_iternext;
+  }
+  for (;;) {
+    if (!__pyx_t_3 && PyList_CheckExact(__pyx_t_1)) {
+      if (__pyx_t_2 >= PyList_GET_SIZE(__pyx_t_1)) break;
+      __pyx_t_4 = PyList_GET_ITEM(__pyx_t_1, __pyx_t_2); __Pyx_INCREF(__pyx_t_4); __pyx_t_2++;
+    } else if (!__pyx_t_3 && PyTuple_CheckExact(__pyx_t_1)) {
+      if (__pyx_t_2 >= PyTuple_GET_SIZE(__pyx_t_1)) break;
+      __pyx_t_4 = PyTuple_GET_ITEM(__pyx_t_1, __pyx_t_2); __Pyx_INCREF(__pyx_t_4); __pyx_t_2++;
+    } else {
+      __pyx_t_4 = __pyx_t_3(__pyx_t_1);
+      if (unlikely(!__pyx_t_4)) {
+        if (PyErr_Occurred()) {
+          if (likely(PyErr_ExceptionMatches(PyExc_StopIteration))) PyErr_Clear();
+          else {__pyx_filename = __pyx_f[2]; __pyx_lineno = 173; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+        }
+        break;
+      }
+      __Pyx_GOTREF(__pyx_t_4);
+    }
+    __Pyx_XDECREF(__pyx_v_trule);
+    __pyx_v_trule = __pyx_t_4;
+    __pyx_t_4 = 0;
+
+    /* "/Users/vchahun/Sandbox/cdec/python/src/grammar.pxi":174
+ *         cdef grammar.TextGrammar* _g = <grammar.TextGrammar*> self.grammar.get()
+ *         for trule in rules:
+ *             if not isinstance(trule, BaseTRule):             # <<<<<<<<<<<<<<
+ *                 raise ValueError('the grammar should contain TRule objects')
+ *             _g.AddRule((<TRule> trule).rule[0])
  */
-  __Pyx_XDECREF(__pyx_r);
-  __pyx_t_1 = PyObject_Call(((PyObject *)((PyObject*)__pyx_ptype_5_cdec_HypergraphNode)), ((PyObject *)__pyx_empty_tuple), NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 150; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __Pyx_GOTREF(__pyx_t_1);
-  __pyx_t_2 = ((struct __pyx_vtabstruct_5_cdec_HypergraphNode *)((struct __pyx_obj_5_cdec_HypergraphNode *)__pyx_t_1)->__pyx_vtab)->init(((struct __pyx_obj_5_cdec_HypergraphNode *)__pyx_t_1), __pyx_v_self->hg, __pyx_v_self->edge->head_node_); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 150; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __Pyx_GOTREF(__pyx_t_2);
+    __pyx_t_4 = ((PyObject *)((PyObject*)__pyx_ptype_5_cdec_BaseTRule));
+    __Pyx_INCREF(__pyx_t_4);
+    __pyx_t_5 = __Pyx_TypeCheck(__pyx_v_trule, __pyx_t_4); 
+    __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
+    __pyx_t_6 = (!__pyx_t_5);
+    if (__pyx_t_6) {
+
+      /* "/Users/vchahun/Sandbox/cdec/python/src/grammar.pxi":175
+ *         for trule in rules:
+ *             if not isinstance(trule, BaseTRule):
+ *                 raise ValueError('the grammar should contain TRule objects')             # <<<<<<<<<<<<<<
+ *             _g.AddRule((<TRule> trule).rule[0])
+ */
+      __pyx_t_4 = PyObject_Call(__pyx_builtin_ValueError, ((PyObject *)__pyx_k_tuple_14), NULL); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 175; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __Pyx_GOTREF(__pyx_t_4);
+      __Pyx_Raise(__pyx_t_4, 0, 0, 0);
+      __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
+      {__pyx_filename = __pyx_f[2]; __pyx_lineno = 175; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      goto __pyx_L5;
+    }
+    __pyx_L5:;
+
+    /* "/Users/vchahun/Sandbox/cdec/python/src/grammar.pxi":176
+ *             if not isinstance(trule, BaseTRule):
+ *                 raise ValueError('the grammar should contain TRule objects')
+ *             _g.AddRule((<TRule> trule).rule[0])             # <<<<<<<<<<<<<<
+ */
+    __pyx_v__g->AddRule((((struct __pyx_obj_5_cdec_TRule *)__pyx_v_trule)->__pyx_base.rule[0]));
+  }
   __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
-  __pyx_r = __pyx_t_2;
-  __pyx_t_2 = 0;
-  goto __pyx_L0;
 
-  __pyx_r = Py_None; __Pyx_INCREF(Py_None);
+  __pyx_r = 0;
   goto __pyx_L0;
   __pyx_L1_error:;
   __Pyx_XDECREF(__pyx_t_1);
-  __Pyx_XDECREF(__pyx_t_2);
-  __Pyx_AddTraceback("_cdec.HypergraphEdge.head_node.__get__", __pyx_clineno, __pyx_lineno, __pyx_filename);
-  __pyx_r = NULL;
+  __Pyx_XDECREF(__pyx_t_4);
+  __Pyx_AddTraceback("_cdec.TextGrammar.__cinit__", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __pyx_r = -1;
   __pyx_L0:;
-  __Pyx_XGIVEREF(__pyx_r);
+  __Pyx_XDECREF(__pyx_v_trule);
   __Pyx_RefNannyFinishContext();
   return __pyx_r;
 }
-static PyObject *__pyx_gb_5_cdec_14HypergraphEdge_10tail_nodes_2generator8(__pyx_GeneratorObject *__pyx_generator, PyObject *__pyx_sent_value); /* proto */
 
 /* Python wrapper */
-static PyObject *__pyx_pw_5_cdec_14HypergraphEdge_10tail_nodes_1__get__(PyObject *__pyx_v_self); /*proto*/
-static PyObject *__pyx_pw_5_cdec_14HypergraphEdge_10tail_nodes_1__get__(PyObject *__pyx_v_self) {
-  PyObject *__pyx_r = 0;
+static void __pyx_pw_5_cdec_10Hypergraph_1__dealloc__(PyObject *__pyx_v_self); /*proto*/
+static void __pyx_pw_5_cdec_10Hypergraph_1__dealloc__(PyObject *__pyx_v_self) {
   __Pyx_RefNannyDeclarations
-  __Pyx_RefNannySetupContext("__get__ (wrapper)", 0);
-  __pyx_r = __pyx_pf_5_cdec_14HypergraphEdge_10tail_nodes___get__(((struct __pyx_obj_5_cdec_HypergraphEdge *)__pyx_v_self));
+  __Pyx_RefNannySetupContext("__dealloc__ (wrapper)", 0);
+  __pyx_pf_5_cdec_10Hypergraph___dealloc__(((struct __pyx_obj_5_cdec_Hypergraph *)__pyx_v_self));
   __Pyx_RefNannyFinishContext();
-  return __pyx_r;
 }
 
-/* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":153
+/* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":8
+ *     cdef MT19937* rng
  * 
- *     property tail_nodes:
- *         def __get__(self):             # <<<<<<<<<<<<<<
- *             cdef unsigned i
- *             for i in range(self.edge.tail_nodes_.size()):
+ *     def __dealloc__(self):             # <<<<<<<<<<<<<<
+ *         del self.hg
+ *         if self.rng != NULL:
  */
 
-static PyObject *__pyx_pf_5_cdec_14HypergraphEdge_10tail_nodes___get__(struct __pyx_obj_5_cdec_HypergraphEdge *__pyx_v_self) {
-  struct __pyx_obj_5_cdec___pyx_scope_struct_12___get__ *__pyx_cur_scope;
-  PyObject *__pyx_r = NULL;
+static void __pyx_pf_5_cdec_10Hypergraph___dealloc__(struct __pyx_obj_5_cdec_Hypergraph *__pyx_v_self) {
   __Pyx_RefNannyDeclarations
-  int __pyx_lineno = 0;
-  const char *__pyx_filename = NULL;
-  int __pyx_clineno = 0;
-  __Pyx_RefNannySetupContext("__get__", 0);
-  __pyx_cur_scope = (struct __pyx_obj_5_cdec___pyx_scope_struct_12___get__ *)__pyx_ptype_5_cdec___pyx_scope_struct_12___get__->tp_new(__pyx_ptype_5_cdec___pyx_scope_struct_12___get__, __pyx_empty_tuple, NULL);
-  if (unlikely(!__pyx_cur_scope)) {
-    __Pyx_RefNannyFinishContext();
-    return NULL;
-  }
-  __Pyx_GOTREF(__pyx_cur_scope);
-  __pyx_cur_scope->__pyx_v_self = __pyx_v_self;
-  __Pyx_INCREF((PyObject *)__pyx_cur_scope->__pyx_v_self);
-  __Pyx_GIVEREF((PyObject *)__pyx_cur_scope->__pyx_v_self);
-  {
-    __pyx_GeneratorObject *gen = __Pyx_Generator_New((__pyx_generator_body_t) __pyx_gb_5_cdec_14HypergraphEdge_10tail_nodes_2generator8, (PyObject *) __pyx_cur_scope); if (unlikely(!gen)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 153; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-    __Pyx_DECREF(__pyx_cur_scope);
-    __Pyx_RefNannyFinishContext();
-    return (PyObject *) gen;
-  }
-
-  __pyx_r = Py_None; __Pyx_INCREF(Py_None);
-  goto __pyx_L0;
-  __pyx_L1_error:;
-  __Pyx_AddTraceback("_cdec.HypergraphEdge.tail_nodes.__get__", __pyx_clineno, __pyx_lineno, __pyx_filename);
-  __pyx_r = NULL;
-  __pyx_L0:;
-  __Pyx_DECREF(((PyObject *)__pyx_cur_scope));
-  __Pyx_XGIVEREF(__pyx_r);
-  __Pyx_RefNannyFinishContext();
-  return __pyx_r;
-}
+  int __pyx_t_1;
+  __Pyx_RefNannySetupContext("__dealloc__", 0);
 
-static PyObject *__pyx_gb_5_cdec_14HypergraphEdge_10tail_nodes_2generator8(__pyx_GeneratorObject *__pyx_generator, PyObject *__pyx_sent_value) /* generator body */
-{
-  struct __pyx_obj_5_cdec___pyx_scope_struct_12___get__ *__pyx_cur_scope = ((struct __pyx_obj_5_cdec___pyx_scope_struct_12___get__ *)__pyx_generator->closure);
-  PyObject *__pyx_r = NULL;
-  unsigned int __pyx_t_1;
-  unsigned int __pyx_t_2;
-  PyObject *__pyx_t_3 = NULL;
-  PyObject *__pyx_t_4 = NULL;
-  __Pyx_RefNannyDeclarations
-  __Pyx_RefNannySetupContext("None", 0);
-  switch (__pyx_generator->resume_label) {
-    case 0: goto __pyx_L3_first_run;
-    case 1: goto __pyx_L6_resume_from_yield;
-    default: /* CPython raises the right error here */
-    __Pyx_RefNannyFinishContext();
-    return NULL;
-  }
-  __pyx_L3_first_run:;
-  if (unlikely(!__pyx_sent_value)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 153; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":9
+ * 
+ *     def __dealloc__(self):
+ *         del self.hg             # <<<<<<<<<<<<<<
+ *         if self.rng != NULL:
+ *             del self.rng
+ */
+  delete __pyx_v_self->hg;
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":155
- *         def __get__(self):
- *             cdef unsigned i
- *             for i in range(self.edge.tail_nodes_.size()):             # <<<<<<<<<<<<<<
- *                 yield HypergraphNode().init(self.hg, self.edge.tail_nodes_[i])
+  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":10
+ *     def __dealloc__(self):
+ *         del self.hg
+ *         if self.rng != NULL:             # <<<<<<<<<<<<<<
+ *             del self.rng
  * 
  */
-  __pyx_t_1 = __pyx_cur_scope->__pyx_v_self->edge->tail_nodes_.size();
-  for (__pyx_t_2 = 0; __pyx_t_2 < __pyx_t_1; __pyx_t_2+=1) {
-    __pyx_cur_scope->__pyx_v_i = __pyx_t_2;
+  __pyx_t_1 = (__pyx_v_self->rng != NULL);
+  if (__pyx_t_1) {
 
-    /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":156
- *             cdef unsigned i
- *             for i in range(self.edge.tail_nodes_.size()):
- *                 yield HypergraphNode().init(self.hg, self.edge.tail_nodes_[i])             # <<<<<<<<<<<<<<
+    /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":11
+ *         del self.hg
+ *         if self.rng != NULL:
+ *             del self.rng             # <<<<<<<<<<<<<<
  * 
- *     property span:
+ *     def viterbi(self):
  */
-    __pyx_t_3 = PyObject_Call(((PyObject *)((PyObject*)__pyx_ptype_5_cdec_HypergraphNode)), ((PyObject *)__pyx_empty_tuple), NULL); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 156; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-    __Pyx_GOTREF(__pyx_t_3);
-    __pyx_t_4 = ((struct __pyx_vtabstruct_5_cdec_HypergraphNode *)((struct __pyx_obj_5_cdec_HypergraphNode *)__pyx_t_3)->__pyx_vtab)->init(((struct __pyx_obj_5_cdec_HypergraphNode *)__pyx_t_3), __pyx_cur_scope->__pyx_v_self->hg, (__pyx_cur_scope->__pyx_v_self->edge->tail_nodes_[__pyx_cur_scope->__pyx_v_i])); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 156; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-    __Pyx_GOTREF(__pyx_t_4);
-    __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
-    __pyx_r = __pyx_t_4;
-    __pyx_t_4 = 0;
-    __pyx_cur_scope->__pyx_t_0 = __pyx_t_1;
-    __pyx_cur_scope->__pyx_t_1 = __pyx_t_2;
-    __Pyx_XGIVEREF(__pyx_r);
-    __Pyx_RefNannyFinishContext();
-    /* return from generator, yielding value */
-    __pyx_generator->resume_label = 1;
-    return __pyx_r;
-    __pyx_L6_resume_from_yield:;
-    __pyx_t_1 = __pyx_cur_scope->__pyx_t_0;
-    __pyx_t_2 = __pyx_cur_scope->__pyx_t_1;
-    if (unlikely(!__pyx_sent_value)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 156; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    delete __pyx_v_self->rng;
+    goto __pyx_L3;
   }
-  PyErr_SetNone(PyExc_StopIteration);
-  goto __pyx_L0;
-  __pyx_L1_error:;
-  __Pyx_XDECREF(__pyx_t_3);
-  __Pyx_XDECREF(__pyx_t_4);
-  __Pyx_AddTraceback("__get__", __pyx_clineno, __pyx_lineno, __pyx_filename);
-  __pyx_L0:;
-  __Pyx_XDECREF(__pyx_r);
-  __pyx_generator->resume_label = -1;
+  __pyx_L3:;
+
   __Pyx_RefNannyFinishContext();
-  return NULL;
 }
 
 /* Python wrapper */
-static PyObject *__pyx_pw_5_cdec_14HypergraphEdge_4span_1__get__(PyObject *__pyx_v_self); /*proto*/
-static PyObject *__pyx_pw_5_cdec_14HypergraphEdge_4span_1__get__(PyObject *__pyx_v_self) {
+static PyObject *__pyx_pw_5_cdec_10Hypergraph_3viterbi(PyObject *__pyx_v_self, CYTHON_UNUSED PyObject *unused); /*proto*/
+static PyObject *__pyx_pw_5_cdec_10Hypergraph_3viterbi(PyObject *__pyx_v_self, CYTHON_UNUSED PyObject *unused) {
   PyObject *__pyx_r = 0;
   __Pyx_RefNannyDeclarations
-  __Pyx_RefNannySetupContext("__get__ (wrapper)", 0);
-  __pyx_r = __pyx_pf_5_cdec_14HypergraphEdge_4span___get__(((struct __pyx_obj_5_cdec_HypergraphEdge *)__pyx_v_self));
+  __Pyx_RefNannySetupContext("viterbi (wrapper)", 0);
+  __pyx_r = __pyx_pf_5_cdec_10Hypergraph_2viterbi(((struct __pyx_obj_5_cdec_Hypergraph *)__pyx_v_self));
   __Pyx_RefNannyFinishContext();
   return __pyx_r;
 }
 
-/* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":159
- * 
- *     property span:
- *         def __get__(self):             # <<<<<<<<<<<<<<
- *             return (self.edge.i_, self.edge.j_)
+/* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":13
+ *             del self.rng
  * 
+ *     def viterbi(self):             # <<<<<<<<<<<<<<
+ *         cdef vector[WordID] trans
+ *         hypergraph.ViterbiESentence(self.hg[0], &trans)
  */
 
-static PyObject *__pyx_pf_5_cdec_14HypergraphEdge_4span___get__(struct __pyx_obj_5_cdec_HypergraphEdge *__pyx_v_self) {
+static PyObject *__pyx_pf_5_cdec_10Hypergraph_2viterbi(struct __pyx_obj_5_cdec_Hypergraph *__pyx_v_self) {
+  std::vector<WordID> __pyx_v_trans;
   PyObject *__pyx_r = NULL;
   __Pyx_RefNannyDeclarations
   PyObject *__pyx_t_1 = NULL;
   PyObject *__pyx_t_2 = NULL;
-  PyObject *__pyx_t_3 = NULL;
   int __pyx_lineno = 0;
   const char *__pyx_filename = NULL;
   int __pyx_clineno = 0;
-  __Pyx_RefNannySetupContext("__get__", 0);
+  __Pyx_RefNannySetupContext("viterbi", 0);
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":160
- *     property span:
- *         def __get__(self):
- *             return (self.edge.i_, self.edge.j_)             # <<<<<<<<<<<<<<
+  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":15
+ *     def viterbi(self):
+ *         cdef vector[WordID] trans
+ *         hypergraph.ViterbiESentence(self.hg[0], &trans)             # <<<<<<<<<<<<<<
+ *         return unicode(GetString(trans).c_str(), 'utf8')
  * 
- *     property feature_values:
+ */
+  ViterbiESentence((__pyx_v_self->hg[0]), (&__pyx_v_trans));
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":16
+ *         cdef vector[WordID] trans
+ *         hypergraph.ViterbiESentence(self.hg[0], &trans)
+ *         return unicode(GetString(trans).c_str(), 'utf8')             # <<<<<<<<<<<<<<
+ * 
+ *     def viterbi_trees(self):
  */
   __Pyx_XDECREF(__pyx_r);
-  __pyx_t_1 = PyInt_FromLong(__pyx_v_self->edge->i_); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 160; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __Pyx_GOTREF(__pyx_t_1);
-  __pyx_t_2 = PyInt_FromLong(__pyx_v_self->edge->j_); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 160; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_1 = PyBytes_FromString(TD::GetString(__pyx_v_trans).c_str()); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 16; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(((PyObject *)__pyx_t_1));
+  __pyx_t_2 = PyTuple_New(2); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 16; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __Pyx_GOTREF(__pyx_t_2);
-  __pyx_t_3 = PyTuple_New(2); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 160; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __Pyx_GOTREF(__pyx_t_3);
-  PyTuple_SET_ITEM(__pyx_t_3, 0, __pyx_t_1);
-  __Pyx_GIVEREF(__pyx_t_1);
-  PyTuple_SET_ITEM(__pyx_t_3, 1, __pyx_t_2);
-  __Pyx_GIVEREF(__pyx_t_2);
+  PyTuple_SET_ITEM(__pyx_t_2, 0, ((PyObject *)__pyx_t_1));
+  __Pyx_GIVEREF(((PyObject *)__pyx_t_1));
+  __Pyx_INCREF(((PyObject *)__pyx_n_s__utf8));
+  PyTuple_SET_ITEM(__pyx_t_2, 1, ((PyObject *)__pyx_n_s__utf8));
+  __Pyx_GIVEREF(((PyObject *)__pyx_n_s__utf8));
+  __pyx_t_1 = 0;
+  __pyx_t_1 = PyObject_Call(((PyObject *)((PyObject*)(&PyUnicode_Type))), ((PyObject *)__pyx_t_2), NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 16; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_1);
+  __Pyx_DECREF(((PyObject *)__pyx_t_2)); __pyx_t_2 = 0;
+  __pyx_r = __pyx_t_1;
   __pyx_t_1 = 0;
-  __pyx_t_2 = 0;
-  __pyx_r = ((PyObject *)__pyx_t_3);
-  __pyx_t_3 = 0;
   goto __pyx_L0;
 
   __pyx_r = Py_None; __Pyx_INCREF(Py_None);
@@ -7585,8 +7561,7 @@ static PyObject *__pyx_pf_5_cdec_14HypergraphEdge_4span___get__(struct __pyx_obj
   __pyx_L1_error:;
   __Pyx_XDECREF(__pyx_t_1);
   __Pyx_XDECREF(__pyx_t_2);
-  __Pyx_XDECREF(__pyx_t_3);
-  __Pyx_AddTraceback("_cdec.HypergraphEdge.span.__get__", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __Pyx_AddTraceback("_cdec.Hypergraph.viterbi", __pyx_clineno, __pyx_lineno, __pyx_filename);
   __pyx_r = NULL;
   __pyx_L0:;
   __Pyx_XGIVEREF(__pyx_r);
@@ -7595,431 +7570,288 @@ static PyObject *__pyx_pf_5_cdec_14HypergraphEdge_4span___get__(struct __pyx_obj
 }
 
 /* Python wrapper */
-static PyObject *__pyx_pw_5_cdec_14HypergraphEdge_14feature_values_1__get__(PyObject *__pyx_v_self); /*proto*/
-static PyObject *__pyx_pw_5_cdec_14HypergraphEdge_14feature_values_1__get__(PyObject *__pyx_v_self) {
+static PyObject *__pyx_pw_5_cdec_10Hypergraph_5viterbi_trees(PyObject *__pyx_v_self, CYTHON_UNUSED PyObject *unused); /*proto*/
+static PyObject *__pyx_pw_5_cdec_10Hypergraph_5viterbi_trees(PyObject *__pyx_v_self, CYTHON_UNUSED PyObject *unused) {
   PyObject *__pyx_r = 0;
   __Pyx_RefNannyDeclarations
-  __Pyx_RefNannySetupContext("__get__ (wrapper)", 0);
-  __pyx_r = __pyx_pf_5_cdec_14HypergraphEdge_14feature_values___get__(((struct __pyx_obj_5_cdec_HypergraphEdge *)__pyx_v_self));
+  __Pyx_RefNannySetupContext("viterbi_trees (wrapper)", 0);
+  __pyx_r = __pyx_pf_5_cdec_10Hypergraph_4viterbi_trees(((struct __pyx_obj_5_cdec_Hypergraph *)__pyx_v_self));
   __Pyx_RefNannyFinishContext();
   return __pyx_r;
 }
 
-/* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":163
+/* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":18
+ *         return unicode(GetString(trans).c_str(), 'utf8')
  * 
- *     property feature_values:
- *         def __get__(self):             # <<<<<<<<<<<<<<
- *             cdef SparseVector vector = SparseVector()
- *             vector.vector = new FastSparseVector[double](self.edge.feature_values_)
+ *     def viterbi_trees(self):             # <<<<<<<<<<<<<<
+ *         f_tree = unicode(hypergraph.ViterbiFTree(self.hg[0]).c_str(), 'utf8')
+ *         e_tree = unicode(hypergraph.ViterbiETree(self.hg[0]).c_str(), 'utf8')
  */
 
-static PyObject *__pyx_pf_5_cdec_14HypergraphEdge_14feature_values___get__(struct __pyx_obj_5_cdec_HypergraphEdge *__pyx_v_self) {
-  struct __pyx_obj_5_cdec_SparseVector *__pyx_v_vector = 0;
+static PyObject *__pyx_pf_5_cdec_10Hypergraph_4viterbi_trees(struct __pyx_obj_5_cdec_Hypergraph *__pyx_v_self) {
+  PyObject *__pyx_v_f_tree = NULL;
+  PyObject *__pyx_v_e_tree = NULL;
   PyObject *__pyx_r = NULL;
   __Pyx_RefNannyDeclarations
   PyObject *__pyx_t_1 = NULL;
+  PyObject *__pyx_t_2 = NULL;
   int __pyx_lineno = 0;
   const char *__pyx_filename = NULL;
   int __pyx_clineno = 0;
-  __Pyx_RefNannySetupContext("__get__", 0);
+  __Pyx_RefNannySetupContext("viterbi_trees", 0);
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":164
- *     property feature_values:
- *         def __get__(self):
- *             cdef SparseVector vector = SparseVector()             # <<<<<<<<<<<<<<
- *             vector.vector = new FastSparseVector[double](self.edge.feature_values_)
- *             return vector
+  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":19
+ * 
+ *     def viterbi_trees(self):
+ *         f_tree = unicode(hypergraph.ViterbiFTree(self.hg[0]).c_str(), 'utf8')             # <<<<<<<<<<<<<<
+ *         e_tree = unicode(hypergraph.ViterbiETree(self.hg[0]).c_str(), 'utf8')
+ *         return (f_tree, e_tree)
  */
-  __pyx_t_1 = PyObject_Call(((PyObject *)((PyObject*)__pyx_ptype_5_cdec_SparseVector)), ((PyObject *)__pyx_empty_tuple), NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 164; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_1 = PyBytes_FromString(ViterbiFTree((__pyx_v_self->hg[0])).c_str()); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 19; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(((PyObject *)__pyx_t_1));
+  __pyx_t_2 = PyTuple_New(2); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 19; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_2);
+  PyTuple_SET_ITEM(__pyx_t_2, 0, ((PyObject *)__pyx_t_1));
+  __Pyx_GIVEREF(((PyObject *)__pyx_t_1));
+  __Pyx_INCREF(((PyObject *)__pyx_n_s__utf8));
+  PyTuple_SET_ITEM(__pyx_t_2, 1, ((PyObject *)__pyx_n_s__utf8));
+  __Pyx_GIVEREF(((PyObject *)__pyx_n_s__utf8));
+  __pyx_t_1 = 0;
+  __pyx_t_1 = PyObject_Call(((PyObject *)((PyObject*)(&PyUnicode_Type))), ((PyObject *)__pyx_t_2), NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 19; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __Pyx_GOTREF(__pyx_t_1);
-  __pyx_v_vector = ((struct __pyx_obj_5_cdec_SparseVector *)__pyx_t_1);
+  __Pyx_DECREF(((PyObject *)__pyx_t_2)); __pyx_t_2 = 0;
+  __pyx_v_f_tree = ((PyObject*)__pyx_t_1);
   __pyx_t_1 = 0;
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":165
- *         def __get__(self):
- *             cdef SparseVector vector = SparseVector()
- *             vector.vector = new FastSparseVector[double](self.edge.feature_values_)             # <<<<<<<<<<<<<<
- *             return vector
+  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":20
+ *     def viterbi_trees(self):
+ *         f_tree = unicode(hypergraph.ViterbiFTree(self.hg[0]).c_str(), 'utf8')
+ *         e_tree = unicode(hypergraph.ViterbiETree(self.hg[0]).c_str(), 'utf8')             # <<<<<<<<<<<<<<
+ *         return (f_tree, e_tree)
  * 
  */
-  __pyx_v_vector->vector = new FastSparseVector<double>(__pyx_v_self->edge->feature_values_);
+  __pyx_t_1 = PyBytes_FromString(ViterbiETree((__pyx_v_self->hg[0])).c_str()); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 20; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(((PyObject *)__pyx_t_1));
+  __pyx_t_2 = PyTuple_New(2); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 20; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_2);
+  PyTuple_SET_ITEM(__pyx_t_2, 0, ((PyObject *)__pyx_t_1));
+  __Pyx_GIVEREF(((PyObject *)__pyx_t_1));
+  __Pyx_INCREF(((PyObject *)__pyx_n_s__utf8));
+  PyTuple_SET_ITEM(__pyx_t_2, 1, ((PyObject *)__pyx_n_s__utf8));
+  __Pyx_GIVEREF(((PyObject *)__pyx_n_s__utf8));
+  __pyx_t_1 = 0;
+  __pyx_t_1 = PyObject_Call(((PyObject *)((PyObject*)(&PyUnicode_Type))), ((PyObject *)__pyx_t_2), NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 20; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_1);
+  __Pyx_DECREF(((PyObject *)__pyx_t_2)); __pyx_t_2 = 0;
+  __pyx_v_e_tree = ((PyObject*)__pyx_t_1);
+  __pyx_t_1 = 0;
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":166
- *             cdef SparseVector vector = SparseVector()
- *             vector.vector = new FastSparseVector[double](self.edge.feature_values_)
- *             return vector             # <<<<<<<<<<<<<<
+  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":21
+ *         f_tree = unicode(hypergraph.ViterbiFTree(self.hg[0]).c_str(), 'utf8')
+ *         e_tree = unicode(hypergraph.ViterbiETree(self.hg[0]).c_str(), 'utf8')
+ *         return (f_tree, e_tree)             # <<<<<<<<<<<<<<
  * 
- *     property prob:
+ *     def viterbi_features(self):
  */
   __Pyx_XDECREF(__pyx_r);
-  __Pyx_INCREF(((PyObject *)__pyx_v_vector));
-  __pyx_r = ((PyObject *)__pyx_v_vector);
+  __pyx_t_1 = PyTuple_New(2); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 21; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_1);
+  __Pyx_INCREF(((PyObject *)__pyx_v_f_tree));
+  PyTuple_SET_ITEM(__pyx_t_1, 0, ((PyObject *)__pyx_v_f_tree));
+  __Pyx_GIVEREF(((PyObject *)__pyx_v_f_tree));
+  __Pyx_INCREF(((PyObject *)__pyx_v_e_tree));
+  PyTuple_SET_ITEM(__pyx_t_1, 1, ((PyObject *)__pyx_v_e_tree));
+  __Pyx_GIVEREF(((PyObject *)__pyx_v_e_tree));
+  __pyx_r = ((PyObject *)__pyx_t_1);
+  __pyx_t_1 = 0;
   goto __pyx_L0;
 
   __pyx_r = Py_None; __Pyx_INCREF(Py_None);
   goto __pyx_L0;
   __pyx_L1_error:;
   __Pyx_XDECREF(__pyx_t_1);
-  __Pyx_AddTraceback("_cdec.HypergraphEdge.feature_values.__get__", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __Pyx_XDECREF(__pyx_t_2);
+  __Pyx_AddTraceback("_cdec.Hypergraph.viterbi_trees", __pyx_clineno, __pyx_lineno, __pyx_filename);
   __pyx_r = NULL;
   __pyx_L0:;
-  __Pyx_XDECREF((PyObject *)__pyx_v_vector);
+  __Pyx_XDECREF(__pyx_v_f_tree);
+  __Pyx_XDECREF(__pyx_v_e_tree);
   __Pyx_XGIVEREF(__pyx_r);
   __Pyx_RefNannyFinishContext();
   return __pyx_r;
 }
 
 /* Python wrapper */
-static PyObject *__pyx_pw_5_cdec_14HypergraphEdge_4prob_1__get__(PyObject *__pyx_v_self); /*proto*/
-static PyObject *__pyx_pw_5_cdec_14HypergraphEdge_4prob_1__get__(PyObject *__pyx_v_self) {
+static PyObject *__pyx_pw_5_cdec_10Hypergraph_7viterbi_features(PyObject *__pyx_v_self, CYTHON_UNUSED PyObject *unused); /*proto*/
+static PyObject *__pyx_pw_5_cdec_10Hypergraph_7viterbi_features(PyObject *__pyx_v_self, CYTHON_UNUSED PyObject *unused) {
   PyObject *__pyx_r = 0;
   __Pyx_RefNannyDeclarations
-  __Pyx_RefNannySetupContext("__get__ (wrapper)", 0);
-  __pyx_r = __pyx_pf_5_cdec_14HypergraphEdge_4prob___get__(((struct __pyx_obj_5_cdec_HypergraphEdge *)__pyx_v_self));
+  __Pyx_RefNannySetupContext("viterbi_features (wrapper)", 0);
+  __pyx_r = __pyx_pf_5_cdec_10Hypergraph_6viterbi_features(((struct __pyx_obj_5_cdec_Hypergraph *)__pyx_v_self));
   __Pyx_RefNannyFinishContext();
   return __pyx_r;
 }
 
-/* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":169
- * 
- *     property prob:
- *         def __get__(self):             # <<<<<<<<<<<<<<
- *             return self.edge.edge_prob_.as_float()
+/* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":23
+ *         return (f_tree, e_tree)
  * 
+ *     def viterbi_features(self):             # <<<<<<<<<<<<<<
+ *         cdef SparseVector fmap = SparseVector()
+ *         fmap.vector = new FastSparseVector[weight_t](hypergraph.ViterbiFeatures(self.hg[0]))
  */
 
-static PyObject *__pyx_pf_5_cdec_14HypergraphEdge_4prob___get__(struct __pyx_obj_5_cdec_HypergraphEdge *__pyx_v_self) {
+static PyObject *__pyx_pf_5_cdec_10Hypergraph_6viterbi_features(struct __pyx_obj_5_cdec_Hypergraph *__pyx_v_self) {
+  struct __pyx_obj_5_cdec_SparseVector *__pyx_v_fmap = 0;
   PyObject *__pyx_r = NULL;
   __Pyx_RefNannyDeclarations
   PyObject *__pyx_t_1 = NULL;
   int __pyx_lineno = 0;
   const char *__pyx_filename = NULL;
   int __pyx_clineno = 0;
-  __Pyx_RefNannySetupContext("__get__", 0);
+  __Pyx_RefNannySetupContext("viterbi_features", 0);
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":170
- *     property prob:
- *         def __get__(self):
- *             return self.edge.edge_prob_.as_float()             # <<<<<<<<<<<<<<
+  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":24
  * 
- *     def __richcmp__(HypergraphEdge x, HypergraphEdge y, int op):
+ *     def viterbi_features(self):
+ *         cdef SparseVector fmap = SparseVector()             # <<<<<<<<<<<<<<
+ *         fmap.vector = new FastSparseVector[weight_t](hypergraph.ViterbiFeatures(self.hg[0]))
+ *         return fmap
  */
-  __Pyx_XDECREF(__pyx_r);
-  __pyx_t_1 = PyFloat_FromDouble(__pyx_v_self->edge->edge_prob_.as_float()); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 170; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_1 = PyObject_Call(((PyObject *)((PyObject*)__pyx_ptype_5_cdec_SparseVector)), ((PyObject *)__pyx_empty_tuple), NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 24; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __Pyx_GOTREF(__pyx_t_1);
-  __pyx_r = __pyx_t_1;
+  __pyx_v_fmap = ((struct __pyx_obj_5_cdec_SparseVector *)__pyx_t_1);
   __pyx_t_1 = 0;
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":25
+ *     def viterbi_features(self):
+ *         cdef SparseVector fmap = SparseVector()
+ *         fmap.vector = new FastSparseVector[weight_t](hypergraph.ViterbiFeatures(self.hg[0]))             # <<<<<<<<<<<<<<
+ *         return fmap
+ * 
+ */
+  __pyx_v_fmap->vector = new FastSparseVector<weight_t>(ViterbiFeatures((__pyx_v_self->hg[0])));
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":26
+ *         cdef SparseVector fmap = SparseVector()
+ *         fmap.vector = new FastSparseVector[weight_t](hypergraph.ViterbiFeatures(self.hg[0]))
+ *         return fmap             # <<<<<<<<<<<<<<
+ * 
+ *     def viterbi_joshua(self):
+ */
+  __Pyx_XDECREF(__pyx_r);
+  __Pyx_INCREF(((PyObject *)__pyx_v_fmap));
+  __pyx_r = ((PyObject *)__pyx_v_fmap);
   goto __pyx_L0;
 
   __pyx_r = Py_None; __Pyx_INCREF(Py_None);
   goto __pyx_L0;
   __pyx_L1_error:;
   __Pyx_XDECREF(__pyx_t_1);
-  __Pyx_AddTraceback("_cdec.HypergraphEdge.prob.__get__", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __Pyx_AddTraceback("_cdec.Hypergraph.viterbi_features", __pyx_clineno, __pyx_lineno, __pyx_filename);
   __pyx_r = NULL;
   __pyx_L0:;
+  __Pyx_XDECREF((PyObject *)__pyx_v_fmap);
   __Pyx_XGIVEREF(__pyx_r);
   __Pyx_RefNannyFinishContext();
   return __pyx_r;
 }
 
 /* Python wrapper */
-static PyObject *__pyx_pw_5_cdec_14HypergraphEdge_3__richcmp__(PyObject *__pyx_v_x, PyObject *__pyx_v_y, int __pyx_v_op); /*proto*/
-static PyObject *__pyx_pw_5_cdec_14HypergraphEdge_3__richcmp__(PyObject *__pyx_v_x, PyObject *__pyx_v_y, int __pyx_v_op) {
+static PyObject *__pyx_pw_5_cdec_10Hypergraph_9viterbi_joshua(PyObject *__pyx_v_self, CYTHON_UNUSED PyObject *unused); /*proto*/
+static PyObject *__pyx_pw_5_cdec_10Hypergraph_9viterbi_joshua(PyObject *__pyx_v_self, CYTHON_UNUSED PyObject *unused) {
   PyObject *__pyx_r = 0;
   __Pyx_RefNannyDeclarations
-  __Pyx_RefNannySetupContext("__richcmp__ (wrapper)", 0);
-  if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_x), __pyx_ptype_5_cdec_HypergraphEdge, 1, "x", 0))) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 172; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_y), __pyx_ptype_5_cdec_HypergraphEdge, 1, "y", 0))) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 172; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __pyx_r = __pyx_pf_5_cdec_14HypergraphEdge_2__richcmp__(((struct __pyx_obj_5_cdec_HypergraphEdge *)__pyx_v_x), ((struct __pyx_obj_5_cdec_HypergraphEdge *)__pyx_v_y), ((int)__pyx_v_op));
-  goto __pyx_L0;
-  __pyx_L1_error:;
-  __pyx_r = NULL;
-  __pyx_L0:;
+  __Pyx_RefNannySetupContext("viterbi_joshua (wrapper)", 0);
+  __pyx_r = __pyx_pf_5_cdec_10Hypergraph_8viterbi_joshua(((struct __pyx_obj_5_cdec_Hypergraph *)__pyx_v_self));
   __Pyx_RefNannyFinishContext();
   return __pyx_r;
 }
 
-/* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":172
- *             return self.edge.edge_prob_.as_float()
+/* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":28
+ *         return fmap
+ * 
+ *     def viterbi_joshua(self):             # <<<<<<<<<<<<<<
+ *         return unicode(hypergraph.JoshuaVisualizationString(self.hg[0]).c_str(), 'utf8')
  * 
- *     def __richcmp__(HypergraphEdge x, HypergraphEdge y, int op):             # <<<<<<<<<<<<<<
- *         if op == 2: # ==
- *             return x.edge == y.edge
  */
 
-static PyObject *__pyx_pf_5_cdec_14HypergraphEdge_2__richcmp__(struct __pyx_obj_5_cdec_HypergraphEdge *__pyx_v_x, struct __pyx_obj_5_cdec_HypergraphEdge *__pyx_v_y, int __pyx_v_op) {
+static PyObject *__pyx_pf_5_cdec_10Hypergraph_8viterbi_joshua(struct __pyx_obj_5_cdec_Hypergraph *__pyx_v_self) {
   PyObject *__pyx_r = NULL;
   __Pyx_RefNannyDeclarations
   PyObject *__pyx_t_1 = NULL;
-  int __pyx_t_2;
+  PyObject *__pyx_t_2 = NULL;
   int __pyx_lineno = 0;
   const char *__pyx_filename = NULL;
   int __pyx_clineno = 0;
-  __Pyx_RefNannySetupContext("__richcmp__", 0);
-
-  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":175
- *         if op == 2: # ==
- *             return x.edge == y.edge
- *         elif op == 3: # !=             # <<<<<<<<<<<<<<
- *             return not (x == y)
- *         raise NotImplemented('comparison not implemented for HypergraphEdge')
- */
-  switch (__pyx_v_op) {
-
-    /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":173
- * 
- *     def __richcmp__(HypergraphEdge x, HypergraphEdge y, int op):
- *         if op == 2: # ==             # <<<<<<<<<<<<<<
- *             return x.edge == y.edge
- *         elif op == 3: # !=
- */
-    case 2:
-
-    /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":174
- *     def __richcmp__(HypergraphEdge x, HypergraphEdge y, int op):
- *         if op == 2: # ==
- *             return x.edge == y.edge             # <<<<<<<<<<<<<<
- *         elif op == 3: # !=
- *             return not (x == y)
- */
-    __Pyx_XDECREF(__pyx_r);
-    __pyx_t_1 = __Pyx_PyBool_FromLong((__pyx_v_x->edge == __pyx_v_y->edge)); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 174; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-    __Pyx_GOTREF(__pyx_t_1);
-    __pyx_r = __pyx_t_1;
-    __pyx_t_1 = 0;
-    goto __pyx_L0;
-    break;
-
-    /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":175
- *         if op == 2: # ==
- *             return x.edge == y.edge
- *         elif op == 3: # !=             # <<<<<<<<<<<<<<
- *             return not (x == y)
- *         raise NotImplemented('comparison not implemented for HypergraphEdge')
- */
-    case 3:
+  __Pyx_RefNannySetupContext("viterbi_joshua", 0);
 
-    /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":176
- *             return x.edge == y.edge
- *         elif op == 3: # !=
- *             return not (x == y)             # <<<<<<<<<<<<<<
- *         raise NotImplemented('comparison not implemented for HypergraphEdge')
+  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":29
  * 
- */
-    __Pyx_XDECREF(__pyx_r);
-    __pyx_t_1 = PyObject_RichCompare(((PyObject *)__pyx_v_x), ((PyObject *)__pyx_v_y), Py_EQ); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 176; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-    __Pyx_GOTREF(__pyx_t_1);
-    __pyx_t_2 = __Pyx_PyObject_IsTrue(__pyx_t_1); if (unlikely(__pyx_t_2 < 0)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 176; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-    __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
-    __pyx_t_1 = __Pyx_PyBool_FromLong((!__pyx_t_2)); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 176; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-    __Pyx_GOTREF(__pyx_t_1);
-    __pyx_r = __pyx_t_1;
-    __pyx_t_1 = 0;
-    goto __pyx_L0;
-    break;
-  }
-
-  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":177
- *         elif op == 3: # !=
- *             return not (x == y)
- *         raise NotImplemented('comparison not implemented for HypergraphEdge')             # <<<<<<<<<<<<<<
+ *     def viterbi_joshua(self):
+ *         return unicode(hypergraph.JoshuaVisualizationString(self.hg[0]).c_str(), 'utf8')             # <<<<<<<<<<<<<<
  * 
- * cdef class HypergraphNode:
+ *     def kbest(self, size):
  */
-  __pyx_t_1 = PyObject_Call(__pyx_builtin_NotImplemented, ((PyObject *)__pyx_k_tuple_14), NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 177; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_XDECREF(__pyx_r);
+  __pyx_t_1 = PyBytes_FromString(JoshuaVisualizationString((__pyx_v_self->hg[0])).c_str()); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 29; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(((PyObject *)__pyx_t_1));
+  __pyx_t_2 = PyTuple_New(2); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 29; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_2);
+  PyTuple_SET_ITEM(__pyx_t_2, 0, ((PyObject *)__pyx_t_1));
+  __Pyx_GIVEREF(((PyObject *)__pyx_t_1));
+  __Pyx_INCREF(((PyObject *)__pyx_n_s__utf8));
+  PyTuple_SET_ITEM(__pyx_t_2, 1, ((PyObject *)__pyx_n_s__utf8));
+  __Pyx_GIVEREF(((PyObject *)__pyx_n_s__utf8));
+  __pyx_t_1 = 0;
+  __pyx_t_1 = PyObject_Call(((PyObject *)((PyObject*)(&PyUnicode_Type))), ((PyObject *)__pyx_t_2), NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 29; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __Pyx_GOTREF(__pyx_t_1);
-  __Pyx_Raise(__pyx_t_1, 0, 0, 0);
-  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
-  {__pyx_filename = __pyx_f[2]; __pyx_lineno = 177; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_DECREF(((PyObject *)__pyx_t_2)); __pyx_t_2 = 0;
+  __pyx_r = __pyx_t_1;
+  __pyx_t_1 = 0;
+  goto __pyx_L0;
 
   __pyx_r = Py_None; __Pyx_INCREF(Py_None);
   goto __pyx_L0;
   __pyx_L1_error:;
   __Pyx_XDECREF(__pyx_t_1);
-  __Pyx_AddTraceback("_cdec.HypergraphEdge.__richcmp__", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __Pyx_XDECREF(__pyx_t_2);
+  __Pyx_AddTraceback("_cdec.Hypergraph.viterbi_joshua", __pyx_clineno, __pyx_lineno, __pyx_filename);
   __pyx_r = NULL;
   __pyx_L0:;
   __Pyx_XGIVEREF(__pyx_r);
   __Pyx_RefNannyFinishContext();
   return __pyx_r;
 }
+static PyObject *__pyx_gb_5_cdec_10Hypergraph_12generator4(__pyx_GeneratorObject *__pyx_generator, PyObject *__pyx_sent_value); /* proto */
 
 /* Python wrapper */
-static PyObject *__pyx_pw_5_cdec_14HypergraphEdge_5trule_1__get__(PyObject *__pyx_v_self); /*proto*/
-static PyObject *__pyx_pw_5_cdec_14HypergraphEdge_5trule_1__get__(PyObject *__pyx_v_self) {
-  PyObject *__pyx_r = 0;
-  __Pyx_RefNannyDeclarations
-  __Pyx_RefNannySetupContext("__get__ (wrapper)", 0);
-  __pyx_r = __pyx_pf_5_cdec_14HypergraphEdge_5trule___get__(((struct __pyx_obj_5_cdec_HypergraphEdge *)__pyx_v_self));
-  __Pyx_RefNannyFinishContext();
-  return __pyx_r;
-}
-
-/* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":136
- *     cdef hypergraph.Hypergraph* hg
- *     cdef hypergraph.HypergraphEdge* edge
- *     cdef public TRule trule             # <<<<<<<<<<<<<<
- * 
- *     cdef init(self, hypergraph.Hypergraph* hg, unsigned i):
- */
-
-static PyObject *__pyx_pf_5_cdec_14HypergraphEdge_5trule___get__(struct __pyx_obj_5_cdec_HypergraphEdge *__pyx_v_self) {
-  PyObject *__pyx_r = NULL;
-  __Pyx_RefNannyDeclarations
-  __Pyx_RefNannySetupContext("__get__", 0);
-  __Pyx_XDECREF(__pyx_r);
-  __Pyx_INCREF(((PyObject *)__pyx_v_self->trule));
-  __pyx_r = ((PyObject *)__pyx_v_self->trule);
-  goto __pyx_L0;
-
-  __pyx_r = Py_None; __Pyx_INCREF(Py_None);
-  __pyx_L0:;
-  __Pyx_XGIVEREF(__pyx_r);
-  __Pyx_RefNannyFinishContext();
-  return __pyx_r;
-}
-
-/* Python wrapper */
-static int __pyx_pw_5_cdec_14HypergraphEdge_5trule_3__set__(PyObject *__pyx_v_self, PyObject *__pyx_v_value); /*proto*/
-static int __pyx_pw_5_cdec_14HypergraphEdge_5trule_3__set__(PyObject *__pyx_v_self, PyObject *__pyx_v_value) {
-  int __pyx_r;
-  __Pyx_RefNannyDeclarations
-  __Pyx_RefNannySetupContext("__set__ (wrapper)", 0);
-  __pyx_r = __pyx_pf_5_cdec_14HypergraphEdge_5trule_2__set__(((struct __pyx_obj_5_cdec_HypergraphEdge *)__pyx_v_self), ((PyObject *)__pyx_v_value));
-  __Pyx_RefNannyFinishContext();
-  return __pyx_r;
-}
-
-static int __pyx_pf_5_cdec_14HypergraphEdge_5trule_2__set__(struct __pyx_obj_5_cdec_HypergraphEdge *__pyx_v_self, PyObject *__pyx_v_value) {
-  int __pyx_r;
-  __Pyx_RefNannyDeclarations
-  int __pyx_lineno = 0;
-  const char *__pyx_filename = NULL;
-  int __pyx_clineno = 0;
-  __Pyx_RefNannySetupContext("__set__", 0);
-  if (!(likely(((__pyx_v_value) == Py_None) || likely(__Pyx_TypeTest(__pyx_v_value, __pyx_ptype_5_cdec_TRule))))) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 136; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __Pyx_INCREF(__pyx_v_value);
-  __Pyx_GIVEREF(__pyx_v_value);
-  __Pyx_GOTREF(__pyx_v_self->trule);
-  __Pyx_DECREF(((PyObject *)__pyx_v_self->trule));
-  __pyx_v_self->trule = ((struct __pyx_obj_5_cdec_TRule *)__pyx_v_value);
-
-  __pyx_r = 0;
-  goto __pyx_L0;
-  __pyx_L1_error:;
-  __Pyx_AddTraceback("_cdec.HypergraphEdge.trule.__set__", __pyx_clineno, __pyx_lineno, __pyx_filename);
-  __pyx_r = -1;
-  __pyx_L0:;
-  __Pyx_RefNannyFinishContext();
-  return __pyx_r;
-}
-
-/* Python wrapper */
-static int __pyx_pw_5_cdec_14HypergraphEdge_5trule_5__del__(PyObject *__pyx_v_self); /*proto*/
-static int __pyx_pw_5_cdec_14HypergraphEdge_5trule_5__del__(PyObject *__pyx_v_self) {
-  int __pyx_r;
-  __Pyx_RefNannyDeclarations
-  __Pyx_RefNannySetupContext("__del__ (wrapper)", 0);
-  __pyx_r = __pyx_pf_5_cdec_14HypergraphEdge_5trule_4__del__(((struct __pyx_obj_5_cdec_HypergraphEdge *)__pyx_v_self));
-  __Pyx_RefNannyFinishContext();
-  return __pyx_r;
-}
-
-static int __pyx_pf_5_cdec_14HypergraphEdge_5trule_4__del__(struct __pyx_obj_5_cdec_HypergraphEdge *__pyx_v_self) {
-  int __pyx_r;
-  __Pyx_RefNannyDeclarations
-  __Pyx_RefNannySetupContext("__del__", 0);
-  __Pyx_INCREF(Py_None);
-  __Pyx_GIVEREF(Py_None);
-  __Pyx_GOTREF(__pyx_v_self->trule);
-  __Pyx_DECREF(((PyObject *)__pyx_v_self->trule));
-  __pyx_v_self->trule = ((struct __pyx_obj_5_cdec_TRule *)Py_None);
-
-  __pyx_r = 0;
-  __Pyx_RefNannyFinishContext();
-  return __pyx_r;
-}
-
-/* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":183
- *     cdef hypergraph.HypergraphNode* node
- * 
- *     cdef init(self, hypergraph.Hypergraph* hg, unsigned i):             # <<<<<<<<<<<<<<
- *         self.hg = hg
- *         self.node = &hg.nodes_[i]
- */
-
-static PyObject *__pyx_f_5_cdec_14HypergraphNode_init(struct __pyx_obj_5_cdec_HypergraphNode *__pyx_v_self, Hypergraph *__pyx_v_hg, unsigned int __pyx_v_i) {
-  PyObject *__pyx_r = NULL;
-  __Pyx_RefNannyDeclarations
-  __Pyx_RefNannySetupContext("init", 0);
-
-  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":184
- * 
- *     cdef init(self, hypergraph.Hypergraph* hg, unsigned i):
- *         self.hg = hg             # <<<<<<<<<<<<<<
- *         self.node = &hg.nodes_[i]
- *         return self
- */
-  __pyx_v_self->hg = __pyx_v_hg;
-
-  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":185
- *     cdef init(self, hypergraph.Hypergraph* hg, unsigned i):
- *         self.hg = hg
- *         self.node = &hg.nodes_[i]             # <<<<<<<<<<<<<<
- *         return self
- * 
- */
-  __pyx_v_self->node = (&(__pyx_v_hg->nodes_[__pyx_v_i]));
-
-  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":186
- *         self.hg = hg
- *         self.node = &hg.nodes_[i]
- *         return self             # <<<<<<<<<<<<<<
- * 
- *     property in_edges:
- */
-  __Pyx_XDECREF(__pyx_r);
-  __Pyx_INCREF(((PyObject *)__pyx_v_self));
-  __pyx_r = ((PyObject *)__pyx_v_self);
-  goto __pyx_L0;
-
-  __pyx_r = Py_None; __Pyx_INCREF(Py_None);
-  __pyx_L0:;
-  __Pyx_XGIVEREF(__pyx_r);
-  __Pyx_RefNannyFinishContext();
-  return __pyx_r;
-}
-static PyObject *__pyx_gb_5_cdec_14HypergraphNode_8in_edges_2generator9(__pyx_GeneratorObject *__pyx_generator, PyObject *__pyx_sent_value); /* proto */
-
-/* Python wrapper */
-static PyObject *__pyx_pw_5_cdec_14HypergraphNode_8in_edges_1__get__(PyObject *__pyx_v_self); /*proto*/
-static PyObject *__pyx_pw_5_cdec_14HypergraphNode_8in_edges_1__get__(PyObject *__pyx_v_self) {
+static PyObject *__pyx_pw_5_cdec_10Hypergraph_11kbest(PyObject *__pyx_v_self, PyObject *__pyx_v_size); /*proto*/
+static PyObject *__pyx_pw_5_cdec_10Hypergraph_11kbest(PyObject *__pyx_v_self, PyObject *__pyx_v_size) {
   PyObject *__pyx_r = 0;
   __Pyx_RefNannyDeclarations
-  __Pyx_RefNannySetupContext("__get__ (wrapper)", 0);
-  __pyx_r = __pyx_pf_5_cdec_14HypergraphNode_8in_edges___get__(((struct __pyx_obj_5_cdec_HypergraphNode *)__pyx_v_self));
+  __Pyx_RefNannySetupContext("kbest (wrapper)", 0);
+  __pyx_r = __pyx_pf_5_cdec_10Hypergraph_10kbest(((struct __pyx_obj_5_cdec_Hypergraph *)__pyx_v_self), ((PyObject *)__pyx_v_size));
   __Pyx_RefNannyFinishContext();
   return __pyx_r;
 }
 
-/* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":189
+/* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":31
+ *         return unicode(hypergraph.JoshuaVisualizationString(self.hg[0]).c_str(), 'utf8')
  * 
- *     property in_edges:
- *         def __get__(self):             # <<<<<<<<<<<<<<
- *             cdef unsigned i
- *             for i in range(self.node.in_edges_.size()):
+ *     def kbest(self, size):             # <<<<<<<<<<<<<<
+ *         cdef kbest.KBestDerivations[vector[WordID], kbest.ESentenceTraversal]* derivations = new kbest.KBestDerivations[vector[WordID], kbest.ESentenceTraversal](self.hg[0], size)
+ *         cdef kbest.KBestDerivations[vector[WordID], kbest.ESentenceTraversal].Derivation* derivation
  */
 
-static PyObject *__pyx_pf_5_cdec_14HypergraphNode_8in_edges___get__(struct __pyx_obj_5_cdec_HypergraphNode *__pyx_v_self) {
-  struct __pyx_obj_5_cdec___pyx_scope_struct_13___get__ *__pyx_cur_scope;
+static PyObject *__pyx_pf_5_cdec_10Hypergraph_10kbest(struct __pyx_obj_5_cdec_Hypergraph *__pyx_v_self, PyObject *__pyx_v_size) {
+  struct __pyx_obj_5_cdec___pyx_scope_struct_8_kbest *__pyx_cur_scope;
   PyObject *__pyx_r = NULL;
   __Pyx_RefNannyDeclarations
   int __pyx_lineno = 0;
   const char *__pyx_filename = NULL;
   int __pyx_clineno = 0;
-  __Pyx_RefNannySetupContext("__get__", 0);
-  __pyx_cur_scope = (struct __pyx_obj_5_cdec___pyx_scope_struct_13___get__ *)__pyx_ptype_5_cdec___pyx_scope_struct_13___get__->tp_new(__pyx_ptype_5_cdec___pyx_scope_struct_13___get__, __pyx_empty_tuple, NULL);
+  __Pyx_RefNannySetupContext("kbest", 0);
+  __pyx_cur_scope = (struct __pyx_obj_5_cdec___pyx_scope_struct_8_kbest *)__pyx_ptype_5_cdec___pyx_scope_struct_8_kbest->tp_new(__pyx_ptype_5_cdec___pyx_scope_struct_8_kbest, __pyx_empty_tuple, NULL);
   if (unlikely(!__pyx_cur_scope)) {
     __Pyx_RefNannyFinishContext();
     return NULL;
@@ -8028,8 +7860,11 @@ static PyObject *__pyx_pf_5_cdec_14HypergraphNode_8in_edges___get__(struct __pyx
   __pyx_cur_scope->__pyx_v_self = __pyx_v_self;
   __Pyx_INCREF((PyObject *)__pyx_cur_scope->__pyx_v_self);
   __Pyx_GIVEREF((PyObject *)__pyx_cur_scope->__pyx_v_self);
+  __pyx_cur_scope->__pyx_v_size = __pyx_v_size;
+  __Pyx_INCREF(__pyx_cur_scope->__pyx_v_size);
+  __Pyx_GIVEREF(__pyx_cur_scope->__pyx_v_size);
   {
-    __pyx_GeneratorObject *gen = __Pyx_Generator_New((__pyx_generator_body_t) __pyx_gb_5_cdec_14HypergraphNode_8in_edges_2generator9, (PyObject *) __pyx_cur_scope); if (unlikely(!gen)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 189; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_GeneratorObject *gen = __Pyx_Generator_New((__pyx_generator_body_t) __pyx_gb_5_cdec_10Hypergraph_12generator4, (PyObject *) __pyx_cur_scope); if (unlikely(!gen)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 31; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
     __Pyx_DECREF(__pyx_cur_scope);
     __Pyx_RefNannyFinishContext();
     return (PyObject *) gen;
@@ -8038,7 +7873,7 @@ static PyObject *__pyx_pf_5_cdec_14HypergraphNode_8in_edges___get__(struct __pyx
   __pyx_r = Py_None; __Pyx_INCREF(Py_None);
   goto __pyx_L0;
   __pyx_L1_error:;
-  __Pyx_AddTraceback("_cdec.HypergraphNode.in_edges.__get__", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __Pyx_AddTraceback("_cdec.Hypergraph.kbest", __pyx_clineno, __pyx_lineno, __pyx_filename);
   __pyx_r = NULL;
   __pyx_L0:;
   __Pyx_DECREF(((PyObject *)__pyx_cur_scope));
@@ -8047,105 +7882,193 @@ static PyObject *__pyx_pf_5_cdec_14HypergraphNode_8in_edges___get__(struct __pyx
   return __pyx_r;
 }
 
-static PyObject *__pyx_gb_5_cdec_14HypergraphNode_8in_edges_2generator9(__pyx_GeneratorObject *__pyx_generator, PyObject *__pyx_sent_value) /* generator body */
+static PyObject *__pyx_gb_5_cdec_10Hypergraph_12generator4(__pyx_GeneratorObject *__pyx_generator, PyObject *__pyx_sent_value) /* generator body */
 {
-  struct __pyx_obj_5_cdec___pyx_scope_struct_13___get__ *__pyx_cur_scope = ((struct __pyx_obj_5_cdec___pyx_scope_struct_13___get__ *)__pyx_generator->closure);
+  struct __pyx_obj_5_cdec___pyx_scope_struct_8_kbest *__pyx_cur_scope = ((struct __pyx_obj_5_cdec___pyx_scope_struct_8_kbest *)__pyx_generator->closure);
   PyObject *__pyx_r = NULL;
-  size_t __pyx_t_1;
-  unsigned int __pyx_t_2;
-  PyObject *__pyx_t_3 = NULL;
+  unsigned int __pyx_t_1;
+  long __pyx_t_2;
+  int __pyx_t_3;
   PyObject *__pyx_t_4 = NULL;
+  PyObject *__pyx_t_5 = NULL;
   __Pyx_RefNannyDeclarations
   __Pyx_RefNannySetupContext("None", 0);
   switch (__pyx_generator->resume_label) {
     case 0: goto __pyx_L3_first_run;
-    case 1: goto __pyx_L6_resume_from_yield;
+    case 1: goto __pyx_L10_resume_from_yield;
     default: /* CPython raises the right error here */
     __Pyx_RefNannyFinishContext();
     return NULL;
   }
   __pyx_L3_first_run:;
-  if (unlikely(!__pyx_sent_value)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 189; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (unlikely(!__pyx_sent_value)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 31; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":191
- *         def __get__(self):
- *             cdef unsigned i
- *             for i in range(self.node.in_edges_.size()):             # <<<<<<<<<<<<<<
- *                 yield HypergraphEdge().init(self.hg, self.node.in_edges_[i])
+  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":32
  * 
+ *     def kbest(self, size):
+ *         cdef kbest.KBestDerivations[vector[WordID], kbest.ESentenceTraversal]* derivations = new kbest.KBestDerivations[vector[WordID], kbest.ESentenceTraversal](self.hg[0], size)             # <<<<<<<<<<<<<<
+ *         cdef kbest.KBestDerivations[vector[WordID], kbest.ESentenceTraversal].Derivation* derivation
+ *         cdef unsigned k
  */
-  __pyx_t_1 = __pyx_cur_scope->__pyx_v_self->node->in_edges_.size();
-  for (__pyx_t_2 = 0; __pyx_t_2 < __pyx_t_1; __pyx_t_2+=1) {
-    __pyx_cur_scope->__pyx_v_i = __pyx_t_2;
+  __pyx_t_1 = __Pyx_PyInt_AsUnsignedInt(__pyx_cur_scope->__pyx_v_size); if (unlikely((__pyx_t_1 == (unsigned int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 32; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_cur_scope->__pyx_v_derivations = new KBest::KBestDerivations<std::vector<WordID>,ESentenceTraversal>((__pyx_cur_scope->__pyx_v_self->hg[0]), __pyx_t_1);
 
-    /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":192
- *             cdef unsigned i
- *             for i in range(self.node.in_edges_.size()):
- *                 yield HypergraphEdge().init(self.hg, self.node.in_edges_[i])             # <<<<<<<<<<<<<<
- * 
- *     property out_edges:
+  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":35
+ *         cdef kbest.KBestDerivations[vector[WordID], kbest.ESentenceTraversal].Derivation* derivation
+ *         cdef unsigned k
+ *         try:             # <<<<<<<<<<<<<<
+ *             for k in range(size):
+ *                 derivation = derivations.LazyKthBest(self.hg.nodes_.size() - 1, k)
  */
-    __pyx_t_3 = PyObject_Call(((PyObject *)((PyObject*)__pyx_ptype_5_cdec_HypergraphEdge)), ((PyObject *)__pyx_empty_tuple), NULL); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 192; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-    __Pyx_GOTREF(__pyx_t_3);
-    __pyx_t_4 = ((struct __pyx_vtabstruct_5_cdec_HypergraphEdge *)((struct __pyx_obj_5_cdec_HypergraphEdge *)__pyx_t_3)->__pyx_vtab)->init(((struct __pyx_obj_5_cdec_HypergraphEdge *)__pyx_t_3), __pyx_cur_scope->__pyx_v_self->hg, (__pyx_cur_scope->__pyx_v_self->node->in_edges_[__pyx_cur_scope->__pyx_v_i])); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 192; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-    __Pyx_GOTREF(__pyx_t_4);
-    __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
-    __pyx_r = __pyx_t_4;
-    __pyx_t_4 = 0;
-    __pyx_cur_scope->__pyx_t_0 = __pyx_t_1;
-    __pyx_cur_scope->__pyx_t_1 = __pyx_t_2;
-    __Pyx_XGIVEREF(__pyx_r);
-    __Pyx_RefNannyFinishContext();
-    /* return from generator, yielding value */
-    __pyx_generator->resume_label = 1;
-    return __pyx_r;
-    __pyx_L6_resume_from_yield:;
-    __pyx_t_1 = __pyx_cur_scope->__pyx_t_0;
-    __pyx_t_2 = __pyx_cur_scope->__pyx_t_1;
-    if (unlikely(!__pyx_sent_value)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 192; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  }
-  PyErr_SetNone(PyExc_StopIteration);
-  goto __pyx_L0;
-  __pyx_L1_error:;
-  __Pyx_XDECREF(__pyx_t_3);
-  __Pyx_XDECREF(__pyx_t_4);
-  __Pyx_AddTraceback("__get__", __pyx_clineno, __pyx_lineno, __pyx_filename);
-  __pyx_L0:;
-  __Pyx_XDECREF(__pyx_r);
-  __pyx_generator->resume_label = -1;
-  __Pyx_RefNannyFinishContext();
-  return NULL;
-}
-static PyObject *__pyx_gb_5_cdec_14HypergraphNode_9out_edges_2generator10(__pyx_GeneratorObject *__pyx_generator, PyObject *__pyx_sent_value); /* proto */
-
-/* Python wrapper */
-static PyObject *__pyx_pw_5_cdec_14HypergraphNode_9out_edges_1__get__(PyObject *__pyx_v_self); /*proto*/
-static PyObject *__pyx_pw_5_cdec_14HypergraphNode_9out_edges_1__get__(PyObject *__pyx_v_self) {
-  PyObject *__pyx_r = 0;
-  __Pyx_RefNannyDeclarations
-  __Pyx_RefNannySetupContext("__get__ (wrapper)", 0);
-  __pyx_r = __pyx_pf_5_cdec_14HypergraphNode_9out_edges___get__(((struct __pyx_obj_5_cdec_HypergraphNode *)__pyx_v_self));
-  __Pyx_RefNannyFinishContext();
-  return __pyx_r;
-}
+  /*try:*/ {
 
-/* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":195
- * 
- *     property out_edges:
- *         def __get__(self):             # <<<<<<<<<<<<<<
- *             cdef unsigned i
- *             for i in range(self.node.out_edges_.size()):
+    /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":36
+ *         cdef unsigned k
+ *         try:
+ *             for k in range(size):             # <<<<<<<<<<<<<<
+ *                 derivation = derivations.LazyKthBest(self.hg.nodes_.size() - 1, k)
+ *                 if not derivation: break
  */
+    __pyx_t_2 = __Pyx_PyInt_AsLong(__pyx_cur_scope->__pyx_v_size); if (unlikely((__pyx_t_2 == (long)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 36; __pyx_clineno = __LINE__; goto __pyx_L5;}
+    for (__pyx_t_1 = 0; __pyx_t_1 < __pyx_t_2; __pyx_t_1+=1) {
+      __pyx_cur_scope->__pyx_v_k = __pyx_t_1;
 
-static PyObject *__pyx_pf_5_cdec_14HypergraphNode_9out_edges___get__(struct __pyx_obj_5_cdec_HypergraphNode *__pyx_v_self) {
-  struct __pyx_obj_5_cdec___pyx_scope_struct_14___get__ *__pyx_cur_scope;
+      /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":37
+ *         try:
+ *             for k in range(size):
+ *                 derivation = derivations.LazyKthBest(self.hg.nodes_.size() - 1, k)             # <<<<<<<<<<<<<<
+ *                 if not derivation: break
+ *                 yield unicode(GetString(derivation._yield).c_str(), 'utf8')
+ */
+      __pyx_cur_scope->__pyx_v_derivation = __pyx_cur_scope->__pyx_v_derivations->LazyKthBest((__pyx_cur_scope->__pyx_v_self->hg->nodes_.size() - 1), __pyx_cur_scope->__pyx_v_k);
+
+      /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":38
+ *             for k in range(size):
+ *                 derivation = derivations.LazyKthBest(self.hg.nodes_.size() - 1, k)
+ *                 if not derivation: break             # <<<<<<<<<<<<<<
+ *                 yield unicode(GetString(derivation._yield).c_str(), 'utf8')
+ *         finally:
+ */
+      __pyx_t_3 = (!(__pyx_cur_scope->__pyx_v_derivation != 0));
+      if (__pyx_t_3) {
+        goto __pyx_L8_break;
+        goto __pyx_L9;
+      }
+      __pyx_L9:;
+
+      /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":39
+ *                 derivation = derivations.LazyKthBest(self.hg.nodes_.size() - 1, k)
+ *                 if not derivation: break
+ *                 yield unicode(GetString(derivation._yield).c_str(), 'utf8')             # <<<<<<<<<<<<<<
+ *         finally:
+ *             del derivations
+ */
+      __pyx_t_4 = PyBytes_FromString(TD::GetString(__pyx_cur_scope->__pyx_v_derivation->yield).c_str()); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 39; __pyx_clineno = __LINE__; goto __pyx_L5;}
+      __Pyx_GOTREF(((PyObject *)__pyx_t_4));
+      __pyx_t_5 = PyTuple_New(2); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 39; __pyx_clineno = __LINE__; goto __pyx_L5;}
+      __Pyx_GOTREF(__pyx_t_5);
+      PyTuple_SET_ITEM(__pyx_t_5, 0, ((PyObject *)__pyx_t_4));
+      __Pyx_GIVEREF(((PyObject *)__pyx_t_4));
+      __Pyx_INCREF(((PyObject *)__pyx_n_s__utf8));
+      PyTuple_SET_ITEM(__pyx_t_5, 1, ((PyObject *)__pyx_n_s__utf8));
+      __Pyx_GIVEREF(((PyObject *)__pyx_n_s__utf8));
+      __pyx_t_4 = 0;
+      __pyx_t_4 = PyObject_Call(((PyObject *)((PyObject*)(&PyUnicode_Type))), ((PyObject *)__pyx_t_5), NULL); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 39; __pyx_clineno = __LINE__; goto __pyx_L5;}
+      __Pyx_GOTREF(__pyx_t_4);
+      __Pyx_DECREF(((PyObject *)__pyx_t_5)); __pyx_t_5 = 0;
+      __pyx_r = __pyx_t_4;
+      __pyx_t_4 = 0;
+      __pyx_cur_scope->__pyx_t_0 = __pyx_t_1;
+      __pyx_cur_scope->__pyx_t_1 = __pyx_t_2;
+      __Pyx_XGIVEREF(__pyx_r);
+      __Pyx_RefNannyFinishContext();
+      /* return from generator, yielding value */
+      __pyx_generator->resume_label = 1;
+      return __pyx_r;
+      __pyx_L10_resume_from_yield:;
+      __pyx_t_1 = __pyx_cur_scope->__pyx_t_0;
+      __pyx_t_2 = __pyx_cur_scope->__pyx_t_1;
+      if (unlikely(!__pyx_sent_value)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 39; __pyx_clineno = __LINE__; goto __pyx_L5;}
+    }
+    __pyx_L8_break:;
+  }
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":41
+ *                 yield unicode(GetString(derivation._yield).c_str(), 'utf8')
+ *         finally:
+ *             del derivations             # <<<<<<<<<<<<<<
+ * 
+ *     def kbest_trees(self, size):
+ */
+  /*finally:*/ {
+    int __pyx_why;
+    PyObject *__pyx_exc_type, *__pyx_exc_value, *__pyx_exc_tb;
+    int __pyx_exc_lineno;
+    __pyx_exc_type = 0; __pyx_exc_value = 0; __pyx_exc_tb = 0; __pyx_exc_lineno = 0;
+    __pyx_why = 0; goto __pyx_L6;
+    __pyx_L5: {
+      __pyx_why = 4;
+      __Pyx_XDECREF(__pyx_t_5); __pyx_t_5 = 0;
+      __Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0;
+      __Pyx_ErrFetch(&__pyx_exc_type, &__pyx_exc_value, &__pyx_exc_tb);
+      __pyx_exc_lineno = __pyx_lineno;
+      goto __pyx_L6;
+    }
+    __pyx_L6:;
+    delete __pyx_cur_scope->__pyx_v_derivations;
+    switch (__pyx_why) {
+      case 4: {
+        __Pyx_ErrRestore(__pyx_exc_type, __pyx_exc_value, __pyx_exc_tb);
+        __pyx_lineno = __pyx_exc_lineno;
+        __pyx_exc_type = 0;
+        __pyx_exc_value = 0;
+        __pyx_exc_tb = 0;
+        goto __pyx_L1_error;
+      }
+    }
+  }
+  PyErr_SetNone(PyExc_StopIteration);
+  goto __pyx_L0;
+  __pyx_L1_error:;
+  __Pyx_XDECREF(__pyx_t_4);
+  __Pyx_XDECREF(__pyx_t_5);
+  __Pyx_AddTraceback("kbest", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __pyx_L0:;
+  __Pyx_XDECREF(__pyx_r);
+  __pyx_generator->resume_label = -1;
+  __Pyx_RefNannyFinishContext();
+  return NULL;
+}
+static PyObject *__pyx_gb_5_cdec_10Hypergraph_15generator5(__pyx_GeneratorObject *__pyx_generator, PyObject *__pyx_sent_value); /* proto */
+
+/* Python wrapper */
+static PyObject *__pyx_pw_5_cdec_10Hypergraph_14kbest_trees(PyObject *__pyx_v_self, PyObject *__pyx_v_size); /*proto*/
+static PyObject *__pyx_pw_5_cdec_10Hypergraph_14kbest_trees(PyObject *__pyx_v_self, PyObject *__pyx_v_size) {
+  PyObject *__pyx_r = 0;
+  __Pyx_RefNannyDeclarations
+  __Pyx_RefNannySetupContext("kbest_trees (wrapper)", 0);
+  __pyx_r = __pyx_pf_5_cdec_10Hypergraph_13kbest_trees(((struct __pyx_obj_5_cdec_Hypergraph *)__pyx_v_self), ((PyObject *)__pyx_v_size));
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+/* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":43
+ *             del derivations
+ * 
+ *     def kbest_trees(self, size):             # <<<<<<<<<<<<<<
+ *         cdef kbest.KBestDerivations[vector[WordID], kbest.FTreeTraversal]* f_derivations = new kbest.KBestDerivations[vector[WordID], kbest.FTreeTraversal](self.hg[0], size)
+ *         cdef kbest.KBestDerivations[vector[WordID], kbest.FTreeTraversal].Derivation* f_derivation
+ */
+
+static PyObject *__pyx_pf_5_cdec_10Hypergraph_13kbest_trees(struct __pyx_obj_5_cdec_Hypergraph *__pyx_v_self, PyObject *__pyx_v_size) {
+  struct __pyx_obj_5_cdec___pyx_scope_struct_9_kbest_trees *__pyx_cur_scope;
   PyObject *__pyx_r = NULL;
   __Pyx_RefNannyDeclarations
   int __pyx_lineno = 0;
   const char *__pyx_filename = NULL;
   int __pyx_clineno = 0;
-  __Pyx_RefNannySetupContext("__get__", 0);
-  __pyx_cur_scope = (struct __pyx_obj_5_cdec___pyx_scope_struct_14___get__ *)__pyx_ptype_5_cdec___pyx_scope_struct_14___get__->tp_new(__pyx_ptype_5_cdec___pyx_scope_struct_14___get__, __pyx_empty_tuple, NULL);
+  __Pyx_RefNannySetupContext("kbest_trees", 0);
+  __pyx_cur_scope = (struct __pyx_obj_5_cdec___pyx_scope_struct_9_kbest_trees *)__pyx_ptype_5_cdec___pyx_scope_struct_9_kbest_trees->tp_new(__pyx_ptype_5_cdec___pyx_scope_struct_9_kbest_trees, __pyx_empty_tuple, NULL);
   if (unlikely(!__pyx_cur_scope)) {
     __Pyx_RefNannyFinishContext();
     return NULL;
@@ -8154,8 +8077,11 @@ static PyObject *__pyx_pf_5_cdec_14HypergraphNode_9out_edges___get__(struct __py
   __pyx_cur_scope->__pyx_v_self = __pyx_v_self;
   __Pyx_INCREF((PyObject *)__pyx_cur_scope->__pyx_v_self);
   __Pyx_GIVEREF((PyObject *)__pyx_cur_scope->__pyx_v_self);
+  __pyx_cur_scope->__pyx_v_size = __pyx_v_size;
+  __Pyx_INCREF(__pyx_cur_scope->__pyx_v_size);
+  __Pyx_GIVEREF(__pyx_cur_scope->__pyx_v_size);
   {
-    __pyx_GeneratorObject *gen = __Pyx_Generator_New((__pyx_generator_body_t) __pyx_gb_5_cdec_14HypergraphNode_9out_edges_2generator10, (PyObject *) __pyx_cur_scope); if (unlikely(!gen)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 195; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_GeneratorObject *gen = __Pyx_Generator_New((__pyx_generator_body_t) __pyx_gb_5_cdec_10Hypergraph_15generator5, (PyObject *) __pyx_cur_scope); if (unlikely(!gen)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 43; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
     __Pyx_DECREF(__pyx_cur_scope);
     __Pyx_RefNannyFinishContext();
     return (PyObject *) gen;
@@ -8164,7 +8090,7 @@ static PyObject *__pyx_pf_5_cdec_14HypergraphNode_9out_edges___get__(struct __py
   __pyx_r = Py_None; __Pyx_INCREF(Py_None);
   goto __pyx_L0;
   __pyx_L1_error:;
-  __Pyx_AddTraceback("_cdec.HypergraphNode.out_edges.__get__", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __Pyx_AddTraceback("_cdec.Hypergraph.kbest_trees", __pyx_clineno, __pyx_lineno, __pyx_filename);
   __pyx_r = NULL;
   __pyx_L0:;
   __Pyx_DECREF(((PyObject *)__pyx_cur_scope));
@@ -8173,1160 +8099,1306 @@ static PyObject *__pyx_pf_5_cdec_14HypergraphNode_9out_edges___get__(struct __py
   return __pyx_r;
 }
 
-static PyObject *__pyx_gb_5_cdec_14HypergraphNode_9out_edges_2generator10(__pyx_GeneratorObject *__pyx_generator, PyObject *__pyx_sent_value) /* generator body */
+static PyObject *__pyx_gb_5_cdec_10Hypergraph_15generator5(__pyx_GeneratorObject *__pyx_generator, PyObject *__pyx_sent_value) /* generator body */
 {
-  struct __pyx_obj_5_cdec___pyx_scope_struct_14___get__ *__pyx_cur_scope = ((struct __pyx_obj_5_cdec___pyx_scope_struct_14___get__ *)__pyx_generator->closure);
+  struct __pyx_obj_5_cdec___pyx_scope_struct_9_kbest_trees *__pyx_cur_scope = ((struct __pyx_obj_5_cdec___pyx_scope_struct_9_kbest_trees *)__pyx_generator->closure);
   PyObject *__pyx_r = NULL;
-  size_t __pyx_t_1;
-  unsigned int __pyx_t_2;
-  PyObject *__pyx_t_3 = NULL;
-  PyObject *__pyx_t_4 = NULL;
+  unsigned int __pyx_t_1;
+  long __pyx_t_2;
+  int __pyx_t_3;
+  int __pyx_t_4;
+  int __pyx_t_5;
+  PyObject *__pyx_t_6 = NULL;
+  PyObject *__pyx_t_7 = NULL;
   __Pyx_RefNannyDeclarations
   __Pyx_RefNannySetupContext("None", 0);
   switch (__pyx_generator->resume_label) {
     case 0: goto __pyx_L3_first_run;
-    case 1: goto __pyx_L6_resume_from_yield;
+    case 1: goto __pyx_L10_resume_from_yield;
     default: /* CPython raises the right error here */
     __Pyx_RefNannyFinishContext();
     return NULL;
   }
   __pyx_L3_first_run:;
-  if (unlikely(!__pyx_sent_value)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 195; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (unlikely(!__pyx_sent_value)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 43; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":197
- *         def __get__(self):
- *             cdef unsigned i
- *             for i in range(self.node.out_edges_.size()):             # <<<<<<<<<<<<<<
- *                 yield HypergraphEdge().init(self.hg, self.node.out_edges_[i])
+  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":44
  * 
+ *     def kbest_trees(self, size):
+ *         cdef kbest.KBestDerivations[vector[WordID], kbest.FTreeTraversal]* f_derivations = new kbest.KBestDerivations[vector[WordID], kbest.FTreeTraversal](self.hg[0], size)             # <<<<<<<<<<<<<<
+ *         cdef kbest.KBestDerivations[vector[WordID], kbest.FTreeTraversal].Derivation* f_derivation
+ *         cdef kbest.KBestDerivations[vector[WordID], kbest.ETreeTraversal]* e_derivations = new kbest.KBestDerivations[vector[WordID], kbest.ETreeTraversal](self.hg[0], size)
  */
-  __pyx_t_1 = __pyx_cur_scope->__pyx_v_self->node->out_edges_.size();
-  for (__pyx_t_2 = 0; __pyx_t_2 < __pyx_t_1; __pyx_t_2+=1) {
-    __pyx_cur_scope->__pyx_v_i = __pyx_t_2;
+  __pyx_t_1 = __Pyx_PyInt_AsUnsignedInt(__pyx_cur_scope->__pyx_v_size); if (unlikely((__pyx_t_1 == (unsigned int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 44; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_cur_scope->__pyx_v_f_derivations = new KBest::KBestDerivations<std::vector<WordID>,FTreeTraversal>((__pyx_cur_scope->__pyx_v_self->hg[0]), __pyx_t_1);
 
-    /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":198
- *             cdef unsigned i
- *             for i in range(self.node.out_edges_.size()):
- *                 yield HypergraphEdge().init(self.hg, self.node.out_edges_[i])             # <<<<<<<<<<<<<<
- * 
- *     property span:
+  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":46
+ *         cdef kbest.KBestDerivations[vector[WordID], kbest.FTreeTraversal]* f_derivations = new kbest.KBestDerivations[vector[WordID], kbest.FTreeTraversal](self.hg[0], size)
+ *         cdef kbest.KBestDerivations[vector[WordID], kbest.FTreeTraversal].Derivation* f_derivation
+ *         cdef kbest.KBestDerivations[vector[WordID], kbest.ETreeTraversal]* e_derivations = new kbest.KBestDerivations[vector[WordID], kbest.ETreeTraversal](self.hg[0], size)             # <<<<<<<<<<<<<<
+ *         cdef kbest.KBestDerivations[vector[WordID], kbest.ETreeTraversal].Derivation* e_derivation
+ *         cdef unsigned k
  */
-    __pyx_t_3 = PyObject_Call(((PyObject *)((PyObject*)__pyx_ptype_5_cdec_HypergraphEdge)), ((PyObject *)__pyx_empty_tuple), NULL); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 198; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-    __Pyx_GOTREF(__pyx_t_3);
-    __pyx_t_4 = ((struct __pyx_vtabstruct_5_cdec_HypergraphEdge *)((struct __pyx_obj_5_cdec_HypergraphEdge *)__pyx_t_3)->__pyx_vtab)->init(((struct __pyx_obj_5_cdec_HypergraphEdge *)__pyx_t_3), __pyx_cur_scope->__pyx_v_self->hg, (__pyx_cur_scope->__pyx_v_self->node->out_edges_[__pyx_cur_scope->__pyx_v_i])); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 198; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-    __Pyx_GOTREF(__pyx_t_4);
-    __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
-    __pyx_r = __pyx_t_4;
-    __pyx_t_4 = 0;
-    __pyx_cur_scope->__pyx_t_0 = __pyx_t_1;
-    __pyx_cur_scope->__pyx_t_1 = __pyx_t_2;
-    __Pyx_XGIVEREF(__pyx_r);
-    __Pyx_RefNannyFinishContext();
-    /* return from generator, yielding value */
-    __pyx_generator->resume_label = 1;
-    return __pyx_r;
-    __pyx_L6_resume_from_yield:;
-    __pyx_t_1 = __pyx_cur_scope->__pyx_t_0;
-    __pyx_t_2 = __pyx_cur_scope->__pyx_t_1;
-    if (unlikely(!__pyx_sent_value)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 198; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  }
-  PyErr_SetNone(PyExc_StopIteration);
-  goto __pyx_L0;
-  __pyx_L1_error:;
-  __Pyx_XDECREF(__pyx_t_3);
-  __Pyx_XDECREF(__pyx_t_4);
-  __Pyx_AddTraceback("__get__", __pyx_clineno, __pyx_lineno, __pyx_filename);
-  __pyx_L0:;
-  __Pyx_XDECREF(__pyx_r);
-  __pyx_generator->resume_label = -1;
-  __Pyx_RefNannyFinishContext();
-  return NULL;
-}
-
-/* Python wrapper */
-static PyObject *__pyx_pw_5_cdec_14HypergraphNode_4span_1__get__(PyObject *__pyx_v_self); /*proto*/
-static PyObject *__pyx_pw_5_cdec_14HypergraphNode_4span_1__get__(PyObject *__pyx_v_self) {
-  PyObject *__pyx_r = 0;
-  __Pyx_RefNannyDeclarations
-  __Pyx_RefNannySetupContext("__get__ (wrapper)", 0);
-  __pyx_r = __pyx_pf_5_cdec_14HypergraphNode_4span___get__(((struct __pyx_obj_5_cdec_HypergraphNode *)__pyx_v_self));
-  __Pyx_RefNannyFinishContext();
-  return __pyx_r;
-}
+  __pyx_t_1 = __Pyx_PyInt_AsUnsignedInt(__pyx_cur_scope->__pyx_v_size); if (unlikely((__pyx_t_1 == (unsigned int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 46; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_cur_scope->__pyx_v_e_derivations = new KBest::KBestDerivations<std::vector<WordID>,ETreeTraversal>((__pyx_cur_scope->__pyx_v_self->hg[0]), __pyx_t_1);
 
-/* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":201
- * 
- *     property span:
- *         def __get__(self):             # <<<<<<<<<<<<<<
- *             return next(self.in_edges).span
- * 
+  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":49
+ *         cdef kbest.KBestDerivations[vector[WordID], kbest.ETreeTraversal].Derivation* e_derivation
+ *         cdef unsigned k
+ *         try:             # <<<<<<<<<<<<<<
+ *             for k in range(size):
+ *                 f_derivation = f_derivations.LazyKthBest(self.hg.nodes_.size() - 1, k)
  */
+  /*try:*/ {
 
-static PyObject *__pyx_pf_5_cdec_14HypergraphNode_4span___get__(struct __pyx_obj_5_cdec_HypergraphNode *__pyx_v_self) {
-  PyObject *__pyx_r = NULL;
-  __Pyx_RefNannyDeclarations
-  PyObject *__pyx_t_1 = NULL;
-  PyObject *__pyx_t_2 = NULL;
-  int __pyx_lineno = 0;
-  const char *__pyx_filename = NULL;
-  int __pyx_clineno = 0;
-  __Pyx_RefNannySetupContext("__get__", 0);
+    /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":50
+ *         cdef unsigned k
+ *         try:
+ *             for k in range(size):             # <<<<<<<<<<<<<<
+ *                 f_derivation = f_derivations.LazyKthBest(self.hg.nodes_.size() - 1, k)
+ *                 e_derivation = e_derivations.LazyKthBest(self.hg.nodes_.size() - 1, k)
+ */
+    __pyx_t_2 = __Pyx_PyInt_AsLong(__pyx_cur_scope->__pyx_v_size); if (unlikely((__pyx_t_2 == (long)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 50; __pyx_clineno = __LINE__; goto __pyx_L5;}
+    for (__pyx_t_1 = 0; __pyx_t_1 < __pyx_t_2; __pyx_t_1+=1) {
+      __pyx_cur_scope->__pyx_v_k = __pyx_t_1;
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":202
- *     property span:
- *         def __get__(self):
- *             return next(self.in_edges).span             # <<<<<<<<<<<<<<
- * 
- *     property cat:
+      /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":51
+ *         try:
+ *             for k in range(size):
+ *                 f_derivation = f_derivations.LazyKthBest(self.hg.nodes_.size() - 1, k)             # <<<<<<<<<<<<<<
+ *                 e_derivation = e_derivations.LazyKthBest(self.hg.nodes_.size() - 1, k)
+ *                 if not f_derivation or not e_derivation: break
  */
-  __Pyx_XDECREF(__pyx_r);
-  __pyx_t_1 = PyObject_GetAttr(((PyObject *)__pyx_v_self), __pyx_n_s__in_edges); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 202; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __Pyx_GOTREF(__pyx_t_1);
-  __pyx_t_2 = __Pyx_PyIter_Next(__pyx_t_1); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 202; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __Pyx_GOTREF(__pyx_t_2);
-  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
-  __pyx_t_1 = PyObject_GetAttr(__pyx_t_2, __pyx_n_s__span); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 202; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __Pyx_GOTREF(__pyx_t_1);
-  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
-  __pyx_r = __pyx_t_1;
-  __pyx_t_1 = 0;
-  goto __pyx_L0;
+      __pyx_cur_scope->__pyx_v_f_derivation = __pyx_cur_scope->__pyx_v_f_derivations->LazyKthBest((__pyx_cur_scope->__pyx_v_self->hg->nodes_.size() - 1), __pyx_cur_scope->__pyx_v_k);
 
-  __pyx_r = Py_None; __Pyx_INCREF(Py_None);
+      /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":52
+ *             for k in range(size):
+ *                 f_derivation = f_derivations.LazyKthBest(self.hg.nodes_.size() - 1, k)
+ *                 e_derivation = e_derivations.LazyKthBest(self.hg.nodes_.size() - 1, k)             # <<<<<<<<<<<<<<
+ *                 if not f_derivation or not e_derivation: break
+ *                 f_tree = unicode(GetString(f_derivation._yield).c_str(), 'utf8')
+ */
+      __pyx_cur_scope->__pyx_v_e_derivation = __pyx_cur_scope->__pyx_v_e_derivations->LazyKthBest((__pyx_cur_scope->__pyx_v_self->hg->nodes_.size() - 1), __pyx_cur_scope->__pyx_v_k);
+
+      /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":53
+ *                 f_derivation = f_derivations.LazyKthBest(self.hg.nodes_.size() - 1, k)
+ *                 e_derivation = e_derivations.LazyKthBest(self.hg.nodes_.size() - 1, k)
+ *                 if not f_derivation or not e_derivation: break             # <<<<<<<<<<<<<<
+ *                 f_tree = unicode(GetString(f_derivation._yield).c_str(), 'utf8')
+ *                 e_tree = unicode(GetString(e_derivation._yield).c_str(), 'utf8')
+ */
+      __pyx_t_3 = (!(__pyx_cur_scope->__pyx_v_f_derivation != 0));
+      if (!__pyx_t_3) {
+        __pyx_t_4 = (!(__pyx_cur_scope->__pyx_v_e_derivation != 0));
+        __pyx_t_5 = __pyx_t_4;
+      } else {
+        __pyx_t_5 = __pyx_t_3;
+      }
+      if (__pyx_t_5) {
+        goto __pyx_L8_break;
+        goto __pyx_L9;
+      }
+      __pyx_L9:;
+
+      /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":54
+ *                 e_derivation = e_derivations.LazyKthBest(self.hg.nodes_.size() - 1, k)
+ *                 if not f_derivation or not e_derivation: break
+ *                 f_tree = unicode(GetString(f_derivation._yield).c_str(), 'utf8')             # <<<<<<<<<<<<<<
+ *                 e_tree = unicode(GetString(e_derivation._yield).c_str(), 'utf8')
+ *                 yield (f_tree, e_tree)
+ */
+      __pyx_t_6 = PyBytes_FromString(TD::GetString(__pyx_cur_scope->__pyx_v_f_derivation->yield).c_str()); if (unlikely(!__pyx_t_6)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 54; __pyx_clineno = __LINE__; goto __pyx_L5;}
+      __Pyx_GOTREF(((PyObject *)__pyx_t_6));
+      __pyx_t_7 = PyTuple_New(2); if (unlikely(!__pyx_t_7)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 54; __pyx_clineno = __LINE__; goto __pyx_L5;}
+      __Pyx_GOTREF(__pyx_t_7);
+      PyTuple_SET_ITEM(__pyx_t_7, 0, ((PyObject *)__pyx_t_6));
+      __Pyx_GIVEREF(((PyObject *)__pyx_t_6));
+      __Pyx_INCREF(((PyObject *)__pyx_n_s__utf8));
+      PyTuple_SET_ITEM(__pyx_t_7, 1, ((PyObject *)__pyx_n_s__utf8));
+      __Pyx_GIVEREF(((PyObject *)__pyx_n_s__utf8));
+      __pyx_t_6 = 0;
+      __pyx_t_6 = PyObject_Call(((PyObject *)((PyObject*)(&PyUnicode_Type))), ((PyObject *)__pyx_t_7), NULL); if (unlikely(!__pyx_t_6)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 54; __pyx_clineno = __LINE__; goto __pyx_L5;}
+      __Pyx_GOTREF(__pyx_t_6);
+      __Pyx_DECREF(((PyObject *)__pyx_t_7)); __pyx_t_7 = 0;
+      __Pyx_XGOTREF(((PyObject *)__pyx_cur_scope->__pyx_v_f_tree));
+      __Pyx_XDECREF(((PyObject *)__pyx_cur_scope->__pyx_v_f_tree));
+      __Pyx_GIVEREF(__pyx_t_6);
+      __pyx_cur_scope->__pyx_v_f_tree = ((PyObject*)__pyx_t_6);
+      __pyx_t_6 = 0;
+
+      /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":55
+ *                 if not f_derivation or not e_derivation: break
+ *                 f_tree = unicode(GetString(f_derivation._yield).c_str(), 'utf8')
+ *                 e_tree = unicode(GetString(e_derivation._yield).c_str(), 'utf8')             # <<<<<<<<<<<<<<
+ *                 yield (f_tree, e_tree)
+ *         finally:
+ */
+      __pyx_t_6 = PyBytes_FromString(TD::GetString(__pyx_cur_scope->__pyx_v_e_derivation->yield).c_str()); if (unlikely(!__pyx_t_6)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 55; __pyx_clineno = __LINE__; goto __pyx_L5;}
+      __Pyx_GOTREF(((PyObject *)__pyx_t_6));
+      __pyx_t_7 = PyTuple_New(2); if (unlikely(!__pyx_t_7)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 55; __pyx_clineno = __LINE__; goto __pyx_L5;}
+      __Pyx_GOTREF(__pyx_t_7);
+      PyTuple_SET_ITEM(__pyx_t_7, 0, ((PyObject *)__pyx_t_6));
+      __Pyx_GIVEREF(((PyObject *)__pyx_t_6));
+      __Pyx_INCREF(((PyObject *)__pyx_n_s__utf8));
+      PyTuple_SET_ITEM(__pyx_t_7, 1, ((PyObject *)__pyx_n_s__utf8));
+      __Pyx_GIVEREF(((PyObject *)__pyx_n_s__utf8));
+      __pyx_t_6 = 0;
+      __pyx_t_6 = PyObject_Call(((PyObject *)((PyObject*)(&PyUnicode_Type))), ((PyObject *)__pyx_t_7), NULL); if (unlikely(!__pyx_t_6)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 55; __pyx_clineno = __LINE__; goto __pyx_L5;}
+      __Pyx_GOTREF(__pyx_t_6);
+      __Pyx_DECREF(((PyObject *)__pyx_t_7)); __pyx_t_7 = 0;
+      __Pyx_XGOTREF(((PyObject *)__pyx_cur_scope->__pyx_v_e_tree));
+      __Pyx_XDECREF(((PyObject *)__pyx_cur_scope->__pyx_v_e_tree));
+      __Pyx_GIVEREF(__pyx_t_6);
+      __pyx_cur_scope->__pyx_v_e_tree = ((PyObject*)__pyx_t_6);
+      __pyx_t_6 = 0;
+
+      /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":56
+ *                 f_tree = unicode(GetString(f_derivation._yield).c_str(), 'utf8')
+ *                 e_tree = unicode(GetString(e_derivation._yield).c_str(), 'utf8')
+ *                 yield (f_tree, e_tree)             # <<<<<<<<<<<<<<
+ *         finally:
+ *             del f_derivations
+ */
+      __pyx_t_6 = PyTuple_New(2); if (unlikely(!__pyx_t_6)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 56; __pyx_clineno = __LINE__; goto __pyx_L5;}
+      __Pyx_GOTREF(__pyx_t_6);
+      __Pyx_INCREF(((PyObject *)__pyx_cur_scope->__pyx_v_f_tree));
+      PyTuple_SET_ITEM(__pyx_t_6, 0, ((PyObject *)__pyx_cur_scope->__pyx_v_f_tree));
+      __Pyx_GIVEREF(((PyObject *)__pyx_cur_scope->__pyx_v_f_tree));
+      __Pyx_INCREF(((PyObject *)__pyx_cur_scope->__pyx_v_e_tree));
+      PyTuple_SET_ITEM(__pyx_t_6, 1, ((PyObject *)__pyx_cur_scope->__pyx_v_e_tree));
+      __Pyx_GIVEREF(((PyObject *)__pyx_cur_scope->__pyx_v_e_tree));
+      __pyx_r = ((PyObject *)__pyx_t_6);
+      __pyx_t_6 = 0;
+      __pyx_cur_scope->__pyx_t_0 = __pyx_t_1;
+      __pyx_cur_scope->__pyx_t_1 = __pyx_t_2;
+      __Pyx_XGIVEREF(__pyx_r);
+      __Pyx_RefNannyFinishContext();
+      /* return from generator, yielding value */
+      __pyx_generator->resume_label = 1;
+      return __pyx_r;
+      __pyx_L10_resume_from_yield:;
+      __pyx_t_1 = __pyx_cur_scope->__pyx_t_0;
+      __pyx_t_2 = __pyx_cur_scope->__pyx_t_1;
+      if (unlikely(!__pyx_sent_value)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 56; __pyx_clineno = __LINE__; goto __pyx_L5;}
+    }
+    __pyx_L8_break:;
+  }
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":58
+ *                 yield (f_tree, e_tree)
+ *         finally:
+ *             del f_derivations             # <<<<<<<<<<<<<<
+ *             del e_derivations
+ * 
+ */
+  /*finally:*/ {
+    int __pyx_why;
+    PyObject *__pyx_exc_type, *__pyx_exc_value, *__pyx_exc_tb;
+    int __pyx_exc_lineno;
+    __pyx_exc_type = 0; __pyx_exc_value = 0; __pyx_exc_tb = 0; __pyx_exc_lineno = 0;
+    __pyx_why = 0; goto __pyx_L6;
+    __pyx_L5: {
+      __pyx_why = 4;
+      __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0;
+      __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0;
+      __Pyx_ErrFetch(&__pyx_exc_type, &__pyx_exc_value, &__pyx_exc_tb);
+      __pyx_exc_lineno = __pyx_lineno;
+      goto __pyx_L6;
+    }
+    __pyx_L6:;
+    delete __pyx_cur_scope->__pyx_v_f_derivations;
+
+    /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":59
+ *         finally:
+ *             del f_derivations
+ *             del e_derivations             # <<<<<<<<<<<<<<
+ * 
+ *     def kbest_features(self, size):
+ */
+    delete __pyx_cur_scope->__pyx_v_e_derivations;
+    switch (__pyx_why) {
+      case 4: {
+        __Pyx_ErrRestore(__pyx_exc_type, __pyx_exc_value, __pyx_exc_tb);
+        __pyx_lineno = __pyx_exc_lineno;
+        __pyx_exc_type = 0;
+        __pyx_exc_value = 0;
+        __pyx_exc_tb = 0;
+        goto __pyx_L1_error;
+      }
+    }
+  }
+  PyErr_SetNone(PyExc_StopIteration);
   goto __pyx_L0;
   __pyx_L1_error:;
-  __Pyx_XDECREF(__pyx_t_1);
-  __Pyx_XDECREF(__pyx_t_2);
-  __Pyx_AddTraceback("_cdec.HypergraphNode.span.__get__", __pyx_clineno, __pyx_lineno, __pyx_filename);
-  __pyx_r = NULL;
+  __Pyx_XDECREF(__pyx_t_6);
+  __Pyx_XDECREF(__pyx_t_7);
+  __Pyx_AddTraceback("kbest_trees", __pyx_clineno, __pyx_lineno, __pyx_filename);
   __pyx_L0:;
-  __Pyx_XGIVEREF(__pyx_r);
+  __Pyx_XDECREF(__pyx_r);
+  __pyx_generator->resume_label = -1;
   __Pyx_RefNannyFinishContext();
-  return __pyx_r;
+  return NULL;
 }
+static PyObject *__pyx_gb_5_cdec_10Hypergraph_18generator6(__pyx_GeneratorObject *__pyx_generator, PyObject *__pyx_sent_value); /* proto */
 
 /* Python wrapper */
-static PyObject *__pyx_pw_5_cdec_14HypergraphNode_3cat_1__get__(PyObject *__pyx_v_self); /*proto*/
-static PyObject *__pyx_pw_5_cdec_14HypergraphNode_3cat_1__get__(PyObject *__pyx_v_self) {
+static PyObject *__pyx_pw_5_cdec_10Hypergraph_17kbest_features(PyObject *__pyx_v_self, PyObject *__pyx_v_size); /*proto*/
+static PyObject *__pyx_pw_5_cdec_10Hypergraph_17kbest_features(PyObject *__pyx_v_self, PyObject *__pyx_v_size) {
   PyObject *__pyx_r = 0;
   __Pyx_RefNannyDeclarations
-  __Pyx_RefNannySetupContext("__get__ (wrapper)", 0);
-  __pyx_r = __pyx_pf_5_cdec_14HypergraphNode_3cat___get__(((struct __pyx_obj_5_cdec_HypergraphNode *)__pyx_v_self));
+  __Pyx_RefNannySetupContext("kbest_features (wrapper)", 0);
+  __pyx_r = __pyx_pf_5_cdec_10Hypergraph_16kbest_features(((struct __pyx_obj_5_cdec_Hypergraph *)__pyx_v_self), ((PyObject *)__pyx_v_size));
   __Pyx_RefNannyFinishContext();
   return __pyx_r;
 }
 
-/* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":205
+/* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":61
+ *             del e_derivations
  * 
- *     property cat:
- *         def __get__(self):             # <<<<<<<<<<<<<<
- *             if self.node.cat_:
- *                 return TDConvert(-self.node.cat_)
+ *     def kbest_features(self, size):             # <<<<<<<<<<<<<<
+ *         cdef kbest.KBestDerivations[FastSparseVector[weight_t], kbest.FeatureVectorTraversal]* derivations = new kbest.KBestDerivations[FastSparseVector[weight_t], kbest.FeatureVectorTraversal](self.hg[0], size)
+ *         cdef kbest.KBestDerivations[FastSparseVector[weight_t], kbest.FeatureVectorTraversal].Derivation* derivation
  */
 
-static PyObject *__pyx_pf_5_cdec_14HypergraphNode_3cat___get__(struct __pyx_obj_5_cdec_HypergraphNode *__pyx_v_self) {
+static PyObject *__pyx_pf_5_cdec_10Hypergraph_16kbest_features(struct __pyx_obj_5_cdec_Hypergraph *__pyx_v_self, PyObject *__pyx_v_size) {
+  struct __pyx_obj_5_cdec___pyx_scope_struct_10_kbest_features *__pyx_cur_scope;
   PyObject *__pyx_r = NULL;
   __Pyx_RefNannyDeclarations
-  PyObject *__pyx_t_1 = NULL;
   int __pyx_lineno = 0;
   const char *__pyx_filename = NULL;
   int __pyx_clineno = 0;
-  __Pyx_RefNannySetupContext("__get__", 0);
-
-  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":206
- *     property cat:
- *         def __get__(self):
- *             if self.node.cat_:             # <<<<<<<<<<<<<<
- *                 return TDConvert(-self.node.cat_)
- * 
- */
-  if (__pyx_v_self->node->cat_) {
-
-    /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":207
- *         def __get__(self):
- *             if self.node.cat_:
- *                 return TDConvert(-self.node.cat_)             # <<<<<<<<<<<<<<
- * 
- *     def __richcmp__(HypergraphNode x, HypergraphNode y, int op):
- */
-    __Pyx_XDECREF(__pyx_r);
-    __pyx_t_1 = PyBytes_FromString(TD::Convert((-__pyx_v_self->node->cat_))); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 207; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-    __Pyx_GOTREF(((PyObject *)__pyx_t_1));
-    __pyx_r = ((PyObject *)__pyx_t_1);
-    __pyx_t_1 = 0;
-    goto __pyx_L0;
-    goto __pyx_L3;
+  __Pyx_RefNannySetupContext("kbest_features", 0);
+  __pyx_cur_scope = (struct __pyx_obj_5_cdec___pyx_scope_struct_10_kbest_features *)__pyx_ptype_5_cdec___pyx_scope_struct_10_kbest_features->tp_new(__pyx_ptype_5_cdec___pyx_scope_struct_10_kbest_features, __pyx_empty_tuple, NULL);
+  if (unlikely(!__pyx_cur_scope)) {
+    __Pyx_RefNannyFinishContext();
+    return NULL;
+  }
+  __Pyx_GOTREF(__pyx_cur_scope);
+  __pyx_cur_scope->__pyx_v_self = __pyx_v_self;
+  __Pyx_INCREF((PyObject *)__pyx_cur_scope->__pyx_v_self);
+  __Pyx_GIVEREF((PyObject *)__pyx_cur_scope->__pyx_v_self);
+  __pyx_cur_scope->__pyx_v_size = __pyx_v_size;
+  __Pyx_INCREF(__pyx_cur_scope->__pyx_v_size);
+  __Pyx_GIVEREF(__pyx_cur_scope->__pyx_v_size);
+  {
+    __pyx_GeneratorObject *gen = __Pyx_Generator_New((__pyx_generator_body_t) __pyx_gb_5_cdec_10Hypergraph_18generator6, (PyObject *) __pyx_cur_scope); if (unlikely(!gen)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 61; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_DECREF(__pyx_cur_scope);
+    __Pyx_RefNannyFinishContext();
+    return (PyObject *) gen;
   }
-  __pyx_L3:;
 
   __pyx_r = Py_None; __Pyx_INCREF(Py_None);
   goto __pyx_L0;
   __pyx_L1_error:;
-  __Pyx_XDECREF(__pyx_t_1);
-  __Pyx_AddTraceback("_cdec.HypergraphNode.cat.__get__", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __Pyx_AddTraceback("_cdec.Hypergraph.kbest_features", __pyx_clineno, __pyx_lineno, __pyx_filename);
   __pyx_r = NULL;
   __pyx_L0:;
+  __Pyx_DECREF(((PyObject *)__pyx_cur_scope));
   __Pyx_XGIVEREF(__pyx_r);
   __Pyx_RefNannyFinishContext();
   return __pyx_r;
 }
 
-/* Python wrapper */
-static PyObject *__pyx_pw_5_cdec_14HypergraphNode_1__richcmp__(PyObject *__pyx_v_x, PyObject *__pyx_v_y, int __pyx_v_op); /*proto*/
-static PyObject *__pyx_pw_5_cdec_14HypergraphNode_1__richcmp__(PyObject *__pyx_v_x, PyObject *__pyx_v_y, int __pyx_v_op) {
-  PyObject *__pyx_r = 0;
+static PyObject *__pyx_gb_5_cdec_10Hypergraph_18generator6(__pyx_GeneratorObject *__pyx_generator, PyObject *__pyx_sent_value) /* generator body */
+{
+  struct __pyx_obj_5_cdec___pyx_scope_struct_10_kbest_features *__pyx_cur_scope = ((struct __pyx_obj_5_cdec___pyx_scope_struct_10_kbest_features *)__pyx_generator->closure);
+  PyObject *__pyx_r = NULL;
+  unsigned int __pyx_t_1;
+  long __pyx_t_2;
+  int __pyx_t_3;
+  PyObject *__pyx_t_4 = NULL;
   __Pyx_RefNannyDeclarations
-  __Pyx_RefNannySetupContext("__richcmp__ (wrapper)", 0);
-  if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_x), __pyx_ptype_5_cdec_HypergraphNode, 1, "x", 0))) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 209; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_y), __pyx_ptype_5_cdec_HypergraphNode, 1, "y", 0))) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 209; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __pyx_r = __pyx_pf_5_cdec_14HypergraphNode___richcmp__(((struct __pyx_obj_5_cdec_HypergraphNode *)__pyx_v_x), ((struct __pyx_obj_5_cdec_HypergraphNode *)__pyx_v_y), ((int)__pyx_v_op));
-  goto __pyx_L0;
-  __pyx_L1_error:;
-  __pyx_r = NULL;
-  __pyx_L0:;
-  __Pyx_RefNannyFinishContext();
-  return __pyx_r;
-}
-
-/* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":209
- *                 return TDConvert(-self.node.cat_)
- * 
- *     def __richcmp__(HypergraphNode x, HypergraphNode y, int op):             # <<<<<<<<<<<<<<
- *         if op == 2: # ==
- *             return x.node == y.node
+  __Pyx_RefNannySetupContext("None", 0);
+  switch (__pyx_generator->resume_label) {
+    case 0: goto __pyx_L3_first_run;
+    case 1: goto __pyx_L10_resume_from_yield;
+    default: /* CPython raises the right error here */
+    __Pyx_RefNannyFinishContext();
+    return NULL;
+  }
+  __pyx_L3_first_run:;
+  if (unlikely(!__pyx_sent_value)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 61; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":62
+ * 
+ *     def kbest_features(self, size):
+ *         cdef kbest.KBestDerivations[FastSparseVector[weight_t], kbest.FeatureVectorTraversal]* derivations = new kbest.KBestDerivations[FastSparseVector[weight_t], kbest.FeatureVectorTraversal](self.hg[0], size)             # <<<<<<<<<<<<<<
+ *         cdef kbest.KBestDerivations[FastSparseVector[weight_t], kbest.FeatureVectorTraversal].Derivation* derivation
+ *         cdef SparseVector fmap
  */
+  __pyx_t_1 = __Pyx_PyInt_AsUnsignedInt(__pyx_cur_scope->__pyx_v_size); if (unlikely((__pyx_t_1 == (unsigned int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 62; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_cur_scope->__pyx_v_derivations = new KBest::KBestDerivations<FastSparseVector<weight_t>,FeatureVectorTraversal>((__pyx_cur_scope->__pyx_v_self->hg[0]), __pyx_t_1);
 
-static PyObject *__pyx_pf_5_cdec_14HypergraphNode___richcmp__(struct __pyx_obj_5_cdec_HypergraphNode *__pyx_v_x, struct __pyx_obj_5_cdec_HypergraphNode *__pyx_v_y, int __pyx_v_op) {
-  PyObject *__pyx_r = NULL;
-  __Pyx_RefNannyDeclarations
-  PyObject *__pyx_t_1 = NULL;
-  int __pyx_t_2;
-  int __pyx_lineno = 0;
-  const char *__pyx_filename = NULL;
-  int __pyx_clineno = 0;
-  __Pyx_RefNannySetupContext("__richcmp__", 0);
+  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":66
+ *         cdef SparseVector fmap
+ *         cdef unsigned k
+ *         try:             # <<<<<<<<<<<<<<
+ *             for k in range(size):
+ *                 derivation = derivations.LazyKthBest(self.hg.nodes_.size() - 1, k)
+ */
+  /*try:*/ {
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":212
- *         if op == 2: # ==
- *             return x.node == y.node
- *         elif op == 3: # !=             # <<<<<<<<<<<<<<
- *             return not (x == y)
- *         raise NotImplemented('comparison not implemented for HypergraphNode')
+    /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":67
+ *         cdef unsigned k
+ *         try:
+ *             for k in range(size):             # <<<<<<<<<<<<<<
+ *                 derivation = derivations.LazyKthBest(self.hg.nodes_.size() - 1, k)
+ *                 if not derivation: break
  */
-  switch (__pyx_v_op) {
+    __pyx_t_2 = __Pyx_PyInt_AsLong(__pyx_cur_scope->__pyx_v_size); if (unlikely((__pyx_t_2 == (long)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 67; __pyx_clineno = __LINE__; goto __pyx_L5;}
+    for (__pyx_t_1 = 0; __pyx_t_1 < __pyx_t_2; __pyx_t_1+=1) {
+      __pyx_cur_scope->__pyx_v_k = __pyx_t_1;
 
-    /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":210
- * 
- *     def __richcmp__(HypergraphNode x, HypergraphNode y, int op):
- *         if op == 2: # ==             # <<<<<<<<<<<<<<
- *             return x.node == y.node
- *         elif op == 3: # !=
+      /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":68
+ *         try:
+ *             for k in range(size):
+ *                 derivation = derivations.LazyKthBest(self.hg.nodes_.size() - 1, k)             # <<<<<<<<<<<<<<
+ *                 if not derivation: break
+ *                 fmap = SparseVector()
  */
-    case 2:
+      __pyx_cur_scope->__pyx_v_derivation = __pyx_cur_scope->__pyx_v_derivations->LazyKthBest((__pyx_cur_scope->__pyx_v_self->hg->nodes_.size() - 1), __pyx_cur_scope->__pyx_v_k);
 
-    /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":211
- *     def __richcmp__(HypergraphNode x, HypergraphNode y, int op):
- *         if op == 2: # ==
- *             return x.node == y.node             # <<<<<<<<<<<<<<
- *         elif op == 3: # !=
- *             return not (x == y)
+      /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":69
+ *             for k in range(size):
+ *                 derivation = derivations.LazyKthBest(self.hg.nodes_.size() - 1, k)
+ *                 if not derivation: break             # <<<<<<<<<<<<<<
+ *                 fmap = SparseVector()
+ *                 fmap.vector = new FastSparseVector[weight_t](derivation._yield)
  */
-    __Pyx_XDECREF(__pyx_r);
-    __pyx_t_1 = __Pyx_PyBool_FromLong((__pyx_v_x->node == __pyx_v_y->node)); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 211; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-    __Pyx_GOTREF(__pyx_t_1);
-    __pyx_r = __pyx_t_1;
-    __pyx_t_1 = 0;
-    goto __pyx_L0;
-    break;
+      __pyx_t_3 = (!(__pyx_cur_scope->__pyx_v_derivation != 0));
+      if (__pyx_t_3) {
+        goto __pyx_L8_break;
+        goto __pyx_L9;
+      }
+      __pyx_L9:;
 
-    /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":212
- *         if op == 2: # ==
- *             return x.node == y.node
- *         elif op == 3: # !=             # <<<<<<<<<<<<<<
- *             return not (x == y)
- *         raise NotImplemented('comparison not implemented for HypergraphNode')
+      /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":70
+ *                 derivation = derivations.LazyKthBest(self.hg.nodes_.size() - 1, k)
+ *                 if not derivation: break
+ *                 fmap = SparseVector()             # <<<<<<<<<<<<<<
+ *                 fmap.vector = new FastSparseVector[weight_t](derivation._yield)
+ *                 yield fmap
  */
-    case 3:
+      __pyx_t_4 = PyObject_Call(((PyObject *)((PyObject*)__pyx_ptype_5_cdec_SparseVector)), ((PyObject *)__pyx_empty_tuple), NULL); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 70; __pyx_clineno = __LINE__; goto __pyx_L5;}
+      __Pyx_GOTREF(__pyx_t_4);
+      __Pyx_XGOTREF(((PyObject *)__pyx_cur_scope->__pyx_v_fmap));
+      __Pyx_XDECREF(((PyObject *)__pyx_cur_scope->__pyx_v_fmap));
+      __Pyx_GIVEREF(__pyx_t_4);
+      __pyx_cur_scope->__pyx_v_fmap = ((struct __pyx_obj_5_cdec_SparseVector *)__pyx_t_4);
+      __pyx_t_4 = 0;
 
-    /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":213
- *             return x.node == y.node
- *         elif op == 3: # !=
- *             return not (x == y)             # <<<<<<<<<<<<<<
- *         raise NotImplemented('comparison not implemented for HypergraphNode')
+      /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":71
+ *                 if not derivation: break
+ *                 fmap = SparseVector()
+ *                 fmap.vector = new FastSparseVector[weight_t](derivation._yield)             # <<<<<<<<<<<<<<
+ *                 yield fmap
+ *         finally:
  */
-    __Pyx_XDECREF(__pyx_r);
-    __pyx_t_1 = PyObject_RichCompare(((PyObject *)__pyx_v_x), ((PyObject *)__pyx_v_y), Py_EQ); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 213; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-    __Pyx_GOTREF(__pyx_t_1);
-    __pyx_t_2 = __Pyx_PyObject_IsTrue(__pyx_t_1); if (unlikely(__pyx_t_2 < 0)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 213; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-    __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
-    __pyx_t_1 = __Pyx_PyBool_FromLong((!__pyx_t_2)); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 213; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-    __Pyx_GOTREF(__pyx_t_1);
-    __pyx_r = __pyx_t_1;
-    __pyx_t_1 = 0;
-    goto __pyx_L0;
-    break;
-  }
+      __pyx_cur_scope->__pyx_v_fmap->vector = new FastSparseVector<weight_t>(__pyx_cur_scope->__pyx_v_derivation->yield);
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":214
- *         elif op == 3: # !=
- *             return not (x == y)
- *         raise NotImplemented('comparison not implemented for HypergraphNode')             # <<<<<<<<<<<<<<
+      /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":72
+ *                 fmap = SparseVector()
+ *                 fmap.vector = new FastSparseVector[weight_t](derivation._yield)
+ *                 yield fmap             # <<<<<<<<<<<<<<
+ *         finally:
+ *             del derivations
  */
-  __pyx_t_1 = PyObject_Call(__pyx_builtin_NotImplemented, ((PyObject *)__pyx_k_tuple_16), NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 214; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __Pyx_GOTREF(__pyx_t_1);
-  __Pyx_Raise(__pyx_t_1, 0, 0, 0);
-  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
-  {__pyx_filename = __pyx_f[2]; __pyx_lineno = 214; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __Pyx_INCREF(((PyObject *)__pyx_cur_scope->__pyx_v_fmap));
+      __pyx_r = ((PyObject *)__pyx_cur_scope->__pyx_v_fmap);
+      __pyx_cur_scope->__pyx_t_0 = __pyx_t_1;
+      __pyx_cur_scope->__pyx_t_1 = __pyx_t_2;
+      __Pyx_XGIVEREF(__pyx_r);
+      __Pyx_RefNannyFinishContext();
+      /* return from generator, yielding value */
+      __pyx_generator->resume_label = 1;
+      return __pyx_r;
+      __pyx_L10_resume_from_yield:;
+      __pyx_t_1 = __pyx_cur_scope->__pyx_t_0;
+      __pyx_t_2 = __pyx_cur_scope->__pyx_t_1;
+      if (unlikely(!__pyx_sent_value)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 72; __pyx_clineno = __LINE__; goto __pyx_L5;}
+    }
+    __pyx_L8_break:;
+  }
 
-  __pyx_r = Py_None; __Pyx_INCREF(Py_None);
+  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":74
+ *                 yield fmap
+ *         finally:
+ *             del derivations             # <<<<<<<<<<<<<<
+ * 
+ *     def sample(self, unsigned n):
+ */
+  /*finally:*/ {
+    int __pyx_why;
+    PyObject *__pyx_exc_type, *__pyx_exc_value, *__pyx_exc_tb;
+    int __pyx_exc_lineno;
+    __pyx_exc_type = 0; __pyx_exc_value = 0; __pyx_exc_tb = 0; __pyx_exc_lineno = 0;
+    __pyx_why = 0; goto __pyx_L6;
+    __pyx_L5: {
+      __pyx_why = 4;
+      __Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0;
+      __Pyx_ErrFetch(&__pyx_exc_type, &__pyx_exc_value, &__pyx_exc_tb);
+      __pyx_exc_lineno = __pyx_lineno;
+      goto __pyx_L6;
+    }
+    __pyx_L6:;
+    delete __pyx_cur_scope->__pyx_v_derivations;
+    switch (__pyx_why) {
+      case 4: {
+        __Pyx_ErrRestore(__pyx_exc_type, __pyx_exc_value, __pyx_exc_tb);
+        __pyx_lineno = __pyx_exc_lineno;
+        __pyx_exc_type = 0;
+        __pyx_exc_value = 0;
+        __pyx_exc_tb = 0;
+        goto __pyx_L1_error;
+      }
+    }
+  }
+  PyErr_SetNone(PyExc_StopIteration);
   goto __pyx_L0;
   __pyx_L1_error:;
-  __Pyx_XDECREF(__pyx_t_1);
-  __Pyx_AddTraceback("_cdec.HypergraphNode.__richcmp__", __pyx_clineno, __pyx_lineno, __pyx_filename);
-  __pyx_r = NULL;
+  __Pyx_XDECREF(__pyx_t_4);
+  __Pyx_AddTraceback("kbest_features", __pyx_clineno, __pyx_lineno, __pyx_filename);
   __pyx_L0:;
-  __Pyx_XGIVEREF(__pyx_r);
+  __Pyx_XDECREF(__pyx_r);
+  __pyx_generator->resume_label = -1;
   __Pyx_RefNannyFinishContext();
-  return __pyx_r;
+  return NULL;
 }
+static PyObject *__pyx_gb_5_cdec_10Hypergraph_21generator7(__pyx_GeneratorObject *__pyx_generator, PyObject *__pyx_sent_value); /* proto */
 
 /* Python wrapper */
-static int __pyx_pw_5_cdec_7Lattice_1__init__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/
-static int __pyx_pw_5_cdec_7Lattice_1__init__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) {
-  PyObject *__pyx_v_inp = 0;
-  static PyObject **__pyx_pyargnames[] = {&__pyx_n_s__inp,0};
-  int __pyx_r;
+static PyObject *__pyx_pw_5_cdec_10Hypergraph_20sample(PyObject *__pyx_v_self, PyObject *__pyx_arg_n); /*proto*/
+static PyObject *__pyx_pw_5_cdec_10Hypergraph_20sample(PyObject *__pyx_v_self, PyObject *__pyx_arg_n) {
+  unsigned int __pyx_v_n;
+  PyObject *__pyx_r = 0;
   __Pyx_RefNannyDeclarations
-  __Pyx_RefNannySetupContext("__init__ (wrapper)", 0);
-  {
-    PyObject* values[1] = {0};
-    if (unlikely(__pyx_kwds)) {
-      Py_ssize_t kw_args;
-      const Py_ssize_t pos_args = PyTuple_GET_SIZE(__pyx_args);
-      switch (pos_args) {
-        case  1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0);
-        case  0: break;
-        default: goto __pyx_L5_argtuple_error;
-      }
-      kw_args = PyDict_Size(__pyx_kwds);
-      switch (pos_args) {
-        case  0:
-        values[0] = PyDict_GetItem(__pyx_kwds, __pyx_n_s__inp);
-        if (likely(values[0])) kw_args--;
-        else goto __pyx_L5_argtuple_error;
-      }
-      if (unlikely(kw_args > 0)) {
-        if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "__init__") < 0)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 6; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
-      }
-    } else if (PyTuple_GET_SIZE(__pyx_args) != 1) {
-      goto __pyx_L5_argtuple_error;
-    } else {
-      values[0] = PyTuple_GET_ITEM(__pyx_args, 0);
-    }
-    __pyx_v_inp = values[0];
+  __Pyx_RefNannySetupContext("sample (wrapper)", 0);
+  assert(__pyx_arg_n); {
+    __pyx_v_n = __Pyx_PyInt_AsUnsignedInt(__pyx_arg_n); if (unlikely((__pyx_v_n == (unsigned int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 76; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
   }
   goto __pyx_L4_argument_unpacking_done;
-  __pyx_L5_argtuple_error:;
-  __Pyx_RaiseArgtupleInvalid("__init__", 1, 1, 1, PyTuple_GET_SIZE(__pyx_args)); {__pyx_filename = __pyx_f[3]; __pyx_lineno = 6; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
   __pyx_L3_error:;
-  __Pyx_AddTraceback("_cdec.Lattice.__init__", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __Pyx_AddTraceback("_cdec.Hypergraph.sample", __pyx_clineno, __pyx_lineno, __pyx_filename);
   __Pyx_RefNannyFinishContext();
-  return -1;
+  return NULL;
   __pyx_L4_argument_unpacking_done:;
-  __pyx_r = __pyx_pf_5_cdec_7Lattice___init__(((struct __pyx_obj_5_cdec_Lattice *)__pyx_v_self), __pyx_v_inp);
+  __pyx_r = __pyx_pf_5_cdec_10Hypergraph_19sample(((struct __pyx_obj_5_cdec_Hypergraph *)__pyx_v_self), ((unsigned int)__pyx_v_n));
   __Pyx_RefNannyFinishContext();
   return __pyx_r;
 }
 
-/* "/Users/vchahun/Sandbox/cdec/python/src/lattice.pxi":6
- *     cdef lattice.Lattice* lattice
+/* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":76
+ *             del derivations
  * 
- *     def __init__(self, inp):             # <<<<<<<<<<<<<<
- *         if isinstance(inp, tuple):
- *             self.lattice = new lattice.Lattice(len(inp))
+ *     def sample(self, unsigned n):             # <<<<<<<<<<<<<<
+ *         cdef vector[hypergraph.Hypothesis]* hypos = new vector[hypergraph.Hypothesis]()
+ *         if self.rng == NULL:
  */
 
-static int __pyx_pf_5_cdec_7Lattice___init__(struct __pyx_obj_5_cdec_Lattice *__pyx_v_self, PyObject *__pyx_v_inp) {
-  PyObject *__pyx_v_i = NULL;
-  PyObject *__pyx_v_arcs = NULL;
-  int __pyx_r;
+static PyObject *__pyx_pf_5_cdec_10Hypergraph_19sample(struct __pyx_obj_5_cdec_Hypergraph *__pyx_v_self, unsigned int __pyx_v_n) {
+  struct __pyx_obj_5_cdec___pyx_scope_struct_11_sample *__pyx_cur_scope;
+  PyObject *__pyx_r = NULL;
   __Pyx_RefNannyDeclarations
-  PyObject *__pyx_t_1 = NULL;
-  int __pyx_t_2;
-  Py_ssize_t __pyx_t_3;
-  PyObject *__pyx_t_4 = NULL;
-  PyObject *(*__pyx_t_5)(PyObject *);
-  PyObject *__pyx_t_6 = NULL;
-  int __pyx_t_7;
-  char *__pyx_t_8;
   int __pyx_lineno = 0;
   const char *__pyx_filename = NULL;
   int __pyx_clineno = 0;
-  __Pyx_RefNannySetupContext("__init__", 0);
-  __Pyx_INCREF(__pyx_v_inp);
+  __Pyx_RefNannySetupContext("sample", 0);
+  __pyx_cur_scope = (struct __pyx_obj_5_cdec___pyx_scope_struct_11_sample *)__pyx_ptype_5_cdec___pyx_scope_struct_11_sample->tp_new(__pyx_ptype_5_cdec___pyx_scope_struct_11_sample, __pyx_empty_tuple, NULL);
+  if (unlikely(!__pyx_cur_scope)) {
+    __Pyx_RefNannyFinishContext();
+    return NULL;
+  }
+  __Pyx_GOTREF(__pyx_cur_scope);
+  __pyx_cur_scope->__pyx_v_self = __pyx_v_self;
+  __Pyx_INCREF((PyObject *)__pyx_cur_scope->__pyx_v_self);
+  __Pyx_GIVEREF((PyObject *)__pyx_cur_scope->__pyx_v_self);
+  __pyx_cur_scope->__pyx_v_n = __pyx_v_n;
+  {
+    __pyx_GeneratorObject *gen = __Pyx_Generator_New((__pyx_generator_body_t) __pyx_gb_5_cdec_10Hypergraph_21generator7, (PyObject *) __pyx_cur_scope); if (unlikely(!gen)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 76; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_DECREF(__pyx_cur_scope);
+    __Pyx_RefNannyFinishContext();
+    return (PyObject *) gen;
+  }
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/lattice.pxi":7
- * 
- *     def __init__(self, inp):
- *         if isinstance(inp, tuple):             # <<<<<<<<<<<<<<
- *             self.lattice = new lattice.Lattice(len(inp))
- *             for i, arcs in enumerate(inp):
- */
-  __pyx_t_1 = ((PyObject *)((PyObject*)(&PyTuple_Type)));
-  __Pyx_INCREF(__pyx_t_1);
-  __pyx_t_2 = __Pyx_TypeCheck(__pyx_v_inp, __pyx_t_1); 
-  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
-  if (__pyx_t_2) {
+  __pyx_r = Py_None; __Pyx_INCREF(Py_None);
+  goto __pyx_L0;
+  __pyx_L1_error:;
+  __Pyx_AddTraceback("_cdec.Hypergraph.sample", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __pyx_r = NULL;
+  __pyx_L0:;
+  __Pyx_DECREF(((PyObject *)__pyx_cur_scope));
+  __Pyx_XGIVEREF(__pyx_r);
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
 
-    /* "/Users/vchahun/Sandbox/cdec/python/src/lattice.pxi":8
- *     def __init__(self, inp):
- *         if isinstance(inp, tuple):
- *             self.lattice = new lattice.Lattice(len(inp))             # <<<<<<<<<<<<<<
- *             for i, arcs in enumerate(inp):
- *                 self[i] = arcs
+static PyObject *__pyx_gb_5_cdec_10Hypergraph_21generator7(__pyx_GeneratorObject *__pyx_generator, PyObject *__pyx_sent_value) /* generator body */
+{
+  struct __pyx_obj_5_cdec___pyx_scope_struct_11_sample *__pyx_cur_scope = ((struct __pyx_obj_5_cdec___pyx_scope_struct_11_sample *)__pyx_generator->closure);
+  PyObject *__pyx_r = NULL;
+  int __pyx_t_1;
+  size_t __pyx_t_2;
+  unsigned int __pyx_t_3;
+  PyObject *__pyx_t_4 = NULL;
+  PyObject *__pyx_t_5 = NULL;
+  __Pyx_RefNannyDeclarations
+  __Pyx_RefNannySetupContext("None", 0);
+  switch (__pyx_generator->resume_label) {
+    case 0: goto __pyx_L3_first_run;
+    case 1: goto __pyx_L10_resume_from_yield;
+    default: /* CPython raises the right error here */
+    __Pyx_RefNannyFinishContext();
+    return NULL;
+  }
+  __pyx_L3_first_run:;
+  if (unlikely(!__pyx_sent_value)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 76; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":77
+ * 
+ *     def sample(self, unsigned n):
+ *         cdef vector[hypergraph.Hypothesis]* hypos = new vector[hypergraph.Hypothesis]()             # <<<<<<<<<<<<<<
+ *         if self.rng == NULL:
+ *             self.rng = new MT19937()
  */
-    __pyx_t_3 = PyObject_Length(__pyx_v_inp); if (unlikely(__pyx_t_3 == -1)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 8; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-    __pyx_v_self->lattice = new Lattice(__pyx_t_3);
+  __pyx_cur_scope->__pyx_v_hypos = new std::vector<HypergraphSampler::Hypothesis>();
 
-    /* "/Users/vchahun/Sandbox/cdec/python/src/lattice.pxi":9
- *         if isinstance(inp, tuple):
- *             self.lattice = new lattice.Lattice(len(inp))
- *             for i, arcs in enumerate(inp):             # <<<<<<<<<<<<<<
- *                 self[i] = arcs
- *         else:
+  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":78
+ *     def sample(self, unsigned n):
+ *         cdef vector[hypergraph.Hypothesis]* hypos = new vector[hypergraph.Hypothesis]()
+ *         if self.rng == NULL:             # <<<<<<<<<<<<<<
+ *             self.rng = new MT19937()
+ *         hypergraph.sample_hypotheses(self.hg[0], n, self.rng, hypos)
  */
-    __Pyx_INCREF(__pyx_int_0);
-    __pyx_t_1 = __pyx_int_0;
-    if (PyList_CheckExact(__pyx_v_inp) || PyTuple_CheckExact(__pyx_v_inp)) {
-      __pyx_t_4 = __pyx_v_inp; __Pyx_INCREF(__pyx_t_4); __pyx_t_3 = 0;
-      __pyx_t_5 = NULL;
-    } else {
-      __pyx_t_3 = -1; __pyx_t_4 = PyObject_GetIter(__pyx_v_inp); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 9; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-      __Pyx_GOTREF(__pyx_t_4);
-      __pyx_t_5 = Py_TYPE(__pyx_t_4)->tp_iternext;
-    }
-    for (;;) {
-      if (!__pyx_t_5 && PyList_CheckExact(__pyx_t_4)) {
-        if (__pyx_t_3 >= PyList_GET_SIZE(__pyx_t_4)) break;
-        __pyx_t_6 = PyList_GET_ITEM(__pyx_t_4, __pyx_t_3); __Pyx_INCREF(__pyx_t_6); __pyx_t_3++;
-      } else if (!__pyx_t_5 && PyTuple_CheckExact(__pyx_t_4)) {
-        if (__pyx_t_3 >= PyTuple_GET_SIZE(__pyx_t_4)) break;
-        __pyx_t_6 = PyTuple_GET_ITEM(__pyx_t_4, __pyx_t_3); __Pyx_INCREF(__pyx_t_6); __pyx_t_3++;
-      } else {
-        __pyx_t_6 = __pyx_t_5(__pyx_t_4);
-        if (unlikely(!__pyx_t_6)) {
-          if (PyErr_Occurred()) {
-            if (likely(PyErr_ExceptionMatches(PyExc_StopIteration))) PyErr_Clear();
-            else {__pyx_filename = __pyx_f[3]; __pyx_lineno = 9; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-          }
-          break;
-        }
-        __Pyx_GOTREF(__pyx_t_6);
-      }
-      __Pyx_XDECREF(__pyx_v_arcs);
-      __pyx_v_arcs = __pyx_t_6;
-      __pyx_t_6 = 0;
-      __Pyx_INCREF(__pyx_t_1);
-      __Pyx_XDECREF(__pyx_v_i);
-      __pyx_v_i = __pyx_t_1;
-      __pyx_t_6 = PyNumber_Add(__pyx_t_1, __pyx_int_1); if (unlikely(!__pyx_t_6)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 9; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-      __Pyx_GOTREF(__pyx_t_6);
-      __Pyx_DECREF(__pyx_t_1);
-      __pyx_t_1 = __pyx_t_6;
-      __pyx_t_6 = 0;
+  __pyx_t_1 = (__pyx_cur_scope->__pyx_v_self->rng == NULL);
+  if (__pyx_t_1) {
 
-      /* "/Users/vchahun/Sandbox/cdec/python/src/lattice.pxi":10
- *             self.lattice = new lattice.Lattice(len(inp))
- *             for i, arcs in enumerate(inp):
- *                 self[i] = arcs             # <<<<<<<<<<<<<<
- *         else:
- *             if isinstance(inp, unicode):
+    /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":79
+ *         cdef vector[hypergraph.Hypothesis]* hypos = new vector[hypergraph.Hypothesis]()
+ *         if self.rng == NULL:
+ *             self.rng = new MT19937()             # <<<<<<<<<<<<<<
+ *         hypergraph.sample_hypotheses(self.hg[0], n, self.rng, hypos)
+ *         cdef unsigned k
  */
-      if (PyObject_SetItem(((PyObject *)__pyx_v_self), __pyx_v_i, __pyx_v_arcs) < 0) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 10; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-    }
-    __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
-    __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
-    goto __pyx_L3;
+    __pyx_cur_scope->__pyx_v_self->rng = new MT19937();
+    goto __pyx_L4;
   }
-  /*else*/ {
+  __pyx_L4:;
 
-    /* "/Users/vchahun/Sandbox/cdec/python/src/lattice.pxi":12
- *                 self[i] = arcs
- *         else:
- *             if isinstance(inp, unicode):             # <<<<<<<<<<<<<<
- *                 inp = inp.encode('utf8')
- *             if not isinstance(inp, str):
+  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":80
+ *         if self.rng == NULL:
+ *             self.rng = new MT19937()
+ *         hypergraph.sample_hypotheses(self.hg[0], n, self.rng, hypos)             # <<<<<<<<<<<<<<
+ *         cdef unsigned k
+ *         try:
  */
-    __pyx_t_1 = ((PyObject *)((PyObject*)(&PyUnicode_Type)));
-    __Pyx_INCREF(__pyx_t_1);
-    __pyx_t_2 = __Pyx_TypeCheck(__pyx_v_inp, __pyx_t_1); 
-    __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
-    if (__pyx_t_2) {
+  HypergraphSampler::sample_hypotheses((__pyx_cur_scope->__pyx_v_self->hg[0]), __pyx_cur_scope->__pyx_v_n, __pyx_cur_scope->__pyx_v_self->rng, __pyx_cur_scope->__pyx_v_hypos);
 
-      /* "/Users/vchahun/Sandbox/cdec/python/src/lattice.pxi":13
- *         else:
- *             if isinstance(inp, unicode):
- *                 inp = inp.encode('utf8')             # <<<<<<<<<<<<<<
- *             if not isinstance(inp, str):
- *                 raise TypeError('Cannot create lattice from %s' % type(inp))
+  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":82
+ *         hypergraph.sample_hypotheses(self.hg[0], n, self.rng, hypos)
+ *         cdef unsigned k
+ *         try:             # <<<<<<<<<<<<<<
+ *             for k in range(hypos.size()):
+ *                 yield unicode(GetString(hypos[0][k].words).c_str(), 'utf8')
  */
-      __pyx_t_1 = PyObject_GetAttr(__pyx_v_inp, __pyx_n_s__encode); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 13; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-      __Pyx_GOTREF(__pyx_t_1);
-      __pyx_t_4 = PyObject_Call(__pyx_t_1, ((PyObject *)__pyx_k_tuple_17), NULL); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 13; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-      __Pyx_GOTREF(__pyx_t_4);
-      __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
-      __Pyx_DECREF(__pyx_v_inp);
-      __pyx_v_inp = __pyx_t_4;
-      __pyx_t_4 = 0;
-      goto __pyx_L6;
-    }
-    __pyx_L6:;
+  /*try:*/ {
 
-    /* "/Users/vchahun/Sandbox/cdec/python/src/lattice.pxi":14
- *             if isinstance(inp, unicode):
- *                 inp = inp.encode('utf8')
- *             if not isinstance(inp, str):             # <<<<<<<<<<<<<<
- *                 raise TypeError('Cannot create lattice from %s' % type(inp))
- *             self.lattice = new lattice.Lattice()
+    /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":83
+ *         cdef unsigned k
+ *         try:
+ *             for k in range(hypos.size()):             # <<<<<<<<<<<<<<
+ *                 yield unicode(GetString(hypos[0][k].words).c_str(), 'utf8')
+ *         finally:
  */
-    __pyx_t_4 = ((PyObject *)((PyObject*)(&PyString_Type)));
-    __Pyx_INCREF(__pyx_t_4);
-    __pyx_t_2 = __Pyx_TypeCheck(__pyx_v_inp, __pyx_t_4); 
-    __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
-    __pyx_t_7 = (!__pyx_t_2);
-    if (__pyx_t_7) {
+    __pyx_t_2 = __pyx_cur_scope->__pyx_v_hypos->size();
+    for (__pyx_t_3 = 0; __pyx_t_3 < __pyx_t_2; __pyx_t_3+=1) {
+      __pyx_cur_scope->__pyx_v_k = __pyx_t_3;
 
-      /* "/Users/vchahun/Sandbox/cdec/python/src/lattice.pxi":15
- *                 inp = inp.encode('utf8')
- *             if not isinstance(inp, str):
- *                 raise TypeError('Cannot create lattice from %s' % type(inp))             # <<<<<<<<<<<<<<
- *             self.lattice = new lattice.Lattice()
- *             lattice.ConvertTextToLattice(string(<char *>inp), self.lattice)
+      /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":84
+ *         try:
+ *             for k in range(hypos.size()):
+ *                 yield unicode(GetString(hypos[0][k].words).c_str(), 'utf8')             # <<<<<<<<<<<<<<
+ *         finally:
+ *             del hypos
  */
-      __pyx_t_4 = PyNumber_Remainder(((PyObject *)__pyx_kp_s_18), ((PyObject *)Py_TYPE(__pyx_v_inp))); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 15; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __pyx_t_4 = PyBytes_FromString(TD::GetString(((__pyx_cur_scope->__pyx_v_hypos[0])[__pyx_cur_scope->__pyx_v_k]).words).c_str()); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 84; __pyx_clineno = __LINE__; goto __pyx_L6;}
       __Pyx_GOTREF(((PyObject *)__pyx_t_4));
-      __pyx_t_1 = PyTuple_New(1); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 15; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-      __Pyx_GOTREF(__pyx_t_1);
-      PyTuple_SET_ITEM(__pyx_t_1, 0, ((PyObject *)__pyx_t_4));
+      __pyx_t_5 = PyTuple_New(2); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 84; __pyx_clineno = __LINE__; goto __pyx_L6;}
+      __Pyx_GOTREF(__pyx_t_5);
+      PyTuple_SET_ITEM(__pyx_t_5, 0, ((PyObject *)__pyx_t_4));
       __Pyx_GIVEREF(((PyObject *)__pyx_t_4));
+      __Pyx_INCREF(((PyObject *)__pyx_n_s__utf8));
+      PyTuple_SET_ITEM(__pyx_t_5, 1, ((PyObject *)__pyx_n_s__utf8));
+      __Pyx_GIVEREF(((PyObject *)__pyx_n_s__utf8));
       __pyx_t_4 = 0;
-      __pyx_t_4 = PyObject_Call(__pyx_builtin_TypeError, ((PyObject *)__pyx_t_1), NULL); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 15; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __pyx_t_4 = PyObject_Call(((PyObject *)((PyObject*)(&PyUnicode_Type))), ((PyObject *)__pyx_t_5), NULL); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 84; __pyx_clineno = __LINE__; goto __pyx_L6;}
       __Pyx_GOTREF(__pyx_t_4);
-      __Pyx_DECREF(((PyObject *)__pyx_t_1)); __pyx_t_1 = 0;
-      __Pyx_Raise(__pyx_t_4, 0, 0, 0);
-      __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
-      {__pyx_filename = __pyx_f[3]; __pyx_lineno = 15; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-      goto __pyx_L7;
+      __Pyx_DECREF(((PyObject *)__pyx_t_5)); __pyx_t_5 = 0;
+      __pyx_r = __pyx_t_4;
+      __pyx_t_4 = 0;
+      __pyx_cur_scope->__pyx_t_0 = __pyx_t_2;
+      __pyx_cur_scope->__pyx_t_1 = __pyx_t_3;
+      __Pyx_XGIVEREF(__pyx_r);
+      __Pyx_RefNannyFinishContext();
+      /* return from generator, yielding value */
+      __pyx_generator->resume_label = 1;
+      return __pyx_r;
+      __pyx_L10_resume_from_yield:;
+      __pyx_t_2 = __pyx_cur_scope->__pyx_t_0;
+      __pyx_t_3 = __pyx_cur_scope->__pyx_t_1;
+      if (unlikely(!__pyx_sent_value)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 84; __pyx_clineno = __LINE__; goto __pyx_L6;}
     }
-    __pyx_L7:;
+  }
 
-    /* "/Users/vchahun/Sandbox/cdec/python/src/lattice.pxi":16
- *             if not isinstance(inp, str):
- *                 raise TypeError('Cannot create lattice from %s' % type(inp))
- *             self.lattice = new lattice.Lattice()             # <<<<<<<<<<<<<<
- *             lattice.ConvertTextToLattice(string(<char *>inp), self.lattice)
+  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":86
+ *                 yield unicode(GetString(hypos[0][k].words).c_str(), 'utf8')
+ *         finally:
+ *             del hypos             # <<<<<<<<<<<<<<
  * 
+ *     def intersect(self, Lattice lat):
  */
-    __pyx_v_self->lattice = new Lattice();
-
-    /* "/Users/vchahun/Sandbox/cdec/python/src/lattice.pxi":17
- *                 raise TypeError('Cannot create lattice from %s' % type(inp))
- *             self.lattice = new lattice.Lattice()
- *             lattice.ConvertTextToLattice(string(<char *>inp), self.lattice)             # <<<<<<<<<<<<<<
+  /*finally:*/ {
+    int __pyx_why;
+    PyObject *__pyx_exc_type, *__pyx_exc_value, *__pyx_exc_tb;
+    int __pyx_exc_lineno;
+    __pyx_exc_type = 0; __pyx_exc_value = 0; __pyx_exc_tb = 0; __pyx_exc_lineno = 0;
+    __pyx_why = 0; goto __pyx_L7;
+    __pyx_L6: {
+      __pyx_why = 4;
+      __Pyx_XDECREF(__pyx_t_5); __pyx_t_5 = 0;
+      __Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0;
+      __Pyx_ErrFetch(&__pyx_exc_type, &__pyx_exc_value, &__pyx_exc_tb);
+      __pyx_exc_lineno = __pyx_lineno;
+      goto __pyx_L7;
+    }
+    __pyx_L7:;
+    delete __pyx_cur_scope->__pyx_v_hypos;
+    switch (__pyx_why) {
+      case 4: {
+        __Pyx_ErrRestore(__pyx_exc_type, __pyx_exc_value, __pyx_exc_tb);
+        __pyx_lineno = __pyx_exc_lineno;
+        __pyx_exc_type = 0;
+        __pyx_exc_value = 0;
+        __pyx_exc_tb = 0;
+        goto __pyx_L1_error;
+      }
+    }
+  }
+  PyErr_SetNone(PyExc_StopIteration);
+  goto __pyx_L0;
+  __pyx_L1_error:;
+  __Pyx_XDECREF(__pyx_t_4);
+  __Pyx_XDECREF(__pyx_t_5);
+  __Pyx_AddTraceback("sample", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __pyx_L0:;
+  __Pyx_XDECREF(__pyx_r);
+  __pyx_generator->resume_label = -1;
+  __Pyx_RefNannyFinishContext();
+  return NULL;
+}
+
+/* Python wrapper */
+static PyObject *__pyx_pw_5_cdec_10Hypergraph_23intersect(PyObject *__pyx_v_self, PyObject *__pyx_v_lat); /*proto*/
+static PyObject *__pyx_pw_5_cdec_10Hypergraph_23intersect(PyObject *__pyx_v_self, PyObject *__pyx_v_lat) {
+  PyObject *__pyx_r = 0;
+  __Pyx_RefNannyDeclarations
+  __Pyx_RefNannySetupContext("intersect (wrapper)", 0);
+  if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_lat), __pyx_ptype_5_cdec_Lattice, 1, "lat", 0))) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 88; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_r = __pyx_pf_5_cdec_10Hypergraph_22intersect(((struct __pyx_obj_5_cdec_Hypergraph *)__pyx_v_self), ((struct __pyx_obj_5_cdec_Lattice *)__pyx_v_lat));
+  goto __pyx_L0;
+  __pyx_L1_error:;
+  __pyx_r = NULL;
+  __pyx_L0:;
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+/* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":88
+ *             del hypos
+ * 
+ *     def intersect(self, Lattice lat):             # <<<<<<<<<<<<<<
+ *         return hypergraph.Intersect(lat.lattice[0], self.hg)
  * 
- *     def __getitem__(self, int index):
  */
-    __pyx_t_8 = PyBytes_AsString(__pyx_v_inp); if (unlikely((!__pyx_t_8) && PyErr_Occurred())) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 17; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-    LatticeTools::ConvertTextToLattice(std::string(((char *)__pyx_t_8)), __pyx_v_self->lattice);
-  }
-  __pyx_L3:;
 
-  __pyx_r = 0;
+static PyObject *__pyx_pf_5_cdec_10Hypergraph_22intersect(struct __pyx_obj_5_cdec_Hypergraph *__pyx_v_self, struct __pyx_obj_5_cdec_Lattice *__pyx_v_lat) {
+  PyObject *__pyx_r = NULL;
+  __Pyx_RefNannyDeclarations
+  PyObject *__pyx_t_1 = NULL;
+  int __pyx_lineno = 0;
+  const char *__pyx_filename = NULL;
+  int __pyx_clineno = 0;
+  __Pyx_RefNannySetupContext("intersect", 0);
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":89
+ * 
+ *     def intersect(self, Lattice lat):
+ *         return hypergraph.Intersect(lat.lattice[0], self.hg)             # <<<<<<<<<<<<<<
+ * 
+ *     def prune(self, beam_alpha=0, density=0, **kwargs):
+ */
+  __Pyx_XDECREF(__pyx_r);
+  __pyx_t_1 = __Pyx_PyBool_FromLong(HG::Intersect((__pyx_v_lat->lattice[0]), __pyx_v_self->hg)); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 89; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_1);
+  __pyx_r = __pyx_t_1;
+  __pyx_t_1 = 0;
+  goto __pyx_L0;
+
+  __pyx_r = Py_None; __Pyx_INCREF(Py_None);
   goto __pyx_L0;
   __pyx_L1_error:;
   __Pyx_XDECREF(__pyx_t_1);
-  __Pyx_XDECREF(__pyx_t_4);
-  __Pyx_XDECREF(__pyx_t_6);
-  __Pyx_AddTraceback("_cdec.Lattice.__init__", __pyx_clineno, __pyx_lineno, __pyx_filename);
-  __pyx_r = -1;
+  __Pyx_AddTraceback("_cdec.Hypergraph.intersect", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __pyx_r = NULL;
   __pyx_L0:;
-  __Pyx_XDECREF(__pyx_v_i);
-  __Pyx_XDECREF(__pyx_v_arcs);
-  __Pyx_XDECREF(__pyx_v_inp);
+  __Pyx_XGIVEREF(__pyx_r);
   __Pyx_RefNannyFinishContext();
   return __pyx_r;
 }
 
 /* Python wrapper */
-static PyObject *__pyx_pw_5_cdec_7Lattice_3__getitem__(PyObject *__pyx_v_self, PyObject *__pyx_arg_index); /*proto*/
-static PyObject *__pyx_pw_5_cdec_7Lattice_3__getitem__(PyObject *__pyx_v_self, PyObject *__pyx_arg_index) {
-  int __pyx_v_index;
+static PyObject *__pyx_pw_5_cdec_10Hypergraph_25prune(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/
+static PyObject *__pyx_pw_5_cdec_10Hypergraph_25prune(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) {
+  PyObject *__pyx_v_beam_alpha = 0;
+  PyObject *__pyx_v_density = 0;
+  PyObject *__pyx_v_kwargs = 0;
+  static PyObject **__pyx_pyargnames[] = {&__pyx_n_s__beam_alpha,&__pyx_n_s__density,0};
   PyObject *__pyx_r = 0;
   __Pyx_RefNannyDeclarations
-  __Pyx_RefNannySetupContext("__getitem__ (wrapper)", 0);
-  assert(__pyx_arg_index); {
-    __pyx_v_index = __Pyx_PyInt_AsInt(__pyx_arg_index); if (unlikely((__pyx_v_index == (int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 19; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+  __Pyx_RefNannySetupContext("prune (wrapper)", 0);
+  __pyx_v_kwargs = PyDict_New(); if (unlikely(!__pyx_v_kwargs)) return NULL;
+  __Pyx_GOTREF(__pyx_v_kwargs);
+  {
+    PyObject* values[2] = {0,0};
+    values[0] = ((PyObject *)__pyx_int_0);
+    values[1] = ((PyObject *)__pyx_int_0);
+    if (unlikely(__pyx_kwds)) {
+      Py_ssize_t kw_args;
+      const Py_ssize_t pos_args = PyTuple_GET_SIZE(__pyx_args);
+      switch (pos_args) {
+        case  2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1);
+        case  1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0);
+        case  0: break;
+        default: goto __pyx_L5_argtuple_error;
+      }
+      kw_args = PyDict_Size(__pyx_kwds);
+      switch (pos_args) {
+        case  0:
+        if (kw_args > 0) {
+          PyObject* value = PyDict_GetItem(__pyx_kwds, __pyx_n_s__beam_alpha);
+          if (value) { values[0] = value; kw_args--; }
+        }
+        case  1:
+        if (kw_args > 0) {
+          PyObject* value = PyDict_GetItem(__pyx_kwds, __pyx_n_s__density);
+          if (value) { values[1] = value; kw_args--; }
+        }
+      }
+      if (unlikely(kw_args > 0)) {
+        if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, __pyx_v_kwargs, values, pos_args, "prune") < 0)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 91; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+      }
+    } else {
+      switch (PyTuple_GET_SIZE(__pyx_args)) {
+        case  2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1);
+        case  1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0);
+        case  0: break;
+        default: goto __pyx_L5_argtuple_error;
+      }
+    }
+    __pyx_v_beam_alpha = values[0];
+    __pyx_v_density = values[1];
   }
   goto __pyx_L4_argument_unpacking_done;
+  __pyx_L5_argtuple_error:;
+  __Pyx_RaiseArgtupleInvalid("prune", 0, 0, 2, PyTuple_GET_SIZE(__pyx_args)); {__pyx_filename = __pyx_f[3]; __pyx_lineno = 91; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
   __pyx_L3_error:;
-  __Pyx_AddTraceback("_cdec.Lattice.__getitem__", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __Pyx_DECREF(__pyx_v_kwargs); __pyx_v_kwargs = 0;
+  __Pyx_AddTraceback("_cdec.Hypergraph.prune", __pyx_clineno, __pyx_lineno, __pyx_filename);
   __Pyx_RefNannyFinishContext();
   return NULL;
   __pyx_L4_argument_unpacking_done:;
-  __pyx_r = __pyx_pf_5_cdec_7Lattice_2__getitem__(((struct __pyx_obj_5_cdec_Lattice *)__pyx_v_self), ((int)__pyx_v_index));
+  __pyx_r = __pyx_pf_5_cdec_10Hypergraph_24prune(((struct __pyx_obj_5_cdec_Hypergraph *)__pyx_v_self), __pyx_v_beam_alpha, __pyx_v_density, __pyx_v_kwargs);
+  __Pyx_XDECREF(__pyx_v_kwargs);
   __Pyx_RefNannyFinishContext();
   return __pyx_r;
 }
 
-/* "/Users/vchahun/Sandbox/cdec/python/src/lattice.pxi":19
- *             lattice.ConvertTextToLattice(string(<char *>inp), self.lattice)
+/* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":91
+ *         return hypergraph.Intersect(lat.lattice[0], self.hg)
  * 
- *     def __getitem__(self, int index):             # <<<<<<<<<<<<<<
- *         if not 0 <= index < len(self):
- *             raise IndexError('lattice index out of range')
+ *     def prune(self, beam_alpha=0, density=0, **kwargs):             # <<<<<<<<<<<<<<
+ *         cdef hypergraph.EdgeMask* preserve_mask = NULL
+ *         if 'csplit_preserve_full_word' in kwargs:
  */
 
-static PyObject *__pyx_pf_5_cdec_7Lattice_2__getitem__(struct __pyx_obj_5_cdec_Lattice *__pyx_v_self, int __pyx_v_index) {
-  PyObject *__pyx_v_arcs = NULL;
-  std::vector<LatticeArc> __pyx_v_arc_vector;
-  LatticeArc *__pyx_v_arc;
-  unsigned int __pyx_v_i;
-  PyObject *__pyx_v_label = NULL;
+static PyObject *__pyx_pf_5_cdec_10Hypergraph_24prune(struct __pyx_obj_5_cdec_Hypergraph *__pyx_v_self, PyObject *__pyx_v_beam_alpha, PyObject *__pyx_v_density, PyObject *__pyx_v_kwargs) {
+  std::vector<bool> *__pyx_v_preserve_mask;
   PyObject *__pyx_r = NULL;
   __Pyx_RefNannyDeclarations
   int __pyx_t_1;
-  Py_ssize_t __pyx_t_2;
-  int __pyx_t_3;
-  PyObject *__pyx_t_4 = NULL;
-  size_t __pyx_t_5;
-  unsigned int __pyx_t_6;
-  PyObject *__pyx_t_7 = NULL;
-  PyObject *__pyx_t_8 = NULL;
-  int __pyx_t_9;
+  double __pyx_t_2;
+  double __pyx_t_3;
   int __pyx_lineno = 0;
   const char *__pyx_filename = NULL;
   int __pyx_clineno = 0;
-  __Pyx_RefNannySetupContext("__getitem__", 0);
+  __Pyx_RefNannySetupContext("prune", 0);
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/lattice.pxi":20
+  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":92
  * 
- *     def __getitem__(self, int index):
- *         if not 0 <= index < len(self):             # <<<<<<<<<<<<<<
- *             raise IndexError('lattice index out of range')
- *         arcs = []
+ *     def prune(self, beam_alpha=0, density=0, **kwargs):
+ *         cdef hypergraph.EdgeMask* preserve_mask = NULL             # <<<<<<<<<<<<<<
+ *         if 'csplit_preserve_full_word' in kwargs:
+ *              preserve_mask = new hypergraph.EdgeMask(self.hg.edges_.size())
  */
-  __pyx_t_1 = (0 <= __pyx_v_index);
+  __pyx_v_preserve_mask = NULL;
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":93
+ *     def prune(self, beam_alpha=0, density=0, **kwargs):
+ *         cdef hypergraph.EdgeMask* preserve_mask = NULL
+ *         if 'csplit_preserve_full_word' in kwargs:             # <<<<<<<<<<<<<<
+ *              preserve_mask = new hypergraph.EdgeMask(self.hg.edges_.size())
+ *              preserve_mask[0][hypergraph.GetFullWordEdgeIndex(self.hg[0])] = True
+ */
+  __pyx_t_1 = ((PyDict_Contains(((PyObject *)__pyx_v_kwargs), ((PyObject *)__pyx_n_s_15)))); if (unlikely(__pyx_t_1 < 0)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 93; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   if (__pyx_t_1) {
-    __pyx_t_2 = PyObject_Length(((PyObject *)__pyx_v_self)); if (unlikely(__pyx_t_2 == -1)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 20; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-    __pyx_t_1 = (__pyx_v_index < __pyx_t_2);
-  }
-  __pyx_t_3 = (!__pyx_t_1);
-  if (__pyx_t_3) {
 
-    /* "/Users/vchahun/Sandbox/cdec/python/src/lattice.pxi":21
- *     def __getitem__(self, int index):
- *         if not 0 <= index < len(self):
- *             raise IndexError('lattice index out of range')             # <<<<<<<<<<<<<<
- *         arcs = []
- *         cdef vector[lattice.LatticeArc] arc_vector = self.lattice[0][index]
+    /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":94
+ *         cdef hypergraph.EdgeMask* preserve_mask = NULL
+ *         if 'csplit_preserve_full_word' in kwargs:
+ *              preserve_mask = new hypergraph.EdgeMask(self.hg.edges_.size())             # <<<<<<<<<<<<<<
+ *              preserve_mask[0][hypergraph.GetFullWordEdgeIndex(self.hg[0])] = True
+ *         self.hg.PruneInsideOutside(beam_alpha, density, preserve_mask, False, 1, False)
  */
-    __pyx_t_4 = PyObject_Call(__pyx_builtin_IndexError, ((PyObject *)__pyx_k_tuple_20), NULL); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 21; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-    __Pyx_GOTREF(__pyx_t_4);
-    __Pyx_Raise(__pyx_t_4, 0, 0, 0);
-    __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
-    {__pyx_filename = __pyx_f[3]; __pyx_lineno = 21; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_v_preserve_mask = new std::vector<bool>(__pyx_v_self->hg->edges_.size());
+
+    /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":95
+ *         if 'csplit_preserve_full_word' in kwargs:
+ *              preserve_mask = new hypergraph.EdgeMask(self.hg.edges_.size())
+ *              preserve_mask[0][hypergraph.GetFullWordEdgeIndex(self.hg[0])] = True             # <<<<<<<<<<<<<<
+ *         self.hg.PruneInsideOutside(beam_alpha, density, preserve_mask, False, 1, False)
+ *         if preserve_mask:
+ */
+    ((__pyx_v_preserve_mask[0])[CompoundSplit::GetFullWordEdgeIndex((__pyx_v_self->hg[0]))]) = 1;
     goto __pyx_L3;
   }
   __pyx_L3:;
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/lattice.pxi":22
- *         if not 0 <= index < len(self):
- *             raise IndexError('lattice index out of range')
- *         arcs = []             # <<<<<<<<<<<<<<
- *         cdef vector[lattice.LatticeArc] arc_vector = self.lattice[0][index]
- *         cdef lattice.LatticeArc* arc
+  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":96
+ *              preserve_mask = new hypergraph.EdgeMask(self.hg.edges_.size())
+ *              preserve_mask[0][hypergraph.GetFullWordEdgeIndex(self.hg[0])] = True
+ *         self.hg.PruneInsideOutside(beam_alpha, density, preserve_mask, False, 1, False)             # <<<<<<<<<<<<<<
+ *         if preserve_mask:
+ *             del preserve_mask
  */
-  __pyx_t_4 = PyList_New(0); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 22; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __Pyx_GOTREF(__pyx_t_4);
-  __pyx_v_arcs = __pyx_t_4;
-  __pyx_t_4 = 0;
+  __pyx_t_2 = __pyx_PyFloat_AsDouble(__pyx_v_beam_alpha); if (unlikely((__pyx_t_2 == (double)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 96; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_3 = __pyx_PyFloat_AsDouble(__pyx_v_density); if (unlikely((__pyx_t_3 == (double)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 96; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_v_self->hg->PruneInsideOutside(__pyx_t_2, __pyx_t_3, __pyx_v_preserve_mask, 0, 1.0, 0);
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/lattice.pxi":23
- *             raise IndexError('lattice index out of range')
- *         arcs = []
- *         cdef vector[lattice.LatticeArc] arc_vector = self.lattice[0][index]             # <<<<<<<<<<<<<<
- *         cdef lattice.LatticeArc* arc
- *         cdef unsigned i
+  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":97
+ *              preserve_mask[0][hypergraph.GetFullWordEdgeIndex(self.hg[0])] = True
+ *         self.hg.PruneInsideOutside(beam_alpha, density, preserve_mask, False, 1, False)
+ *         if preserve_mask:             # <<<<<<<<<<<<<<
+ *             del preserve_mask
+ * 
  */
-  __pyx_v_arc_vector = ((__pyx_v_self->lattice[0])[__pyx_v_index]);
+  __pyx_t_1 = (__pyx_v_preserve_mask != 0);
+  if (__pyx_t_1) {
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/lattice.pxi":26
- *         cdef lattice.LatticeArc* arc
- *         cdef unsigned i
- *         for i in range(arc_vector.size()):             # <<<<<<<<<<<<<<
- *             arc = &arc_vector[i]
- *             label = unicode(TDConvert(arc.label), 'utf8')
+    /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":98
+ *         self.hg.PruneInsideOutside(beam_alpha, density, preserve_mask, False, 1, False)
+ *         if preserve_mask:
+ *             del preserve_mask             # <<<<<<<<<<<<<<
+ * 
+ *     def lattice(self): # TODO direct hg -> lattice conversion in cdec
  */
-  __pyx_t_5 = __pyx_v_arc_vector.size();
-  for (__pyx_t_6 = 0; __pyx_t_6 < __pyx_t_5; __pyx_t_6+=1) {
-    __pyx_v_i = __pyx_t_6;
+    delete __pyx_v_preserve_mask;
+    goto __pyx_L4;
+  }
+  __pyx_L4:;
 
-    /* "/Users/vchahun/Sandbox/cdec/python/src/lattice.pxi":27
- *         cdef unsigned i
- *         for i in range(arc_vector.size()):
- *             arc = &arc_vector[i]             # <<<<<<<<<<<<<<
- *             label = unicode(TDConvert(arc.label), 'utf8')
- *             arcs.append((label, arc.cost, arc.dist2next))
- */
-    __pyx_v_arc = (&(__pyx_v_arc_vector[__pyx_v_i]));
+  __pyx_r = Py_None; __Pyx_INCREF(Py_None);
+  goto __pyx_L0;
+  __pyx_L1_error:;
+  __Pyx_AddTraceback("_cdec.Hypergraph.prune", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __pyx_r = NULL;
+  __pyx_L0:;
+  __Pyx_XGIVEREF(__pyx_r);
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
 
-    /* "/Users/vchahun/Sandbox/cdec/python/src/lattice.pxi":28
- *         for i in range(arc_vector.size()):
- *             arc = &arc_vector[i]
- *             label = unicode(TDConvert(arc.label), 'utf8')             # <<<<<<<<<<<<<<
- *             arcs.append((label, arc.cost, arc.dist2next))
- *         return tuple(arcs)
+/* Python wrapper */
+static PyObject *__pyx_pw_5_cdec_10Hypergraph_27lattice(PyObject *__pyx_v_self, CYTHON_UNUSED PyObject *unused); /*proto*/
+static PyObject *__pyx_pw_5_cdec_10Hypergraph_27lattice(PyObject *__pyx_v_self, CYTHON_UNUSED PyObject *unused) {
+  PyObject *__pyx_r = 0;
+  __Pyx_RefNannyDeclarations
+  __Pyx_RefNannySetupContext("lattice (wrapper)", 0);
+  __pyx_r = __pyx_pf_5_cdec_10Hypergraph_26lattice(((struct __pyx_obj_5_cdec_Hypergraph *)__pyx_v_self));
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+/* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":100
+ *             del preserve_mask
+ * 
+ *     def lattice(self): # TODO direct hg -> lattice conversion in cdec             # <<<<<<<<<<<<<<
+ *         cdef str plf = hypergraph.AsPLF(self.hg[0], True).c_str()
+ *         return Lattice(eval(plf))
  */
-    __pyx_t_4 = PyBytes_FromString(TD::Convert(__pyx_v_arc->label)); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 28; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-    __Pyx_GOTREF(((PyObject *)__pyx_t_4));
-    __pyx_t_7 = PyTuple_New(2); if (unlikely(!__pyx_t_7)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 28; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-    __Pyx_GOTREF(__pyx_t_7);
-    PyTuple_SET_ITEM(__pyx_t_7, 0, ((PyObject *)__pyx_t_4));
-    __Pyx_GIVEREF(((PyObject *)__pyx_t_4));
-    __Pyx_INCREF(((PyObject *)__pyx_n_s__utf8));
-    PyTuple_SET_ITEM(__pyx_t_7, 1, ((PyObject *)__pyx_n_s__utf8));
-    __Pyx_GIVEREF(((PyObject *)__pyx_n_s__utf8));
-    __pyx_t_4 = 0;
-    __pyx_t_4 = PyObject_Call(((PyObject *)((PyObject*)(&PyUnicode_Type))), ((PyObject *)__pyx_t_7), NULL); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 28; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-    __Pyx_GOTREF(__pyx_t_4);
-    __Pyx_DECREF(((PyObject *)__pyx_t_7)); __pyx_t_7 = 0;
-    __Pyx_XDECREF(((PyObject *)__pyx_v_label));
-    __pyx_v_label = ((PyObject*)__pyx_t_4);
-    __pyx_t_4 = 0;
 
-    /* "/Users/vchahun/Sandbox/cdec/python/src/lattice.pxi":29
- *             arc = &arc_vector[i]
- *             label = unicode(TDConvert(arc.label), 'utf8')
- *             arcs.append((label, arc.cost, arc.dist2next))             # <<<<<<<<<<<<<<
- *         return tuple(arcs)
+static PyObject *__pyx_pf_5_cdec_10Hypergraph_26lattice(struct __pyx_obj_5_cdec_Hypergraph *__pyx_v_self) {
+  PyObject *__pyx_v_plf = 0;
+  PyObject *__pyx_r = NULL;
+  __Pyx_RefNannyDeclarations
+  PyObject *__pyx_t_1 = NULL;
+  PyObject *__pyx_t_2 = NULL;
+  PyObject *__pyx_t_3 = NULL;
+  int __pyx_lineno = 0;
+  const char *__pyx_filename = NULL;
+  int __pyx_clineno = 0;
+  __Pyx_RefNannySetupContext("lattice", 0);
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":101
+ * 
+ *     def lattice(self): # TODO direct hg -> lattice conversion in cdec
+ *         cdef str plf = hypergraph.AsPLF(self.hg[0], True).c_str()             # <<<<<<<<<<<<<<
+ *         return Lattice(eval(plf))
  * 
  */
-    __pyx_t_4 = PyFloat_FromDouble(__pyx_v_arc->cost); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 29; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-    __Pyx_GOTREF(__pyx_t_4);
-    __pyx_t_7 = PyInt_FromLong(__pyx_v_arc->dist2next); if (unlikely(!__pyx_t_7)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 29; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-    __Pyx_GOTREF(__pyx_t_7);
-    __pyx_t_8 = PyTuple_New(3); if (unlikely(!__pyx_t_8)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 29; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-    __Pyx_GOTREF(__pyx_t_8);
-    __Pyx_INCREF(((PyObject *)__pyx_v_label));
-    PyTuple_SET_ITEM(__pyx_t_8, 0, ((PyObject *)__pyx_v_label));
-    __Pyx_GIVEREF(((PyObject *)__pyx_v_label));
-    PyTuple_SET_ITEM(__pyx_t_8, 1, __pyx_t_4);
-    __Pyx_GIVEREF(__pyx_t_4);
-    PyTuple_SET_ITEM(__pyx_t_8, 2, __pyx_t_7);
-    __Pyx_GIVEREF(__pyx_t_7);
-    __pyx_t_4 = 0;
-    __pyx_t_7 = 0;
-    __pyx_t_9 = PyList_Append(__pyx_v_arcs, ((PyObject *)__pyx_t_8)); if (unlikely(__pyx_t_9 == -1)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 29; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-    __Pyx_DECREF(((PyObject *)__pyx_t_8)); __pyx_t_8 = 0;
-  }
+  __pyx_t_1 = PyBytes_FromString(HypergraphIO::AsPLF((__pyx_v_self->hg[0]), 1).c_str()); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 101; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(((PyObject *)__pyx_t_1));
+  if (!(likely(PyString_CheckExact(((PyObject *)__pyx_t_1)))||(PyErr_Format(PyExc_TypeError, "Expected str, got %.200s", Py_TYPE(((PyObject *)__pyx_t_1))->tp_name), 0))) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 101; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_v_plf = ((PyObject*)__pyx_t_1);
+  __pyx_t_1 = 0;
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/lattice.pxi":30
- *             label = unicode(TDConvert(arc.label), 'utf8')
- *             arcs.append((label, arc.cost, arc.dist2next))
- *         return tuple(arcs)             # <<<<<<<<<<<<<<
+  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":102
+ *     def lattice(self): # TODO direct hg -> lattice conversion in cdec
+ *         cdef str plf = hypergraph.AsPLF(self.hg[0], True).c_str()
+ *         return Lattice(eval(plf))             # <<<<<<<<<<<<<<
  * 
- *     def __setitem__(self, int index, tuple arcs):
+ *     def reweight(self, weights):
  */
   __Pyx_XDECREF(__pyx_r);
-  __pyx_t_8 = ((PyObject *)PyList_AsTuple(__pyx_v_arcs)); if (unlikely(!__pyx_t_8)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 30; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __Pyx_GOTREF(((PyObject *)__pyx_t_8));
-  __pyx_r = ((PyObject *)__pyx_t_8);
-  __pyx_t_8 = 0;
+  __pyx_t_1 = __Pyx_Globals(); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 102; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_1);
+  __pyx_t_2 = PyDict_New(); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 102; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(((PyObject *)__pyx_t_2));
+  if (((PyObject *)__pyx_v_plf)) {
+    if (PyDict_SetItem(__pyx_t_2, ((PyObject *)__pyx_n_s__plf), ((PyObject *)__pyx_v_plf)) < 0) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 102; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  }
+  if (((PyObject *)__pyx_v_self)) {
+    if (PyDict_SetItem(__pyx_t_2, ((PyObject *)__pyx_n_s__self), ((PyObject *)__pyx_v_self)) < 0) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 102; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  }
+  __pyx_t_3 = PyTuple_New(3); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 102; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_3);
+  __Pyx_INCREF(((PyObject *)__pyx_v_plf));
+  PyTuple_SET_ITEM(__pyx_t_3, 0, ((PyObject *)__pyx_v_plf));
+  __Pyx_GIVEREF(((PyObject *)__pyx_v_plf));
+  PyTuple_SET_ITEM(__pyx_t_3, 1, ((PyObject *)__pyx_t_1));
+  __Pyx_GIVEREF(((PyObject *)__pyx_t_1));
+  PyTuple_SET_ITEM(__pyx_t_3, 2, ((PyObject *)__pyx_t_2));
+  __Pyx_GIVEREF(((PyObject *)__pyx_t_2));
+  __pyx_t_1 = 0;
+  __pyx_t_2 = 0;
+  __pyx_t_2 = PyObject_Call(__pyx_builtin_eval, ((PyObject *)__pyx_t_3), NULL); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 102; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_2);
+  __Pyx_DECREF(((PyObject *)__pyx_t_3)); __pyx_t_3 = 0;
+  __pyx_t_3 = PyTuple_New(1); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 102; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_3);
+  PyTuple_SET_ITEM(__pyx_t_3, 0, __pyx_t_2);
+  __Pyx_GIVEREF(__pyx_t_2);
+  __pyx_t_2 = 0;
+  __pyx_t_2 = PyObject_Call(((PyObject *)((PyObject*)__pyx_ptype_5_cdec_Lattice)), ((PyObject *)__pyx_t_3), NULL); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 102; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_2);
+  __Pyx_DECREF(((PyObject *)__pyx_t_3)); __pyx_t_3 = 0;
+  __pyx_r = __pyx_t_2;
+  __pyx_t_2 = 0;
   goto __pyx_L0;
 
   __pyx_r = Py_None; __Pyx_INCREF(Py_None);
   goto __pyx_L0;
   __pyx_L1_error:;
-  __Pyx_XDECREF(__pyx_t_4);
-  __Pyx_XDECREF(__pyx_t_7);
-  __Pyx_XDECREF(__pyx_t_8);
-  __Pyx_AddTraceback("_cdec.Lattice.__getitem__", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __Pyx_XDECREF(__pyx_t_1);
+  __Pyx_XDECREF(__pyx_t_2);
+  __Pyx_XDECREF(__pyx_t_3);
+  __Pyx_AddTraceback("_cdec.Hypergraph.lattice", __pyx_clineno, __pyx_lineno, __pyx_filename);
   __pyx_r = NULL;
   __pyx_L0:;
-  __Pyx_XDECREF(__pyx_v_arcs);
-  __Pyx_XDECREF(__pyx_v_label);
+  __Pyx_XDECREF(__pyx_v_plf);
   __Pyx_XGIVEREF(__pyx_r);
   __Pyx_RefNannyFinishContext();
   return __pyx_r;
 }
 
 /* Python wrapper */
-static int __pyx_pw_5_cdec_7Lattice_5__setitem__(PyObject *__pyx_v_self, PyObject *__pyx_arg_index, PyObject *__pyx_v_arcs); /*proto*/
-static int __pyx_pw_5_cdec_7Lattice_5__setitem__(PyObject *__pyx_v_self, PyObject *__pyx_arg_index, PyObject *__pyx_v_arcs) {
-  int __pyx_v_index;
-  int __pyx_r;
+static PyObject *__pyx_pw_5_cdec_10Hypergraph_29reweight(PyObject *__pyx_v_self, PyObject *__pyx_v_weights); /*proto*/
+static PyObject *__pyx_pw_5_cdec_10Hypergraph_29reweight(PyObject *__pyx_v_self, PyObject *__pyx_v_weights) {
+  PyObject *__pyx_r = 0;
   __Pyx_RefNannyDeclarations
-  __Pyx_RefNannySetupContext("__setitem__ (wrapper)", 0);
-  assert(__pyx_arg_index); {
-    __pyx_v_index = __Pyx_PyInt_AsInt(__pyx_arg_index); if (unlikely((__pyx_v_index == (int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 32; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
-  }
-  goto __pyx_L4_argument_unpacking_done;
-  __pyx_L3_error:;
-  __Pyx_AddTraceback("_cdec.Lattice.__setitem__", __pyx_clineno, __pyx_lineno, __pyx_filename);
-  __Pyx_RefNannyFinishContext();
-  return -1;
-  __pyx_L4_argument_unpacking_done:;
-  if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_arcs), (&PyTuple_Type), 1, "arcs", 1))) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 32; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __pyx_r = __pyx_pf_5_cdec_7Lattice_4__setitem__(((struct __pyx_obj_5_cdec_Lattice *)__pyx_v_self), ((int)__pyx_v_index), ((PyObject*)__pyx_v_arcs));
-  goto __pyx_L0;
-  __pyx_L1_error:;
-  __pyx_r = -1;
-  __pyx_L0:;
+  __Pyx_RefNannySetupContext("reweight (wrapper)", 0);
+  __pyx_r = __pyx_pf_5_cdec_10Hypergraph_28reweight(((struct __pyx_obj_5_cdec_Hypergraph *)__pyx_v_self), ((PyObject *)__pyx_v_weights));
   __Pyx_RefNannyFinishContext();
   return __pyx_r;
 }
 
-/* "/Users/vchahun/Sandbox/cdec/python/src/lattice.pxi":32
- *         return tuple(arcs)
+/* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":104
+ *         return Lattice(eval(plf))
  * 
- *     def __setitem__(self, int index, tuple arcs):             # <<<<<<<<<<<<<<
- *         if not 0 <= index < len(self):
- *             raise IndexError('lattice index out of range')
+ *     def reweight(self, weights):             # <<<<<<<<<<<<<<
+ *         if isinstance(weights, SparseVector):
+ *             self.hg.Reweight((<SparseVector> weights).vector[0])
  */
 
-static int __pyx_pf_5_cdec_7Lattice_4__setitem__(struct __pyx_obj_5_cdec_Lattice *__pyx_v_self, int __pyx_v_index, PyObject *__pyx_v_arcs) {
-  LatticeArc *__pyx_v_arc;
-  PyObject *__pyx_v_label = NULL;
-  PyObject *__pyx_v_cost = NULL;
-  PyObject *__pyx_v_dist2next = NULL;
-  int __pyx_r;
+static PyObject *__pyx_pf_5_cdec_10Hypergraph_28reweight(struct __pyx_obj_5_cdec_Hypergraph *__pyx_v_self, PyObject *__pyx_v_weights) {
+  PyObject *__pyx_r = NULL;
   __Pyx_RefNannyDeclarations
-  int __pyx_t_1;
-  Py_ssize_t __pyx_t_2;
-  int __pyx_t_3;
-  PyObject *__pyx_t_4 = NULL;
-  PyObject *__pyx_t_5 = NULL;
-  PyObject *__pyx_t_6 = NULL;
-  PyObject *__pyx_t_7 = NULL;
-  PyObject *__pyx_t_8 = NULL;
-  PyObject *__pyx_t_9 = NULL;
-  PyObject *(*__pyx_t_10)(PyObject *);
-  char *__pyx_t_11;
-  double __pyx_t_12;
-  int __pyx_t_13;
+  PyObject *__pyx_t_1 = NULL;
+  int __pyx_t_2;
+  PyObject *__pyx_t_3 = NULL;
   int __pyx_lineno = 0;
   const char *__pyx_filename = NULL;
   int __pyx_clineno = 0;
-  __Pyx_RefNannySetupContext("__setitem__", 0);
+  __Pyx_RefNannySetupContext("reweight", 0);
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/lattice.pxi":33
+  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":105
  * 
- *     def __setitem__(self, int index, tuple arcs):
- *         if not 0 <= index < len(self):             # <<<<<<<<<<<<<<
- *             raise IndexError('lattice index out of range')
- *         cdef lattice.LatticeArc* arc
+ *     def reweight(self, weights):
+ *         if isinstance(weights, SparseVector):             # <<<<<<<<<<<<<<
+ *             self.hg.Reweight((<SparseVector> weights).vector[0])
+ *         elif isinstance(weights, DenseVector):
  */
-  __pyx_t_1 = (0 <= __pyx_v_index);
-  if (__pyx_t_1) {
-    __pyx_t_2 = PyObject_Length(((PyObject *)__pyx_v_self)); if (unlikely(__pyx_t_2 == -1)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 33; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-    __pyx_t_1 = (__pyx_v_index < __pyx_t_2);
-  }
-  __pyx_t_3 = (!__pyx_t_1);
-  if (__pyx_t_3) {
+  __pyx_t_1 = ((PyObject *)((PyObject*)__pyx_ptype_5_cdec_SparseVector));
+  __Pyx_INCREF(__pyx_t_1);
+  __pyx_t_2 = __Pyx_TypeCheck(__pyx_v_weights, __pyx_t_1); 
+  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+  if (__pyx_t_2) {
 
-    /* "/Users/vchahun/Sandbox/cdec/python/src/lattice.pxi":34
- *     def __setitem__(self, int index, tuple arcs):
- *         if not 0 <= index < len(self):
- *             raise IndexError('lattice index out of range')             # <<<<<<<<<<<<<<
- *         cdef lattice.LatticeArc* arc
- *         for (label, cost, dist2next) in arcs:
+    /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":106
+ *     def reweight(self, weights):
+ *         if isinstance(weights, SparseVector):
+ *             self.hg.Reweight((<SparseVector> weights).vector[0])             # <<<<<<<<<<<<<<
+ *         elif isinstance(weights, DenseVector):
+ *             self.hg.Reweight((<DenseVector> weights).vector[0])
  */
-    __pyx_t_4 = PyObject_Call(__pyx_builtin_IndexError, ((PyObject *)__pyx_k_tuple_21), NULL); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 34; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-    __Pyx_GOTREF(__pyx_t_4);
-    __Pyx_Raise(__pyx_t_4, 0, 0, 0);
-    __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
-    {__pyx_filename = __pyx_f[3]; __pyx_lineno = 34; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_v_self->hg->Reweight((((struct __pyx_obj_5_cdec_SparseVector *)__pyx_v_weights)->vector[0]));
     goto __pyx_L3;
   }
-  __pyx_L3:;
-
-  /* "/Users/vchahun/Sandbox/cdec/python/src/lattice.pxi":36
- *             raise IndexError('lattice index out of range')
- *         cdef lattice.LatticeArc* arc
- *         for (label, cost, dist2next) in arcs:             # <<<<<<<<<<<<<<
- *             if isinstance(label, unicode):
- *                 label = label.encode('utf8')
- */
-  if (unlikely(((PyObject *)__pyx_v_arcs) == Py_None)) {
-    PyErr_SetString(PyExc_TypeError, "'NoneType' object is not iterable"); {__pyx_filename = __pyx_f[3]; __pyx_lineno = 36; __pyx_clineno = __LINE__; goto __pyx_L1_error;} 
-  }
-  __pyx_t_4 = ((PyObject *)__pyx_v_arcs); __Pyx_INCREF(__pyx_t_4); __pyx_t_2 = 0;
-  for (;;) {
-    if (__pyx_t_2 >= PyTuple_GET_SIZE(__pyx_t_4)) break;
-    __pyx_t_5 = PyTuple_GET_ITEM(__pyx_t_4, __pyx_t_2); __Pyx_INCREF(__pyx_t_5); __pyx_t_2++;
-    if ((likely(PyTuple_CheckExact(__pyx_t_5))) || (PyList_CheckExact(__pyx_t_5))) {
-      PyObject* sequence = __pyx_t_5;
-      if (likely(PyTuple_CheckExact(sequence))) {
-        if (unlikely(PyTuple_GET_SIZE(sequence) != 3)) {
-          if (PyTuple_GET_SIZE(sequence) > 3) __Pyx_RaiseTooManyValuesError(3);
-          else __Pyx_RaiseNeedMoreValuesError(PyTuple_GET_SIZE(sequence));
-          {__pyx_filename = __pyx_f[3]; __pyx_lineno = 36; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-        }
-        __pyx_t_6 = PyTuple_GET_ITEM(sequence, 0); 
-        __pyx_t_7 = PyTuple_GET_ITEM(sequence, 1); 
-        __pyx_t_8 = PyTuple_GET_ITEM(sequence, 2); 
-      } else {
-        if (unlikely(PyList_GET_SIZE(sequence) != 3)) {
-          if (PyList_GET_SIZE(sequence) > 3) __Pyx_RaiseTooManyValuesError(3);
-          else __Pyx_RaiseNeedMoreValuesError(PyList_GET_SIZE(sequence));
-          {__pyx_filename = __pyx_f[3]; __pyx_lineno = 36; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-        }
-        __pyx_t_6 = PyList_GET_ITEM(sequence, 0); 
-        __pyx_t_7 = PyList_GET_ITEM(sequence, 1); 
-        __pyx_t_8 = PyList_GET_ITEM(sequence, 2); 
-      }
-      __Pyx_INCREF(__pyx_t_6);
-      __Pyx_INCREF(__pyx_t_7);
-      __Pyx_INCREF(__pyx_t_8);
-      __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
-    } else {
-      Py_ssize_t index = -1;
-      __pyx_t_9 = PyObject_GetIter(__pyx_t_5); if (unlikely(!__pyx_t_9)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 36; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-      __Pyx_GOTREF(__pyx_t_9);
-      __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
-      __pyx_t_10 = Py_TYPE(__pyx_t_9)->tp_iternext;
-      index = 0; __pyx_t_6 = __pyx_t_10(__pyx_t_9); if (unlikely(!__pyx_t_6)) goto __pyx_L6_unpacking_failed;
-      __Pyx_GOTREF(__pyx_t_6);
-      index = 1; __pyx_t_7 = __pyx_t_10(__pyx_t_9); if (unlikely(!__pyx_t_7)) goto __pyx_L6_unpacking_failed;
-      __Pyx_GOTREF(__pyx_t_7);
-      index = 2; __pyx_t_8 = __pyx_t_10(__pyx_t_9); if (unlikely(!__pyx_t_8)) goto __pyx_L6_unpacking_failed;
-      __Pyx_GOTREF(__pyx_t_8);
-      if (__Pyx_IternextUnpackEndCheck(__pyx_t_10(__pyx_t_9), 3) < 0) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 36; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-      __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0;
-      goto __pyx_L7_unpacking_done;
-      __pyx_L6_unpacking_failed:;
-      __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0;
-      if (PyErr_Occurred() && PyErr_ExceptionMatches(PyExc_StopIteration)) PyErr_Clear();
-      if (!PyErr_Occurred()) __Pyx_RaiseNeedMoreValuesError(index);
-      {__pyx_filename = __pyx_f[3]; __pyx_lineno = 36; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-      __pyx_L7_unpacking_done:;
-    }
-    __Pyx_XDECREF(__pyx_v_label);
-    __pyx_v_label = __pyx_t_6;
-    __pyx_t_6 = 0;
-    __Pyx_XDECREF(__pyx_v_cost);
-    __pyx_v_cost = __pyx_t_7;
-    __pyx_t_7 = 0;
-    __Pyx_XDECREF(__pyx_v_dist2next);
-    __pyx_v_dist2next = __pyx_t_8;
-    __pyx_t_8 = 0;
-
-    /* "/Users/vchahun/Sandbox/cdec/python/src/lattice.pxi":37
- *         cdef lattice.LatticeArc* arc
- *         for (label, cost, dist2next) in arcs:
- *             if isinstance(label, unicode):             # <<<<<<<<<<<<<<
- *                 label = label.encode('utf8')
- *             arc = new lattice.LatticeArc(TDConvert(<char *>label), cost, dist2next)
- */
-    __pyx_t_5 = ((PyObject *)((PyObject*)(&PyUnicode_Type)));
-    __Pyx_INCREF(__pyx_t_5);
-    __pyx_t_3 = __Pyx_TypeCheck(__pyx_v_label, __pyx_t_5); 
-    __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
-    if (__pyx_t_3) {
-
-      /* "/Users/vchahun/Sandbox/cdec/python/src/lattice.pxi":38
- *         for (label, cost, dist2next) in arcs:
- *             if isinstance(label, unicode):
- *                 label = label.encode('utf8')             # <<<<<<<<<<<<<<
- *             arc = new lattice.LatticeArc(TDConvert(<char *>label), cost, dist2next)
- *             self.lattice[0][index].push_back(arc[0])
- */
-      __pyx_t_5 = PyObject_GetAttr(__pyx_v_label, __pyx_n_s__encode); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 38; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-      __Pyx_GOTREF(__pyx_t_5);
-      __pyx_t_8 = PyObject_Call(__pyx_t_5, ((PyObject *)__pyx_k_tuple_22), NULL); if (unlikely(!__pyx_t_8)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 38; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-      __Pyx_GOTREF(__pyx_t_8);
-      __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
-      __Pyx_DECREF(__pyx_v_label);
-      __pyx_v_label = __pyx_t_8;
-      __pyx_t_8 = 0;
-      goto __pyx_L8;
-    }
-    __pyx_L8:;
 
-    /* "/Users/vchahun/Sandbox/cdec/python/src/lattice.pxi":39
- *             if isinstance(label, unicode):
- *                 label = label.encode('utf8')
- *             arc = new lattice.LatticeArc(TDConvert(<char *>label), cost, dist2next)             # <<<<<<<<<<<<<<
- *             self.lattice[0][index].push_back(arc[0])
- *             del arc
+  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":107
+ *         if isinstance(weights, SparseVector):
+ *             self.hg.Reweight((<SparseVector> weights).vector[0])
+ *         elif isinstance(weights, DenseVector):             # <<<<<<<<<<<<<<
+ *             self.hg.Reweight((<DenseVector> weights).vector[0])
+ *         else:
  */
-    __pyx_t_11 = PyBytes_AsString(__pyx_v_label); if (unlikely((!__pyx_t_11) && PyErr_Occurred())) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 39; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-    __pyx_t_12 = __pyx_PyFloat_AsDouble(__pyx_v_cost); if (unlikely((__pyx_t_12 == (double)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 39; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-    __pyx_t_13 = __Pyx_PyInt_AsInt(__pyx_v_dist2next); if (unlikely((__pyx_t_13 == (int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 39; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-    __pyx_v_arc = new LatticeArc(TD::Convert(((char *)__pyx_t_11)), __pyx_t_12, __pyx_t_13);
+  __pyx_t_1 = ((PyObject *)((PyObject*)__pyx_ptype_5_cdec_DenseVector));
+  __Pyx_INCREF(__pyx_t_1);
+  __pyx_t_2 = __Pyx_TypeCheck(__pyx_v_weights, __pyx_t_1); 
+  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+  if (__pyx_t_2) {
 
-    /* "/Users/vchahun/Sandbox/cdec/python/src/lattice.pxi":40
- *                 label = label.encode('utf8')
- *             arc = new lattice.LatticeArc(TDConvert(<char *>label), cost, dist2next)
- *             self.lattice[0][index].push_back(arc[0])             # <<<<<<<<<<<<<<
- *             del arc
- * 
+    /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":108
+ *             self.hg.Reweight((<SparseVector> weights).vector[0])
+ *         elif isinstance(weights, DenseVector):
+ *             self.hg.Reweight((<DenseVector> weights).vector[0])             # <<<<<<<<<<<<<<
+ *         else:
+ *             raise TypeError('cannot reweight hypergraph with %s' % type(weights))
  */
-    ((__pyx_v_self->lattice[0])[__pyx_v_index]).push_back((__pyx_v_arc[0]));
+    __pyx_v_self->hg->Reweight((((struct __pyx_obj_5_cdec_DenseVector *)__pyx_v_weights)->vector[0]));
+    goto __pyx_L3;
+  }
+  /*else*/ {
 
-    /* "/Users/vchahun/Sandbox/cdec/python/src/lattice.pxi":41
- *             arc = new lattice.LatticeArc(TDConvert(<char *>label), cost, dist2next)
- *             self.lattice[0][index].push_back(arc[0])
- *             del arc             # <<<<<<<<<<<<<<
+    /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":110
+ *             self.hg.Reweight((<DenseVector> weights).vector[0])
+ *         else:
+ *             raise TypeError('cannot reweight hypergraph with %s' % type(weights))             # <<<<<<<<<<<<<<
  * 
- *     def __len__(self):
+ *     property edges:
  */
-    delete __pyx_v_arc;
+    __pyx_t_1 = PyNumber_Remainder(((PyObject *)__pyx_kp_s_16), ((PyObject *)Py_TYPE(__pyx_v_weights))); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 110; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(((PyObject *)__pyx_t_1));
+    __pyx_t_3 = PyTuple_New(1); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 110; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_3);
+    PyTuple_SET_ITEM(__pyx_t_3, 0, ((PyObject *)__pyx_t_1));
+    __Pyx_GIVEREF(((PyObject *)__pyx_t_1));
+    __pyx_t_1 = 0;
+    __pyx_t_1 = PyObject_Call(__pyx_builtin_TypeError, ((PyObject *)__pyx_t_3), NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 110; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_1);
+    __Pyx_DECREF(((PyObject *)__pyx_t_3)); __pyx_t_3 = 0;
+    __Pyx_Raise(__pyx_t_1, 0, 0, 0);
+    __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+    {__pyx_filename = __pyx_f[3]; __pyx_lineno = 110; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   }
-  __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
+  __pyx_L3:;
 
-  __pyx_r = 0;
+  __pyx_r = Py_None; __Pyx_INCREF(Py_None);
   goto __pyx_L0;
   __pyx_L1_error:;
-  __Pyx_XDECREF(__pyx_t_4);
-  __Pyx_XDECREF(__pyx_t_5);
-  __Pyx_XDECREF(__pyx_t_6);
-  __Pyx_XDECREF(__pyx_t_7);
-  __Pyx_XDECREF(__pyx_t_8);
-  __Pyx_XDECREF(__pyx_t_9);
-  __Pyx_AddTraceback("_cdec.Lattice.__setitem__", __pyx_clineno, __pyx_lineno, __pyx_filename);
-  __pyx_r = -1;
+  __Pyx_XDECREF(__pyx_t_1);
+  __Pyx_XDECREF(__pyx_t_3);
+  __Pyx_AddTraceback("_cdec.Hypergraph.reweight", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __pyx_r = NULL;
   __pyx_L0:;
-  __Pyx_XDECREF(__pyx_v_label);
-  __Pyx_XDECREF(__pyx_v_cost);
-  __Pyx_XDECREF(__pyx_v_dist2next);
+  __Pyx_XGIVEREF(__pyx_r);
   __Pyx_RefNannyFinishContext();
   return __pyx_r;
 }
+static PyObject *__pyx_gb_5_cdec_10Hypergraph_5edges_2generator8(__pyx_GeneratorObject *__pyx_generator, PyObject *__pyx_sent_value); /* proto */
 
 /* Python wrapper */
-static Py_ssize_t __pyx_pw_5_cdec_7Lattice_7__len__(PyObject *__pyx_v_self); /*proto*/
-static Py_ssize_t __pyx_pw_5_cdec_7Lattice_7__len__(PyObject *__pyx_v_self) {
-  Py_ssize_t __pyx_r;
+static PyObject *__pyx_pw_5_cdec_10Hypergraph_5edges_1__get__(PyObject *__pyx_v_self); /*proto*/
+static PyObject *__pyx_pw_5_cdec_10Hypergraph_5edges_1__get__(PyObject *__pyx_v_self) {
+  PyObject *__pyx_r = 0;
   __Pyx_RefNannyDeclarations
-  __Pyx_RefNannySetupContext("__len__ (wrapper)", 0);
-  __pyx_r = __pyx_pf_5_cdec_7Lattice_6__len__(((struct __pyx_obj_5_cdec_Lattice *)__pyx_v_self));
+  __Pyx_RefNannySetupContext("__get__ (wrapper)", 0);
+  __pyx_r = __pyx_pf_5_cdec_10Hypergraph_5edges___get__(((struct __pyx_obj_5_cdec_Hypergraph *)__pyx_v_self));
   __Pyx_RefNannyFinishContext();
   return __pyx_r;
 }
 
-/* "/Users/vchahun/Sandbox/cdec/python/src/lattice.pxi":43
- *             del arc
- * 
- *     def __len__(self):             # <<<<<<<<<<<<<<
- *         return self.lattice.size()
+/* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":113
  * 
+ *     property edges:
+ *         def __get__(self):             # <<<<<<<<<<<<<<
+ *             cdef unsigned i
+ *             for i in range(self.hg.edges_.size()):
  */
 
-static Py_ssize_t __pyx_pf_5_cdec_7Lattice_6__len__(struct __pyx_obj_5_cdec_Lattice *__pyx_v_self) {
-  Py_ssize_t __pyx_r;
+static PyObject *__pyx_pf_5_cdec_10Hypergraph_5edges___get__(struct __pyx_obj_5_cdec_Hypergraph *__pyx_v_self) {
+  struct __pyx_obj_5_cdec___pyx_scope_struct_12___get__ *__pyx_cur_scope;
+  PyObject *__pyx_r = NULL;
   __Pyx_RefNannyDeclarations
-  __Pyx_RefNannySetupContext("__len__", 0);
+  int __pyx_lineno = 0;
+  const char *__pyx_filename = NULL;
+  int __pyx_clineno = 0;
+  __Pyx_RefNannySetupContext("__get__", 0);
+  __pyx_cur_scope = (struct __pyx_obj_5_cdec___pyx_scope_struct_12___get__ *)__pyx_ptype_5_cdec___pyx_scope_struct_12___get__->tp_new(__pyx_ptype_5_cdec___pyx_scope_struct_12___get__, __pyx_empty_tuple, NULL);
+  if (unlikely(!__pyx_cur_scope)) {
+    __Pyx_RefNannyFinishContext();
+    return NULL;
+  }
+  __Pyx_GOTREF(__pyx_cur_scope);
+  __pyx_cur_scope->__pyx_v_self = __pyx_v_self;
+  __Pyx_INCREF((PyObject *)__pyx_cur_scope->__pyx_v_self);
+  __Pyx_GIVEREF((PyObject *)__pyx_cur_scope->__pyx_v_self);
+  {
+    __pyx_GeneratorObject *gen = __Pyx_Generator_New((__pyx_generator_body_t) __pyx_gb_5_cdec_10Hypergraph_5edges_2generator8, (PyObject *) __pyx_cur_scope); if (unlikely(!gen)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 113; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_DECREF(__pyx_cur_scope);
+    __Pyx_RefNannyFinishContext();
+    return (PyObject *) gen;
+  }
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/lattice.pxi":44
- * 
- *     def __len__(self):
- *         return self.lattice.size()             # <<<<<<<<<<<<<<
- * 
- *     def __str__(self):
- */
-  __pyx_r = __pyx_v_self->lattice->size();
+  __pyx_r = Py_None; __Pyx_INCREF(Py_None);
   goto __pyx_L0;
-
-  __pyx_r = 0;
+  __pyx_L1_error:;
+  __Pyx_AddTraceback("_cdec.Hypergraph.edges.__get__", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __pyx_r = NULL;
   __pyx_L0:;
+  __Pyx_DECREF(((PyObject *)__pyx_cur_scope));
+  __Pyx_XGIVEREF(__pyx_r);
   __Pyx_RefNannyFinishContext();
   return __pyx_r;
 }
 
-/* Python wrapper */
-static PyObject *__pyx_pw_5_cdec_7Lattice_9__str__(PyObject *__pyx_v_self); /*proto*/
-static PyObject *__pyx_pw_5_cdec_7Lattice_9__str__(PyObject *__pyx_v_self) {
-  PyObject *__pyx_r = 0;
-  __Pyx_RefNannyDeclarations
-  __Pyx_RefNannySetupContext("__str__ (wrapper)", 0);
-  __pyx_r = __pyx_pf_5_cdec_7Lattice_8__str__(((struct __pyx_obj_5_cdec_Lattice *)__pyx_v_self));
-  __Pyx_RefNannyFinishContext();
-  return __pyx_r;
-}
-
-/* "/Users/vchahun/Sandbox/cdec/python/src/lattice.pxi":46
- *         return self.lattice.size()
- * 
- *     def __str__(self):             # <<<<<<<<<<<<<<
- *         return hypergraph.AsPLF(self.lattice[0], True).c_str()
- * 
- */
-
-static PyObject *__pyx_pf_5_cdec_7Lattice_8__str__(struct __pyx_obj_5_cdec_Lattice *__pyx_v_self) {
+static PyObject *__pyx_gb_5_cdec_10Hypergraph_5edges_2generator8(__pyx_GeneratorObject *__pyx_generator, PyObject *__pyx_sent_value) /* generator body */
+{
+  struct __pyx_obj_5_cdec___pyx_scope_struct_12___get__ *__pyx_cur_scope = ((struct __pyx_obj_5_cdec___pyx_scope_struct_12___get__ *)__pyx_generator->closure);
   PyObject *__pyx_r = NULL;
+  size_t __pyx_t_1;
+  unsigned int __pyx_t_2;
+  PyObject *__pyx_t_3 = NULL;
+  PyObject *__pyx_t_4 = NULL;
   __Pyx_RefNannyDeclarations
-  PyObject *__pyx_t_1 = NULL;
-  int __pyx_lineno = 0;
-  const char *__pyx_filename = NULL;
-  int __pyx_clineno = 0;
-  __Pyx_RefNannySetupContext("__str__", 0);
+  __Pyx_RefNannySetupContext("None", 0);
+  switch (__pyx_generator->resume_label) {
+    case 0: goto __pyx_L3_first_run;
+    case 1: goto __pyx_L6_resume_from_yield;
+    default: /* CPython raises the right error here */
+    __Pyx_RefNannyFinishContext();
+    return NULL;
+  }
+  __pyx_L3_first_run:;
+  if (unlikely(!__pyx_sent_value)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 113; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/lattice.pxi":47
- * 
- *     def __str__(self):
- *         return hypergraph.AsPLF(self.lattice[0], True).c_str()             # <<<<<<<<<<<<<<
+  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":115
+ *         def __get__(self):
+ *             cdef unsigned i
+ *             for i in range(self.hg.edges_.size()):             # <<<<<<<<<<<<<<
+ *                 yield HypergraphEdge().init(self.hg, i)
  * 
- *     def __iter__(self):
  */
-  __Pyx_XDECREF(__pyx_r);
-  __pyx_t_1 = PyBytes_FromString(HypergraphIO::AsPLF((__pyx_v_self->lattice[0]), 1).c_str()); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 47; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __Pyx_GOTREF(((PyObject *)__pyx_t_1));
-  __pyx_r = ((PyObject *)__pyx_t_1);
-  __pyx_t_1 = 0;
-  goto __pyx_L0;
+  __pyx_t_1 = __pyx_cur_scope->__pyx_v_self->hg->edges_.size();
+  for (__pyx_t_2 = 0; __pyx_t_2 < __pyx_t_1; __pyx_t_2+=1) {
+    __pyx_cur_scope->__pyx_v_i = __pyx_t_2;
 
-  __pyx_r = Py_None; __Pyx_INCREF(Py_None);
+    /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":116
+ *             cdef unsigned i
+ *             for i in range(self.hg.edges_.size()):
+ *                 yield HypergraphEdge().init(self.hg, i)             # <<<<<<<<<<<<<<
+ * 
+ *     property nodes:
+ */
+    __pyx_t_3 = PyObject_Call(((PyObject *)((PyObject*)__pyx_ptype_5_cdec_HypergraphEdge)), ((PyObject *)__pyx_empty_tuple), NULL); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 116; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_3);
+    __pyx_t_4 = ((struct __pyx_vtabstruct_5_cdec_HypergraphEdge *)((struct __pyx_obj_5_cdec_HypergraphEdge *)__pyx_t_3)->__pyx_vtab)->init(((struct __pyx_obj_5_cdec_HypergraphEdge *)__pyx_t_3), __pyx_cur_scope->__pyx_v_self->hg, __pyx_cur_scope->__pyx_v_i); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 116; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_4);
+    __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
+    __pyx_r = __pyx_t_4;
+    __pyx_t_4 = 0;
+    __pyx_cur_scope->__pyx_t_0 = __pyx_t_1;
+    __pyx_cur_scope->__pyx_t_1 = __pyx_t_2;
+    __Pyx_XGIVEREF(__pyx_r);
+    __Pyx_RefNannyFinishContext();
+    /* return from generator, yielding value */
+    __pyx_generator->resume_label = 1;
+    return __pyx_r;
+    __pyx_L6_resume_from_yield:;
+    __pyx_t_1 = __pyx_cur_scope->__pyx_t_0;
+    __pyx_t_2 = __pyx_cur_scope->__pyx_t_1;
+    if (unlikely(!__pyx_sent_value)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 116; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  }
+  PyErr_SetNone(PyExc_StopIteration);
   goto __pyx_L0;
   __pyx_L1_error:;
-  __Pyx_XDECREF(__pyx_t_1);
-  __Pyx_AddTraceback("_cdec.Lattice.__str__", __pyx_clineno, __pyx_lineno, __pyx_filename);
-  __pyx_r = NULL;
+  __Pyx_XDECREF(__pyx_t_3);
+  __Pyx_XDECREF(__pyx_t_4);
+  __Pyx_AddTraceback("__get__", __pyx_clineno, __pyx_lineno, __pyx_filename);
   __pyx_L0:;
-  __Pyx_XGIVEREF(__pyx_r);
+  __Pyx_XDECREF(__pyx_r);
+  __pyx_generator->resume_label = -1;
   __Pyx_RefNannyFinishContext();
-  return __pyx_r;
+  return NULL;
 }
-static PyObject *__pyx_gb_5_cdec_7Lattice_12generator11(__pyx_GeneratorObject *__pyx_generator, PyObject *__pyx_sent_value); /* proto */
+static PyObject *__pyx_gb_5_cdec_10Hypergraph_5nodes_2generator9(__pyx_GeneratorObject *__pyx_generator, PyObject *__pyx_sent_value); /* proto */
 
 /* Python wrapper */
-static PyObject *__pyx_pw_5_cdec_7Lattice_11__iter__(PyObject *__pyx_v_self); /*proto*/
-static PyObject *__pyx_pw_5_cdec_7Lattice_11__iter__(PyObject *__pyx_v_self) {
+static PyObject *__pyx_pw_5_cdec_10Hypergraph_5nodes_1__get__(PyObject *__pyx_v_self); /*proto*/
+static PyObject *__pyx_pw_5_cdec_10Hypergraph_5nodes_1__get__(PyObject *__pyx_v_self) {
   PyObject *__pyx_r = 0;
   __Pyx_RefNannyDeclarations
-  __Pyx_RefNannySetupContext("__iter__ (wrapper)", 0);
-  __pyx_r = __pyx_pf_5_cdec_7Lattice_10__iter__(((struct __pyx_obj_5_cdec_Lattice *)__pyx_v_self));
+  __Pyx_RefNannySetupContext("__get__ (wrapper)", 0);
+  __pyx_r = __pyx_pf_5_cdec_10Hypergraph_5nodes___get__(((struct __pyx_obj_5_cdec_Hypergraph *)__pyx_v_self));
   __Pyx_RefNannyFinishContext();
   return __pyx_r;
 }
 
-/* "/Users/vchahun/Sandbox/cdec/python/src/lattice.pxi":49
- *         return hypergraph.AsPLF(self.lattice[0], True).c_str()
+/* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":119
  * 
- *     def __iter__(self):             # <<<<<<<<<<<<<<
- *         cdef unsigned i
- *         for i in range(len(self)):
+ *     property nodes:
+ *         def __get__(self):             # <<<<<<<<<<<<<<
+ *             cdef unsigned i
+ *             for i in range(self.hg.nodes_.size()):
  */
 
-static PyObject *__pyx_pf_5_cdec_7Lattice_10__iter__(struct __pyx_obj_5_cdec_Lattice *__pyx_v_self) {
-  struct __pyx_obj_5_cdec___pyx_scope_struct_15___iter__ *__pyx_cur_scope;
+static PyObject *__pyx_pf_5_cdec_10Hypergraph_5nodes___get__(struct __pyx_obj_5_cdec_Hypergraph *__pyx_v_self) {
+  struct __pyx_obj_5_cdec___pyx_scope_struct_13___get__ *__pyx_cur_scope;
   PyObject *__pyx_r = NULL;
   __Pyx_RefNannyDeclarations
   int __pyx_lineno = 0;
   const char *__pyx_filename = NULL;
   int __pyx_clineno = 0;
-  __Pyx_RefNannySetupContext("__iter__", 0);
-  __pyx_cur_scope = (struct __pyx_obj_5_cdec___pyx_scope_struct_15___iter__ *)__pyx_ptype_5_cdec___pyx_scope_struct_15___iter__->tp_new(__pyx_ptype_5_cdec___pyx_scope_struct_15___iter__, __pyx_empty_tuple, NULL);
+  __Pyx_RefNannySetupContext("__get__", 0);
+  __pyx_cur_scope = (struct __pyx_obj_5_cdec___pyx_scope_struct_13___get__ *)__pyx_ptype_5_cdec___pyx_scope_struct_13___get__->tp_new(__pyx_ptype_5_cdec___pyx_scope_struct_13___get__, __pyx_empty_tuple, NULL);
   if (unlikely(!__pyx_cur_scope)) {
     __Pyx_RefNannyFinishContext();
     return NULL;
@@ -9336,7 +9408,7 @@ static PyObject *__pyx_pf_5_cdec_7Lattice_10__iter__(struct __pyx_obj_5_cdec_Lat
   __Pyx_INCREF((PyObject *)__pyx_cur_scope->__pyx_v_self);
   __Pyx_GIVEREF((PyObject *)__pyx_cur_scope->__pyx_v_self);
   {
-    __pyx_GeneratorObject *gen = __Pyx_Generator_New((__pyx_generator_body_t) __pyx_gb_5_cdec_7Lattice_12generator11, (PyObject *) __pyx_cur_scope); if (unlikely(!gen)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 49; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_GeneratorObject *gen = __Pyx_Generator_New((__pyx_generator_body_t) __pyx_gb_5_cdec_10Hypergraph_5nodes_2generator9, (PyObject *) __pyx_cur_scope); if (unlikely(!gen)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 119; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
     __Pyx_DECREF(__pyx_cur_scope);
     __Pyx_RefNannyFinishContext();
     return (PyObject *) gen;
@@ -9345,7 +9417,7 @@ static PyObject *__pyx_pf_5_cdec_7Lattice_10__iter__(struct __pyx_obj_5_cdec_Lat
   __pyx_r = Py_None; __Pyx_INCREF(Py_None);
   goto __pyx_L0;
   __pyx_L1_error:;
-  __Pyx_AddTraceback("_cdec.Lattice.__iter__", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __Pyx_AddTraceback("_cdec.Hypergraph.nodes.__get__", __pyx_clineno, __pyx_lineno, __pyx_filename);
   __pyx_r = NULL;
   __pyx_L0:;
   __Pyx_DECREF(((PyObject *)__pyx_cur_scope));
@@ -9354,13 +9426,14 @@ static PyObject *__pyx_pf_5_cdec_7Lattice_10__iter__(struct __pyx_obj_5_cdec_Lat
   return __pyx_r;
 }
 
-static PyObject *__pyx_gb_5_cdec_7Lattice_12generator11(__pyx_GeneratorObject *__pyx_generator, PyObject *__pyx_sent_value) /* generator body */
+static PyObject *__pyx_gb_5_cdec_10Hypergraph_5nodes_2generator9(__pyx_GeneratorObject *__pyx_generator, PyObject *__pyx_sent_value) /* generator body */
 {
-  struct __pyx_obj_5_cdec___pyx_scope_struct_15___iter__ *__pyx_cur_scope = ((struct __pyx_obj_5_cdec___pyx_scope_struct_15___iter__ *)__pyx_generator->closure);
+  struct __pyx_obj_5_cdec___pyx_scope_struct_13___get__ *__pyx_cur_scope = ((struct __pyx_obj_5_cdec___pyx_scope_struct_13___get__ *)__pyx_generator->closure);
   PyObject *__pyx_r = NULL;
-  Py_ssize_t __pyx_t_1;
+  size_t __pyx_t_1;
   unsigned int __pyx_t_2;
   PyObject *__pyx_t_3 = NULL;
+  PyObject *__pyx_t_4 = NULL;
   __Pyx_RefNannyDeclarations
   __Pyx_RefNannySetupContext("None", 0);
   switch (__pyx_generator->resume_label) {
@@ -9371,30 +9444,33 @@ static PyObject *__pyx_gb_5_cdec_7Lattice_12generator11(__pyx_GeneratorObject *_
     return NULL;
   }
   __pyx_L3_first_run:;
-  if (unlikely(!__pyx_sent_value)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 49; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (unlikely(!__pyx_sent_value)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 119; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/lattice.pxi":51
- *     def __iter__(self):
- *         cdef unsigned i
- *         for i in range(len(self)):             # <<<<<<<<<<<<<<
- *             yield self[i]
+  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":121
+ *         def __get__(self):
+ *             cdef unsigned i
+ *             for i in range(self.hg.nodes_.size()):             # <<<<<<<<<<<<<<
+ *                 yield HypergraphNode().init(self.hg, i)
  * 
  */
-  __pyx_t_1 = PyObject_Length(((PyObject *)__pyx_cur_scope->__pyx_v_self)); if (unlikely(__pyx_t_1 == -1)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 51; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_1 = __pyx_cur_scope->__pyx_v_self->hg->nodes_.size();
   for (__pyx_t_2 = 0; __pyx_t_2 < __pyx_t_1; __pyx_t_2+=1) {
     __pyx_cur_scope->__pyx_v_i = __pyx_t_2;
 
-    /* "/Users/vchahun/Sandbox/cdec/python/src/lattice.pxi":52
- *         cdef unsigned i
- *         for i in range(len(self)):
- *             yield self[i]             # <<<<<<<<<<<<<<
+    /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":122
+ *             cdef unsigned i
+ *             for i in range(self.hg.nodes_.size()):
+ *                 yield HypergraphNode().init(self.hg, i)             # <<<<<<<<<<<<<<
  * 
- *     def __dealloc__(self):
+ *     property goal:
  */
-    __pyx_t_3 = __Pyx_GetItemInt(((PyObject *)__pyx_cur_scope->__pyx_v_self), __pyx_cur_scope->__pyx_v_i, sizeof(unsigned int)+1, PyLong_FromUnsignedLong); if (!__pyx_t_3) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 52; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_t_3 = PyObject_Call(((PyObject *)((PyObject*)__pyx_ptype_5_cdec_HypergraphNode)), ((PyObject *)__pyx_empty_tuple), NULL); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 122; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
     __Pyx_GOTREF(__pyx_t_3);
-    __pyx_r = __pyx_t_3;
-    __pyx_t_3 = 0;
+    __pyx_t_4 = ((struct __pyx_vtabstruct_5_cdec_HypergraphNode *)((struct __pyx_obj_5_cdec_HypergraphNode *)__pyx_t_3)->__pyx_vtab)->init(((struct __pyx_obj_5_cdec_HypergraphNode *)__pyx_t_3), __pyx_cur_scope->__pyx_v_self->hg, __pyx_cur_scope->__pyx_v_i); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 122; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_4);
+    __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
+    __pyx_r = __pyx_t_4;
+    __pyx_t_4 = 0;
     __pyx_cur_scope->__pyx_t_0 = __pyx_t_1;
     __pyx_cur_scope->__pyx_t_1 = __pyx_t_2;
     __Pyx_XGIVEREF(__pyx_r);
@@ -9405,13 +9481,14 @@ static PyObject *__pyx_gb_5_cdec_7Lattice_12generator11(__pyx_GeneratorObject *_
     __pyx_L6_resume_from_yield:;
     __pyx_t_1 = __pyx_cur_scope->__pyx_t_0;
     __pyx_t_2 = __pyx_cur_scope->__pyx_t_1;
-    if (unlikely(!__pyx_sent_value)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 52; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    if (unlikely(!__pyx_sent_value)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 122; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   }
   PyErr_SetNone(PyExc_StopIteration);
   goto __pyx_L0;
   __pyx_L1_error:;
   __Pyx_XDECREF(__pyx_t_3);
-  __Pyx_AddTraceback("__iter__", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __Pyx_XDECREF(__pyx_t_4);
+  __Pyx_AddTraceback("__get__", __pyx_clineno, __pyx_lineno, __pyx_filename);
   __pyx_L0:;
   __Pyx_XDECREF(__pyx_r);
   __pyx_generator->resume_label = -1;
@@ -9420,531 +9497,448 @@ static PyObject *__pyx_gb_5_cdec_7Lattice_12generator11(__pyx_GeneratorObject *_
 }
 
 /* Python wrapper */
-static void __pyx_pw_5_cdec_7Lattice_14__dealloc__(PyObject *__pyx_v_self); /*proto*/
-static void __pyx_pw_5_cdec_7Lattice_14__dealloc__(PyObject *__pyx_v_self) {
+static PyObject *__pyx_pw_5_cdec_10Hypergraph_4goal_1__get__(PyObject *__pyx_v_self); /*proto*/
+static PyObject *__pyx_pw_5_cdec_10Hypergraph_4goal_1__get__(PyObject *__pyx_v_self) {
+  PyObject *__pyx_r = 0;
   __Pyx_RefNannyDeclarations
-  __Pyx_RefNannySetupContext("__dealloc__ (wrapper)", 0);
-  __pyx_pf_5_cdec_7Lattice_13__dealloc__(((struct __pyx_obj_5_cdec_Lattice *)__pyx_v_self));
+  __Pyx_RefNannySetupContext("__get__ (wrapper)", 0);
+  __pyx_r = __pyx_pf_5_cdec_10Hypergraph_4goal___get__(((struct __pyx_obj_5_cdec_Hypergraph *)__pyx_v_self));
   __Pyx_RefNannyFinishContext();
+  return __pyx_r;
 }
 
-/* "/Users/vchahun/Sandbox/cdec/python/src/lattice.pxi":54
- *             yield self[i]
+/* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":125
  * 
- *     def __dealloc__(self):             # <<<<<<<<<<<<<<
- *         del self.lattice
+ *     property goal:
+ *         def __get__(self):             # <<<<<<<<<<<<<<
+ *             return HypergraphNode().init(self.hg, self.hg.GoalNode())
  * 
  */
 
-static void __pyx_pf_5_cdec_7Lattice_13__dealloc__(CYTHON_UNUSED struct __pyx_obj_5_cdec_Lattice *__pyx_v_self) {
+static PyObject *__pyx_pf_5_cdec_10Hypergraph_4goal___get__(struct __pyx_obj_5_cdec_Hypergraph *__pyx_v_self) {
+  PyObject *__pyx_r = NULL;
   __Pyx_RefNannyDeclarations
-  __Pyx_RefNannySetupContext("__dealloc__", 0);
+  PyObject *__pyx_t_1 = NULL;
+  PyObject *__pyx_t_2 = NULL;
+  int __pyx_lineno = 0;
+  const char *__pyx_filename = NULL;
+  int __pyx_clineno = 0;
+  __Pyx_RefNannySetupContext("__get__", 0);
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/lattice.pxi":55
- * 
- *     def __dealloc__(self):
- *         del self.lattice             # <<<<<<<<<<<<<<
+  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":126
+ *     property goal:
+ *         def __get__(self):
+ *             return HypergraphNode().init(self.hg, self.hg.GoalNode())             # <<<<<<<<<<<<<<
  * 
- *     def todot(self):
+ *     property npaths:
  */
-  delete __pyx_v_self->lattice;
-
-  __Pyx_RefNannyFinishContext();
-}
+  __Pyx_XDECREF(__pyx_r);
+  __pyx_t_1 = PyObject_Call(((PyObject *)((PyObject*)__pyx_ptype_5_cdec_HypergraphNode)), ((PyObject *)__pyx_empty_tuple), NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 126; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_1);
+  __pyx_t_2 = ((struct __pyx_vtabstruct_5_cdec_HypergraphNode *)((struct __pyx_obj_5_cdec_HypergraphNode *)__pyx_t_1)->__pyx_vtab)->init(((struct __pyx_obj_5_cdec_HypergraphNode *)__pyx_t_1), __pyx_v_self->hg, __pyx_v_self->hg->GoalNode()); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 126; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_2);
+  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+  __pyx_r = __pyx_t_2;
+  __pyx_t_2 = 0;
+  goto __pyx_L0;
 
-/* Python wrapper */
-static PyObject *__pyx_pw_5_cdec_7Lattice_16todot(PyObject *__pyx_v_self, CYTHON_UNUSED PyObject *unused); /*proto*/
-static PyObject *__pyx_pw_5_cdec_7Lattice_16todot(PyObject *__pyx_v_self, CYTHON_UNUSED PyObject *unused) {
-  PyObject *__pyx_r = 0;
-  __Pyx_RefNannyDeclarations
-  __Pyx_RefNannySetupContext("todot (wrapper)", 0);
-  __pyx_r = __pyx_pf_5_cdec_7Lattice_15todot(((struct __pyx_obj_5_cdec_Lattice *)__pyx_v_self));
+  __pyx_r = Py_None; __Pyx_INCREF(Py_None);
+  goto __pyx_L0;
+  __pyx_L1_error:;
+  __Pyx_XDECREF(__pyx_t_1);
+  __Pyx_XDECREF(__pyx_t_2);
+  __Pyx_AddTraceback("_cdec.Hypergraph.goal.__get__", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __pyx_r = NULL;
+  __pyx_L0:;
+  __Pyx_XGIVEREF(__pyx_r);
   __Pyx_RefNannyFinishContext();
   return __pyx_r;
 }
-static PyObject *__pyx_gb_5_cdec_7Lattice_5todot_2generator17(__pyx_GeneratorObject *__pyx_generator, PyObject *__pyx_sent_value); /* proto */
 
 /* Python wrapper */
-static PyObject *__pyx_pw_5_cdec_7Lattice_5todot_1lines(PyObject *__pyx_self, CYTHON_UNUSED PyObject *unused); /*proto*/
-static PyMethodDef __pyx_mdef_5_cdec_7Lattice_5todot_1lines = {__Pyx_NAMESTR("lines"), (PyCFunction)__pyx_pw_5_cdec_7Lattice_5todot_1lines, METH_NOARGS, __Pyx_DOCSTR(0)};
-static PyObject *__pyx_pw_5_cdec_7Lattice_5todot_1lines(PyObject *__pyx_self, CYTHON_UNUSED PyObject *unused) {
+static PyObject *__pyx_pw_5_cdec_10Hypergraph_6npaths_1__get__(PyObject *__pyx_v_self); /*proto*/
+static PyObject *__pyx_pw_5_cdec_10Hypergraph_6npaths_1__get__(PyObject *__pyx_v_self) {
   PyObject *__pyx_r = 0;
   __Pyx_RefNannyDeclarations
-  __Pyx_RefNannySetupContext("lines (wrapper)", 0);
-  __pyx_self = __pyx_self;
-  __pyx_r = __pyx_pf_5_cdec_7Lattice_5todot_lines(__pyx_self);
+  __Pyx_RefNannySetupContext("__get__ (wrapper)", 0);
+  __pyx_r = __pyx_pf_5_cdec_10Hypergraph_6npaths___get__(((struct __pyx_obj_5_cdec_Hypergraph *)__pyx_v_self));
   __Pyx_RefNannyFinishContext();
   return __pyx_r;
 }
 
-/* "/Users/vchahun/Sandbox/cdec/python/src/lattice.pxi":58
+/* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":129
+ * 
+ *     property npaths:
+ *         def __get__(self):             # <<<<<<<<<<<<<<
+ *             return self.hg.NumberOfPaths()
  * 
- *     def todot(self):
- *         def lines():             # <<<<<<<<<<<<<<
- *             yield 'digraph lattice {'
- *             yield 'rankdir = LR;'
  */
 
-static PyObject *__pyx_pf_5_cdec_7Lattice_5todot_lines(PyObject *__pyx_self) {
-  struct __pyx_obj_5_cdec___pyx_scope_struct_17_lines *__pyx_cur_scope;
+static PyObject *__pyx_pf_5_cdec_10Hypergraph_6npaths___get__(struct __pyx_obj_5_cdec_Hypergraph *__pyx_v_self) {
   PyObject *__pyx_r = NULL;
   __Pyx_RefNannyDeclarations
+  PyObject *__pyx_t_1 = NULL;
   int __pyx_lineno = 0;
   const char *__pyx_filename = NULL;
   int __pyx_clineno = 0;
-  __Pyx_RefNannySetupContext("lines", 0);
-  __pyx_cur_scope = (struct __pyx_obj_5_cdec___pyx_scope_struct_17_lines *)__pyx_ptype_5_cdec___pyx_scope_struct_17_lines->tp_new(__pyx_ptype_5_cdec___pyx_scope_struct_17_lines, __pyx_empty_tuple, NULL);
-  if (unlikely(!__pyx_cur_scope)) {
-    __Pyx_RefNannyFinishContext();
-    return NULL;
-  }
-  __Pyx_GOTREF(__pyx_cur_scope);
-  __pyx_cur_scope->__pyx_outer_scope = (struct __pyx_obj_5_cdec___pyx_scope_struct_16_todot *) __Pyx_CyFunction_GetClosure(__pyx_self);
-  __Pyx_INCREF(((PyObject *)__pyx_cur_scope->__pyx_outer_scope));
-  __Pyx_GIVEREF(__pyx_cur_scope->__pyx_outer_scope);
-  {
-    __pyx_GeneratorObject *gen = __Pyx_Generator_New((__pyx_generator_body_t) __pyx_gb_5_cdec_7Lattice_5todot_2generator17, (PyObject *) __pyx_cur_scope); if (unlikely(!gen)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 58; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-    __Pyx_DECREF(__pyx_cur_scope);
-    __Pyx_RefNannyFinishContext();
-    return (PyObject *) gen;
-  }
+  __Pyx_RefNannySetupContext("__get__", 0);
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":130
+ *     property npaths:
+ *         def __get__(self):
+ *             return self.hg.NumberOfPaths()             # <<<<<<<<<<<<<<
+ * 
+ *     def inside_outside(self):
+ */
+  __Pyx_XDECREF(__pyx_r);
+  __pyx_t_1 = PyFloat_FromDouble(__pyx_v_self->hg->NumberOfPaths()); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 130; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_1);
+  __pyx_r = __pyx_t_1;
+  __pyx_t_1 = 0;
+  goto __pyx_L0;
 
   __pyx_r = Py_None; __Pyx_INCREF(Py_None);
   goto __pyx_L0;
   __pyx_L1_error:;
-  __Pyx_AddTraceback("_cdec.Lattice.todot.lines", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __Pyx_XDECREF(__pyx_t_1);
+  __Pyx_AddTraceback("_cdec.Hypergraph.npaths.__get__", __pyx_clineno, __pyx_lineno, __pyx_filename);
   __pyx_r = NULL;
   __pyx_L0:;
-  __Pyx_DECREF(((PyObject *)__pyx_cur_scope));
   __Pyx_XGIVEREF(__pyx_r);
   __Pyx_RefNannyFinishContext();
   return __pyx_r;
 }
 
-static PyObject *__pyx_gb_5_cdec_7Lattice_5todot_2generator17(__pyx_GeneratorObject *__pyx_generator, PyObject *__pyx_sent_value) /* generator body */
-{
-  struct __pyx_obj_5_cdec___pyx_scope_struct_17_lines *__pyx_cur_scope = ((struct __pyx_obj_5_cdec___pyx_scope_struct_17_lines *)__pyx_generator->closure);
+/* Python wrapper */
+static PyObject *__pyx_pw_5_cdec_10Hypergraph_31inside_outside(PyObject *__pyx_v_self, CYTHON_UNUSED PyObject *unused); /*proto*/
+static PyObject *__pyx_pw_5_cdec_10Hypergraph_31inside_outside(PyObject *__pyx_v_self, CYTHON_UNUSED PyObject *unused) {
+  PyObject *__pyx_r = 0;
+  __Pyx_RefNannyDeclarations
+  __Pyx_RefNannySetupContext("inside_outside (wrapper)", 0);
+  __pyx_r = __pyx_pf_5_cdec_10Hypergraph_30inside_outside(((struct __pyx_obj_5_cdec_Hypergraph *)__pyx_v_self));
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+/* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":132
+ *             return self.hg.NumberOfPaths()
+ * 
+ *     def inside_outside(self):             # <<<<<<<<<<<<<<
+ *         cdef FastSparseVector[LogVal[double]]* result = new FastSparseVector[LogVal[double]]()
+ *         cdef LogVal[double] z = hypergraph.InsideOutside(self.hg[0], result)
+ */
+
+static PyObject *__pyx_pf_5_cdec_10Hypergraph_30inside_outside(struct __pyx_obj_5_cdec_Hypergraph *__pyx_v_self) {
+  FastSparseVector<LogVal<double> > *__pyx_v_result;
+  LogVal<double> __pyx_v_z;
+  struct __pyx_obj_5_cdec_SparseVector *__pyx_v_vector = 0;
+  FastSparseVector<LogVal<double> >::const_iterator *__pyx_v_it;
+  CYTHON_UNUSED unsigned int __pyx_v_i;
   PyObject *__pyx_r = NULL;
+  __Pyx_RefNannyDeclarations
   PyObject *__pyx_t_1 = NULL;
-  Py_ssize_t __pyx_t_2;
-  PyObject *__pyx_t_3 = NULL;
-  PyObject *(*__pyx_t_4)(PyObject *);
-  PyObject *__pyx_t_5 = NULL;
-  Py_ssize_t __pyx_t_6;
-  PyObject *(*__pyx_t_7)(PyObject *);
-  PyObject *__pyx_t_8 = NULL;
-  PyObject *__pyx_t_9 = NULL;
-  PyObject *__pyx_t_10 = NULL;
-  PyObject *__pyx_t_11 = NULL;
-  PyObject *(*__pyx_t_12)(PyObject *);
-  __Pyx_RefNannyDeclarations
-  __Pyx_RefNannySetupContext("None", 0);
-  switch (__pyx_generator->resume_label) {
-    case 0: goto __pyx_L3_first_run;
-    case 1: goto __pyx_L4_resume_from_yield;
-    case 2: goto __pyx_L5_resume_from_yield;
-    case 3: goto __pyx_L6_resume_from_yield;
-    case 4: goto __pyx_L13_resume_from_yield;
-    case 5: goto __pyx_L14_resume_from_yield;
-    case 6: goto __pyx_L15_resume_from_yield;
-    default: /* CPython raises the right error here */
-    __Pyx_RefNannyFinishContext();
-    return NULL;
+  size_t __pyx_t_2;
+  unsigned int __pyx_t_3;
+  int __pyx_lineno = 0;
+  const char *__pyx_filename = NULL;
+  int __pyx_clineno = 0;
+  __Pyx_RefNannySetupContext("inside_outside", 0);
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":133
+ * 
+ *     def inside_outside(self):
+ *         cdef FastSparseVector[LogVal[double]]* result = new FastSparseVector[LogVal[double]]()             # <<<<<<<<<<<<<<
+ *         cdef LogVal[double] z = hypergraph.InsideOutside(self.hg[0], result)
+ *         result[0] /= z
+ */
+  __pyx_v_result = new FastSparseVector<LogVal<double> >();
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":134
+ *     def inside_outside(self):
+ *         cdef FastSparseVector[LogVal[double]]* result = new FastSparseVector[LogVal[double]]()
+ *         cdef LogVal[double] z = hypergraph.InsideOutside(self.hg[0], result)             # <<<<<<<<<<<<<<
+ *         result[0] /= z
+ *         cdef SparseVector vector = SparseVector()
+ */
+  __pyx_v_z = InsideOutside<prob_t, EdgeProb, SparseVector<prob_t>, EdgeFeaturesAndProbWeightFunction>((__pyx_v_self->hg[0]), __pyx_v_result);
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":135
+ *         cdef FastSparseVector[LogVal[double]]* result = new FastSparseVector[LogVal[double]]()
+ *         cdef LogVal[double] z = hypergraph.InsideOutside(self.hg[0], result)
+ *         result[0] /= z             # <<<<<<<<<<<<<<
+ *         cdef SparseVector vector = SparseVector()
+ *         vector.vector = new FastSparseVector[double]()
+ */
+  (__pyx_v_result[0]) /= __pyx_v_z;
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":136
+ *         cdef LogVal[double] z = hypergraph.InsideOutside(self.hg[0], result)
+ *         result[0] /= z
+ *         cdef SparseVector vector = SparseVector()             # <<<<<<<<<<<<<<
+ *         vector.vector = new FastSparseVector[double]()
+ *         cdef FastSparseVector[LogVal[double]].const_iterator* it = new FastSparseVector[LogVal[double]].const_iterator(result[0], False)
+ */
+  __pyx_t_1 = PyObject_Call(((PyObject *)((PyObject*)__pyx_ptype_5_cdec_SparseVector)), ((PyObject *)__pyx_empty_tuple), NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 136; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_1);
+  __pyx_v_vector = ((struct __pyx_obj_5_cdec_SparseVector *)__pyx_t_1);
+  __pyx_t_1 = 0;
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":137
+ *         result[0] /= z
+ *         cdef SparseVector vector = SparseVector()
+ *         vector.vector = new FastSparseVector[double]()             # <<<<<<<<<<<<<<
+ *         cdef FastSparseVector[LogVal[double]].const_iterator* it = new FastSparseVector[LogVal[double]].const_iterator(result[0], False)
+ *         cdef unsigned i
+ */
+  __pyx_v_vector->vector = new FastSparseVector<double>();
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":138
+ *         cdef SparseVector vector = SparseVector()
+ *         vector.vector = new FastSparseVector[double]()
+ *         cdef FastSparseVector[LogVal[double]].const_iterator* it = new FastSparseVector[LogVal[double]].const_iterator(result[0], False)             # <<<<<<<<<<<<<<
+ *         cdef unsigned i
+ *         for i in range(result.size()):
+ */
+  __pyx_v_it = new FastSparseVector<LogVal<double> >::const_iterator((__pyx_v_result[0]), 0);
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":140
+ *         cdef FastSparseVector[LogVal[double]].const_iterator* it = new FastSparseVector[LogVal[double]].const_iterator(result[0], False)
+ *         cdef unsigned i
+ *         for i in range(result.size()):             # <<<<<<<<<<<<<<
+ *             vector.vector.set_value(it[0].ptr().first, log(it[0].ptr().second))
+ *             pinc(it[0]) # ++it
+ */
+  __pyx_t_2 = __pyx_v_result->size();
+  for (__pyx_t_3 = 0; __pyx_t_3 < __pyx_t_2; __pyx_t_3+=1) {
+    __pyx_v_i = __pyx_t_3;
+
+    /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":141
+ *         cdef unsigned i
+ *         for i in range(result.size()):
+ *             vector.vector.set_value(it[0].ptr().first, log(it[0].ptr().second))             # <<<<<<<<<<<<<<
+ *             pinc(it[0]) # ++it
+ *         del it
+ */
+    __pyx_v_vector->vector->set_value((__pyx_v_it[0]).operator->()->first, log((__pyx_v_it[0]).operator->()->second));
+
+    /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":142
+ *         for i in range(result.size()):
+ *             vector.vector.set_value(it[0].ptr().first, log(it[0].ptr().second))
+ *             pinc(it[0]) # ++it             # <<<<<<<<<<<<<<
+ *         del it
+ *         del result
+ */
+    (++(__pyx_v_it[0]));
   }
-  __pyx_L3_first_run:;
-  if (unlikely(!__pyx_sent_value)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 58; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/lattice.pxi":59
- *     def todot(self):
- *         def lines():
- *             yield 'digraph lattice {'             # <<<<<<<<<<<<<<
- *             yield 'rankdir = LR;'
- *             yield 'node [shape=circle];'
+  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":143
+ *             vector.vector.set_value(it[0].ptr().first, log(it[0].ptr().second))
+ *             pinc(it[0]) # ++it
+ *         del it             # <<<<<<<<<<<<<<
+ *         del result
+ *         return vector
  */
-  __Pyx_INCREF(((PyObject *)__pyx_kp_s_23));
-  __pyx_r = ((PyObject *)__pyx_kp_s_23);
+  delete __pyx_v_it;
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":144
+ *             pinc(it[0]) # ++it
+ *         del it
+ *         del result             # <<<<<<<<<<<<<<
+ *         return vector
+ * 
+ */
+  delete __pyx_v_result;
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":145
+ *         del it
+ *         del result
+ *         return vector             # <<<<<<<<<<<<<<
+ * 
+ * cdef class HypergraphEdge:
+ */
+  __Pyx_XDECREF(__pyx_r);
+  __Pyx_INCREF(((PyObject *)__pyx_v_vector));
+  __pyx_r = ((PyObject *)__pyx_v_vector);
+  goto __pyx_L0;
+
+  __pyx_r = Py_None; __Pyx_INCREF(Py_None);
+  goto __pyx_L0;
+  __pyx_L1_error:;
+  __Pyx_XDECREF(__pyx_t_1);
+  __Pyx_AddTraceback("_cdec.Hypergraph.inside_outside", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __pyx_r = NULL;
+  __pyx_L0:;
+  __Pyx_XDECREF((PyObject *)__pyx_v_vector);
   __Pyx_XGIVEREF(__pyx_r);
   __Pyx_RefNannyFinishContext();
-  /* return from generator, yielding value */
-  __pyx_generator->resume_label = 1;
   return __pyx_r;
-  __pyx_L4_resume_from_yield:;
-  if (unlikely(!__pyx_sent_value)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 59; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+}
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/lattice.pxi":60
- *         def lines():
- *             yield 'digraph lattice {'
- *             yield 'rankdir = LR;'             # <<<<<<<<<<<<<<
- *             yield 'node [shape=circle];'
- *             for i in range(len(self)):
+/* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":152
+ *     cdef public BaseTRule trule
+ * 
+ *     cdef init(self, hypergraph.Hypergraph* hg, unsigned i):             # <<<<<<<<<<<<<<
+ *         self.hg = hg
+ *         self.edge = &hg.edges_[i]
+ */
+
+static PyObject *__pyx_f_5_cdec_14HypergraphEdge_init(struct __pyx_obj_5_cdec_HypergraphEdge *__pyx_v_self, Hypergraph *__pyx_v_hg, unsigned int __pyx_v_i) {
+  PyObject *__pyx_r = NULL;
+  __Pyx_RefNannyDeclarations
+  PyObject *__pyx_t_1 = NULL;
+  int __pyx_lineno = 0;
+  const char *__pyx_filename = NULL;
+  int __pyx_clineno = 0;
+  __Pyx_RefNannySetupContext("init", 0);
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":153
+ * 
+ *     cdef init(self, hypergraph.Hypergraph* hg, unsigned i):
+ *         self.hg = hg             # <<<<<<<<<<<<<<
+ *         self.edge = &hg.edges_[i]
+ *         self.trule = BaseTRule()
+ */
+  __pyx_v_self->hg = __pyx_v_hg;
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":154
+ *     cdef init(self, hypergraph.Hypergraph* hg, unsigned i):
+ *         self.hg = hg
+ *         self.edge = &hg.edges_[i]             # <<<<<<<<<<<<<<
+ *         self.trule = BaseTRule()
+ *         self.trule.rule = new shared_ptr[grammar.TRule](self.edge.rule_)
+ */
+  __pyx_v_self->edge = (&(__pyx_v_hg->edges_[__pyx_v_i]));
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":155
+ *         self.hg = hg
+ *         self.edge = &hg.edges_[i]
+ *         self.trule = BaseTRule()             # <<<<<<<<<<<<<<
+ *         self.trule.rule = new shared_ptr[grammar.TRule](self.edge.rule_)
+ *         return self
+ */
+  __pyx_t_1 = PyObject_Call(((PyObject *)((PyObject*)__pyx_ptype_5_cdec_BaseTRule)), ((PyObject *)__pyx_empty_tuple), NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 155; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_1);
+  __Pyx_GIVEREF(__pyx_t_1);
+  __Pyx_GOTREF(__pyx_v_self->trule);
+  __Pyx_DECREF(((PyObject *)__pyx_v_self->trule));
+  __pyx_v_self->trule = ((struct __pyx_obj_5_cdec_BaseTRule *)__pyx_t_1);
+  __pyx_t_1 = 0;
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":156
+ *         self.edge = &hg.edges_[i]
+ *         self.trule = BaseTRule()
+ *         self.trule.rule = new shared_ptr[grammar.TRule](self.edge.rule_)             # <<<<<<<<<<<<<<
+ *         return self
+ * 
+ */
+  __pyx_v_self->trule->rule = new boost::shared_ptr<TRule>(__pyx_v_self->edge->rule_);
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":157
+ *         self.trule = BaseTRule()
+ *         self.trule.rule = new shared_ptr[grammar.TRule](self.edge.rule_)
+ *         return self             # <<<<<<<<<<<<<<
+ * 
+ *     def __len__(self):
  */
-  __Pyx_INCREF(((PyObject *)__pyx_kp_s_24));
-  __pyx_r = ((PyObject *)__pyx_kp_s_24);
+  __Pyx_XDECREF(__pyx_r);
+  __Pyx_INCREF(((PyObject *)__pyx_v_self));
+  __pyx_r = ((PyObject *)__pyx_v_self);
+  goto __pyx_L0;
+
+  __pyx_r = Py_None; __Pyx_INCREF(Py_None);
+  goto __pyx_L0;
+  __pyx_L1_error:;
+  __Pyx_XDECREF(__pyx_t_1);
+  __Pyx_AddTraceback("_cdec.HypergraphEdge.init", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __pyx_r = 0;
+  __pyx_L0:;
   __Pyx_XGIVEREF(__pyx_r);
   __Pyx_RefNannyFinishContext();
-  /* return from generator, yielding value */
-  __pyx_generator->resume_label = 2;
   return __pyx_r;
-  __pyx_L5_resume_from_yield:;
-  if (unlikely(!__pyx_sent_value)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 60; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+}
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/lattice.pxi":61
- *             yield 'digraph lattice {'
- *             yield 'rankdir = LR;'
- *             yield 'node [shape=circle];'             # <<<<<<<<<<<<<<
- *             for i in range(len(self)):
- *                 for label, weight, delta in self[i]:
- */
-  __Pyx_INCREF(((PyObject *)__pyx_kp_s_25));
-  __pyx_r = ((PyObject *)__pyx_kp_s_25);
-  __Pyx_XGIVEREF(__pyx_r);
+/* Python wrapper */
+static Py_ssize_t __pyx_pw_5_cdec_14HypergraphEdge_1__len__(PyObject *__pyx_v_self); /*proto*/
+static Py_ssize_t __pyx_pw_5_cdec_14HypergraphEdge_1__len__(PyObject *__pyx_v_self) {
+  Py_ssize_t __pyx_r;
+  __Pyx_RefNannyDeclarations
+  __Pyx_RefNannySetupContext("__len__ (wrapper)", 0);
+  __pyx_r = __pyx_pf_5_cdec_14HypergraphEdge___len__(((struct __pyx_obj_5_cdec_HypergraphEdge *)__pyx_v_self));
   __Pyx_RefNannyFinishContext();
-  /* return from generator, yielding value */
-  __pyx_generator->resume_label = 3;
   return __pyx_r;
-  __pyx_L6_resume_from_yield:;
-  if (unlikely(!__pyx_sent_value)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 61; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+}
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/lattice.pxi":62
- *             yield 'rankdir = LR;'
- *             yield 'node [shape=circle];'
- *             for i in range(len(self)):             # <<<<<<<<<<<<<<
- *                 for label, weight, delta in self[i]:
- *                     yield '%d -> %d [label="%s"];' % (i, i+delta, label.replace('"', '\\"'))
+/* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":159
+ *         return self
+ * 
+ *     def __len__(self):             # <<<<<<<<<<<<<<
+ *         return self.edge.tail_nodes_.size()
+ * 
  */
-  if (unlikely(!__pyx_cur_scope->__pyx_outer_scope->__pyx_v_self)) { __Pyx_RaiseClosureNameError("self"); {__pyx_filename = __pyx_f[3]; __pyx_lineno = 62; __pyx_clineno = __LINE__; goto __pyx_L1_error;} }
-  __pyx_t_1 = ((PyObject *)__pyx_cur_scope->__pyx_outer_scope->__pyx_v_self);
-  __Pyx_INCREF(__pyx_t_1);
-  __pyx_t_2 = PyObject_Length(__pyx_t_1); if (unlikely(__pyx_t_2 == -1)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 62; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
-  __pyx_t_1 = PyInt_FromSsize_t(__pyx_t_2); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 62; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __Pyx_GOTREF(__pyx_t_1);
-  __pyx_t_3 = PyTuple_New(1); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 62; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __Pyx_GOTREF(__pyx_t_3);
-  PyTuple_SET_ITEM(__pyx_t_3, 0, __pyx_t_1);
-  __Pyx_GIVEREF(__pyx_t_1);
-  __pyx_t_1 = 0;
-  __pyx_t_1 = PyObject_Call(__pyx_builtin_range, ((PyObject *)__pyx_t_3), NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 62; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __Pyx_GOTREF(__pyx_t_1);
-  __Pyx_DECREF(((PyObject *)__pyx_t_3)); __pyx_t_3 = 0;
-  if (PyList_CheckExact(__pyx_t_1) || PyTuple_CheckExact(__pyx_t_1)) {
-    __pyx_t_3 = __pyx_t_1; __Pyx_INCREF(__pyx_t_3); __pyx_t_2 = 0;
-    __pyx_t_4 = NULL;
-  } else {
-    __pyx_t_2 = -1; __pyx_t_3 = PyObject_GetIter(__pyx_t_1); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 62; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-    __Pyx_GOTREF(__pyx_t_3);
-    __pyx_t_4 = Py_TYPE(__pyx_t_3)->tp_iternext;
-  }
-  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
-  for (;;) {
-    if (!__pyx_t_4 && PyList_CheckExact(__pyx_t_3)) {
-      if (__pyx_t_2 >= PyList_GET_SIZE(__pyx_t_3)) break;
-      __pyx_t_1 = PyList_GET_ITEM(__pyx_t_3, __pyx_t_2); __Pyx_INCREF(__pyx_t_1); __pyx_t_2++;
-    } else if (!__pyx_t_4 && PyTuple_CheckExact(__pyx_t_3)) {
-      if (__pyx_t_2 >= PyTuple_GET_SIZE(__pyx_t_3)) break;
-      __pyx_t_1 = PyTuple_GET_ITEM(__pyx_t_3, __pyx_t_2); __Pyx_INCREF(__pyx_t_1); __pyx_t_2++;
-    } else {
-      __pyx_t_1 = __pyx_t_4(__pyx_t_3);
-      if (unlikely(!__pyx_t_1)) {
-        if (PyErr_Occurred()) {
-          if (likely(PyErr_ExceptionMatches(PyExc_StopIteration))) PyErr_Clear();
-          else {__pyx_filename = __pyx_f[3]; __pyx_lineno = 62; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-        }
-        break;
-      }
-      __Pyx_GOTREF(__pyx_t_1);
-    }
-    __Pyx_XGOTREF(__pyx_cur_scope->__pyx_v_i);
-    __Pyx_XDECREF(__pyx_cur_scope->__pyx_v_i);
-    __Pyx_GIVEREF(__pyx_t_1);
-    __pyx_cur_scope->__pyx_v_i = __pyx_t_1;
-    __pyx_t_1 = 0;
 
-    /* "/Users/vchahun/Sandbox/cdec/python/src/lattice.pxi":63
- *             yield 'node [shape=circle];'
- *             for i in range(len(self)):
- *                 for label, weight, delta in self[i]:             # <<<<<<<<<<<<<<
- *                     yield '%d -> %d [label="%s"];' % (i, i+delta, label.replace('"', '\\"'))
- *             yield '%d [shape=doublecircle]' % len(self)
+static Py_ssize_t __pyx_pf_5_cdec_14HypergraphEdge___len__(struct __pyx_obj_5_cdec_HypergraphEdge *__pyx_v_self) {
+  Py_ssize_t __pyx_r;
+  __Pyx_RefNannyDeclarations
+  __Pyx_RefNannySetupContext("__len__", 0);
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":160
+ * 
+ *     def __len__(self):
+ *         return self.edge.tail_nodes_.size()             # <<<<<<<<<<<<<<
+ * 
+ *     property head_node:
  */
-    __pyx_t_1 = PyObject_GetItem(((PyObject *)__pyx_cur_scope->__pyx_outer_scope->__pyx_v_self), __pyx_cur_scope->__pyx_v_i); if (!__pyx_t_1) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 63; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-    __Pyx_GOTREF(__pyx_t_1);
-    if (PyList_CheckExact(__pyx_t_1) || PyTuple_CheckExact(__pyx_t_1)) {
-      __pyx_t_5 = __pyx_t_1; __Pyx_INCREF(__pyx_t_5); __pyx_t_6 = 0;
-      __pyx_t_7 = NULL;
-    } else {
-      __pyx_t_6 = -1; __pyx_t_5 = PyObject_GetIter(__pyx_t_1); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 63; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-      __Pyx_GOTREF(__pyx_t_5);
-      __pyx_t_7 = Py_TYPE(__pyx_t_5)->tp_iternext;
-    }
-    __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
-    for (;;) {
-      if (!__pyx_t_7 && PyList_CheckExact(__pyx_t_5)) {
-        if (__pyx_t_6 >= PyList_GET_SIZE(__pyx_t_5)) break;
-        __pyx_t_1 = PyList_GET_ITEM(__pyx_t_5, __pyx_t_6); __Pyx_INCREF(__pyx_t_1); __pyx_t_6++;
-      } else if (!__pyx_t_7 && PyTuple_CheckExact(__pyx_t_5)) {
-        if (__pyx_t_6 >= PyTuple_GET_SIZE(__pyx_t_5)) break;
-        __pyx_t_1 = PyTuple_GET_ITEM(__pyx_t_5, __pyx_t_6); __Pyx_INCREF(__pyx_t_1); __pyx_t_6++;
-      } else {
-        __pyx_t_1 = __pyx_t_7(__pyx_t_5);
-        if (unlikely(!__pyx_t_1)) {
-          if (PyErr_Occurred()) {
-            if (likely(PyErr_ExceptionMatches(PyExc_StopIteration))) PyErr_Clear();
-            else {__pyx_filename = __pyx_f[3]; __pyx_lineno = 63; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-          }
-          break;
-        }
-        __Pyx_GOTREF(__pyx_t_1);
-      }
-      if ((likely(PyTuple_CheckExact(__pyx_t_1))) || (PyList_CheckExact(__pyx_t_1))) {
-        PyObject* sequence = __pyx_t_1;
-        if (likely(PyTuple_CheckExact(sequence))) {
-          if (unlikely(PyTuple_GET_SIZE(sequence) != 3)) {
-            if (PyTuple_GET_SIZE(sequence) > 3) __Pyx_RaiseTooManyValuesError(3);
-            else __Pyx_RaiseNeedMoreValuesError(PyTuple_GET_SIZE(sequence));
-            {__pyx_filename = __pyx_f[3]; __pyx_lineno = 63; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-          }
-          __pyx_t_8 = PyTuple_GET_ITEM(sequence, 0); 
-          __pyx_t_9 = PyTuple_GET_ITEM(sequence, 1); 
-          __pyx_t_10 = PyTuple_GET_ITEM(sequence, 2); 
-        } else {
-          if (unlikely(PyList_GET_SIZE(sequence) != 3)) {
-            if (PyList_GET_SIZE(sequence) > 3) __Pyx_RaiseTooManyValuesError(3);
-            else __Pyx_RaiseNeedMoreValuesError(PyList_GET_SIZE(sequence));
-            {__pyx_filename = __pyx_f[3]; __pyx_lineno = 63; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-          }
-          __pyx_t_8 = PyList_GET_ITEM(sequence, 0); 
-          __pyx_t_9 = PyList_GET_ITEM(sequence, 1); 
-          __pyx_t_10 = PyList_GET_ITEM(sequence, 2); 
-        }
-        __Pyx_INCREF(__pyx_t_8);
-        __Pyx_INCREF(__pyx_t_9);
-        __Pyx_INCREF(__pyx_t_10);
-        __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
-      } else {
-        Py_ssize_t index = -1;
-        __pyx_t_11 = PyObject_GetIter(__pyx_t_1); if (unlikely(!__pyx_t_11)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 63; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-        __Pyx_GOTREF(__pyx_t_11);
-        __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
-        __pyx_t_12 = Py_TYPE(__pyx_t_11)->tp_iternext;
-        index = 0; __pyx_t_8 = __pyx_t_12(__pyx_t_11); if (unlikely(!__pyx_t_8)) goto __pyx_L11_unpacking_failed;
-        __Pyx_GOTREF(__pyx_t_8);
-        index = 1; __pyx_t_9 = __pyx_t_12(__pyx_t_11); if (unlikely(!__pyx_t_9)) goto __pyx_L11_unpacking_failed;
-        __Pyx_GOTREF(__pyx_t_9);
-        index = 2; __pyx_t_10 = __pyx_t_12(__pyx_t_11); if (unlikely(!__pyx_t_10)) goto __pyx_L11_unpacking_failed;
-        __Pyx_GOTREF(__pyx_t_10);
-        if (__Pyx_IternextUnpackEndCheck(__pyx_t_12(__pyx_t_11), 3) < 0) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 63; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-        __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0;
-        goto __pyx_L12_unpacking_done;
-        __pyx_L11_unpacking_failed:;
-        __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0;
-        if (PyErr_Occurred() && PyErr_ExceptionMatches(PyExc_StopIteration)) PyErr_Clear();
-        if (!PyErr_Occurred()) __Pyx_RaiseNeedMoreValuesError(index);
-        {__pyx_filename = __pyx_f[3]; __pyx_lineno = 63; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-        __pyx_L12_unpacking_done:;
-      }
-      __Pyx_XGOTREF(__pyx_cur_scope->__pyx_v_label);
-      __Pyx_XDECREF(__pyx_cur_scope->__pyx_v_label);
-      __Pyx_GIVEREF(__pyx_t_8);
-      __pyx_cur_scope->__pyx_v_label = __pyx_t_8;
-      __pyx_t_8 = 0;
-      __Pyx_XGOTREF(__pyx_cur_scope->__pyx_v_weight);
-      __Pyx_XDECREF(__pyx_cur_scope->__pyx_v_weight);
-      __Pyx_GIVEREF(__pyx_t_9);
-      __pyx_cur_scope->__pyx_v_weight = __pyx_t_9;
-      __pyx_t_9 = 0;
-      __Pyx_XGOTREF(__pyx_cur_scope->__pyx_v_delta);
-      __Pyx_XDECREF(__pyx_cur_scope->__pyx_v_delta);
-      __Pyx_GIVEREF(__pyx_t_10);
-      __pyx_cur_scope->__pyx_v_delta = __pyx_t_10;
-      __pyx_t_10 = 0;
-
-      /* "/Users/vchahun/Sandbox/cdec/python/src/lattice.pxi":64
- *             for i in range(len(self)):
- *                 for label, weight, delta in self[i]:
- *                     yield '%d -> %d [label="%s"];' % (i, i+delta, label.replace('"', '\\"'))             # <<<<<<<<<<<<<<
- *             yield '%d [shape=doublecircle]' % len(self)
- *             yield '}'
- */
-      __pyx_t_1 = PyNumber_Add(__pyx_cur_scope->__pyx_v_i, __pyx_cur_scope->__pyx_v_delta); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 64; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-      __Pyx_GOTREF(__pyx_t_1);
-      __pyx_t_10 = PyObject_GetAttr(__pyx_cur_scope->__pyx_v_label, __pyx_n_s__replace); if (unlikely(!__pyx_t_10)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 64; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-      __Pyx_GOTREF(__pyx_t_10);
-      __pyx_t_9 = PyObject_Call(__pyx_t_10, ((PyObject *)__pyx_k_tuple_29), NULL); if (unlikely(!__pyx_t_9)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 64; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-      __Pyx_GOTREF(__pyx_t_9);
-      __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0;
-      __pyx_t_10 = PyTuple_New(3); if (unlikely(!__pyx_t_10)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 64; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-      __Pyx_GOTREF(__pyx_t_10);
-      __Pyx_INCREF(__pyx_cur_scope->__pyx_v_i);
-      PyTuple_SET_ITEM(__pyx_t_10, 0, __pyx_cur_scope->__pyx_v_i);
-      __Pyx_GIVEREF(__pyx_cur_scope->__pyx_v_i);
-      PyTuple_SET_ITEM(__pyx_t_10, 1, __pyx_t_1);
-      __Pyx_GIVEREF(__pyx_t_1);
-      PyTuple_SET_ITEM(__pyx_t_10, 2, __pyx_t_9);
-      __Pyx_GIVEREF(__pyx_t_9);
-      __pyx_t_1 = 0;
-      __pyx_t_9 = 0;
-      __pyx_t_9 = PyNumber_Remainder(((PyObject *)__pyx_kp_s_26), ((PyObject *)__pyx_t_10)); if (unlikely(!__pyx_t_9)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 64; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-      __Pyx_GOTREF(((PyObject *)__pyx_t_9));
-      __Pyx_DECREF(((PyObject *)__pyx_t_10)); __pyx_t_10 = 0;
-      __pyx_r = ((PyObject *)__pyx_t_9);
-      __pyx_t_9 = 0;
-      __pyx_cur_scope->__pyx_t_0 = __pyx_t_2;
-      __Pyx_XGIVEREF(__pyx_t_3);
-      __pyx_cur_scope->__pyx_t_1 = __pyx_t_3;
-      __pyx_cur_scope->__pyx_t_2 = __pyx_t_4;
-      __Pyx_XGIVEREF(__pyx_t_5);
-      __pyx_cur_scope->__pyx_t_3 = __pyx_t_5;
-      __pyx_cur_scope->__pyx_t_4 = __pyx_t_6;
-      __pyx_cur_scope->__pyx_t_5 = __pyx_t_7;
-      __Pyx_XGIVEREF(__pyx_r);
-      __Pyx_RefNannyFinishContext();
-      /* return from generator, yielding value */
-      __pyx_generator->resume_label = 4;
-      return __pyx_r;
-      __pyx_L13_resume_from_yield:;
-      __pyx_t_2 = __pyx_cur_scope->__pyx_t_0;
-      __pyx_t_3 = __pyx_cur_scope->__pyx_t_1;
-      __pyx_cur_scope->__pyx_t_1 = 0;
-      __Pyx_XGOTREF(__pyx_t_3);
-      __pyx_t_4 = __pyx_cur_scope->__pyx_t_2;
-      __pyx_t_5 = __pyx_cur_scope->__pyx_t_3;
-      __pyx_cur_scope->__pyx_t_3 = 0;
-      __Pyx_XGOTREF(__pyx_t_5);
-      __pyx_t_6 = __pyx_cur_scope->__pyx_t_4;
-      __pyx_t_7 = __pyx_cur_scope->__pyx_t_5;
-      if (unlikely(!__pyx_sent_value)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 64; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-    }
-    __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
-  }
-  __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
+  __pyx_r = __pyx_v_self->edge->tail_nodes_.size();
+  goto __pyx_L0;
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/lattice.pxi":65
- *                 for label, weight, delta in self[i]:
- *                     yield '%d -> %d [label="%s"];' % (i, i+delta, label.replace('"', '\\"'))
- *             yield '%d [shape=doublecircle]' % len(self)             # <<<<<<<<<<<<<<
- *             yield '}'
- *         return '\n'.join(lines()).encode('utf8')
- */
-  __pyx_t_3 = ((PyObject *)__pyx_cur_scope->__pyx_outer_scope->__pyx_v_self);
-  __Pyx_INCREF(__pyx_t_3);
-  __pyx_t_2 = PyObject_Length(__pyx_t_3); if (unlikely(__pyx_t_2 == -1)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 65; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
-  __pyx_t_3 = PyInt_FromSsize_t(__pyx_t_2); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 65; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __Pyx_GOTREF(__pyx_t_3);
-  __pyx_t_5 = PyNumber_Remainder(((PyObject *)__pyx_kp_s_30), __pyx_t_3); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 65; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __Pyx_GOTREF(((PyObject *)__pyx_t_5));
-  __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
-  __pyx_r = ((PyObject *)__pyx_t_5);
-  __pyx_t_5 = 0;
-  __Pyx_XGIVEREF(__pyx_r);
+  __pyx_r = 0;
+  __pyx_L0:;
   __Pyx_RefNannyFinishContext();
-  /* return from generator, yielding value */
-  __pyx_generator->resume_label = 5;
   return __pyx_r;
-  __pyx_L14_resume_from_yield:;
-  if (unlikely(!__pyx_sent_value)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 65; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+}
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/lattice.pxi":66
- *                     yield '%d -> %d [label="%s"];' % (i, i+delta, label.replace('"', '\\"'))
- *             yield '%d [shape=doublecircle]' % len(self)
- *             yield '}'             # <<<<<<<<<<<<<<
- *         return '\n'.join(lines()).encode('utf8')
- */
-  __Pyx_INCREF(((PyObject *)__pyx_kp_s_31));
-  __pyx_r = ((PyObject *)__pyx_kp_s_31);
-  __Pyx_XGIVEREF(__pyx_r);
+/* Python wrapper */
+static PyObject *__pyx_pw_5_cdec_14HypergraphEdge_9head_node_1__get__(PyObject *__pyx_v_self); /*proto*/
+static PyObject *__pyx_pw_5_cdec_14HypergraphEdge_9head_node_1__get__(PyObject *__pyx_v_self) {
+  PyObject *__pyx_r = 0;
+  __Pyx_RefNannyDeclarations
+  __Pyx_RefNannySetupContext("__get__ (wrapper)", 0);
+  __pyx_r = __pyx_pf_5_cdec_14HypergraphEdge_9head_node___get__(((struct __pyx_obj_5_cdec_HypergraphEdge *)__pyx_v_self));
   __Pyx_RefNannyFinishContext();
-  /* return from generator, yielding value */
-  __pyx_generator->resume_label = 6;
   return __pyx_r;
-  __pyx_L15_resume_from_yield:;
-  if (unlikely(!__pyx_sent_value)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 66; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  PyErr_SetNone(PyExc_StopIteration);
-  goto __pyx_L0;
-  __pyx_L1_error:;
-  __Pyx_XDECREF(__pyx_t_1);
-  __Pyx_XDECREF(__pyx_t_3);
-  __Pyx_XDECREF(__pyx_t_5);
-  __Pyx_XDECREF(__pyx_t_8);
-  __Pyx_XDECREF(__pyx_t_9);
-  __Pyx_XDECREF(__pyx_t_10);
-  __Pyx_XDECREF(__pyx_t_11);
-  __Pyx_AddTraceback("lines", __pyx_clineno, __pyx_lineno, __pyx_filename);
-  __pyx_L0:;
-  __Pyx_XDECREF(__pyx_r);
-  __pyx_generator->resume_label = -1;
-  __Pyx_RefNannyFinishContext();
-  return NULL;
 }
 
-/* "/Users/vchahun/Sandbox/cdec/python/src/lattice.pxi":57
- *         del self.lattice
+/* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":163
+ * 
+ *     property head_node:
+ *         def __get__(self):             # <<<<<<<<<<<<<<
+ *             return HypergraphNode().init(self.hg, self.edge.head_node_)
  * 
- *     def todot(self):             # <<<<<<<<<<<<<<
- *         def lines():
- *             yield 'digraph lattice {'
  */
 
-static PyObject *__pyx_pf_5_cdec_7Lattice_15todot(struct __pyx_obj_5_cdec_Lattice *__pyx_v_self) {
-  struct __pyx_obj_5_cdec___pyx_scope_struct_16_todot *__pyx_cur_scope;
-  PyObject *__pyx_v_lines = 0;
+static PyObject *__pyx_pf_5_cdec_14HypergraphEdge_9head_node___get__(struct __pyx_obj_5_cdec_HypergraphEdge *__pyx_v_self) {
   PyObject *__pyx_r = NULL;
   __Pyx_RefNannyDeclarations
   PyObject *__pyx_t_1 = NULL;
   PyObject *__pyx_t_2 = NULL;
-  PyObject *__pyx_t_3 = NULL;
   int __pyx_lineno = 0;
   const char *__pyx_filename = NULL;
   int __pyx_clineno = 0;
-  __Pyx_RefNannySetupContext("todot", 0);
-  __pyx_cur_scope = (struct __pyx_obj_5_cdec___pyx_scope_struct_16_todot *)__pyx_ptype_5_cdec___pyx_scope_struct_16_todot->tp_new(__pyx_ptype_5_cdec___pyx_scope_struct_16_todot, __pyx_empty_tuple, NULL);
-  if (unlikely(!__pyx_cur_scope)) {
-    __Pyx_RefNannyFinishContext();
-    return NULL;
-  }
-  __Pyx_GOTREF(__pyx_cur_scope);
-  __pyx_cur_scope->__pyx_v_self = __pyx_v_self;
-  __Pyx_INCREF((PyObject *)__pyx_cur_scope->__pyx_v_self);
-  __Pyx_GIVEREF((PyObject *)__pyx_cur_scope->__pyx_v_self);
+  __Pyx_RefNannySetupContext("__get__", 0);
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/lattice.pxi":58
+  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":164
+ *     property head_node:
+ *         def __get__(self):
+ *             return HypergraphNode().init(self.hg, self.edge.head_node_)             # <<<<<<<<<<<<<<
  * 
- *     def todot(self):
- *         def lines():             # <<<<<<<<<<<<<<
- *             yield 'digraph lattice {'
- *             yield 'rankdir = LR;'
- */
-  __pyx_t_1 = __Pyx_CyFunction_NewEx(&__pyx_mdef_5_cdec_7Lattice_5todot_1lines, 0, ((PyObject*)__pyx_cur_scope), __pyx_n_s___cdec, ((PyObject *)__pyx_k_codeobj_33)); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 58; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __Pyx_GOTREF(__pyx_t_1);
-  __pyx_v_lines = __pyx_t_1;
-  __pyx_t_1 = 0;
-
-  /* "/Users/vchahun/Sandbox/cdec/python/src/lattice.pxi":67
- *             yield '%d [shape=doublecircle]' % len(self)
- *             yield '}'
- *         return '\n'.join(lines()).encode('utf8')             # <<<<<<<<<<<<<<
+ *     property tail_nodes:
  */
   __Pyx_XDECREF(__pyx_r);
-  __pyx_t_1 = PyObject_GetAttr(((PyObject *)__pyx_kp_s_35), __pyx_n_s__join); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 67; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_1 = PyObject_Call(((PyObject *)((PyObject*)__pyx_ptype_5_cdec_HypergraphNode)), ((PyObject *)__pyx_empty_tuple), NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 164; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __Pyx_GOTREF(__pyx_t_1);
-  __pyx_t_2 = PyObject_Call(__pyx_v_lines, ((PyObject *)__pyx_empty_tuple), NULL); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 67; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __Pyx_GOTREF(__pyx_t_2);
-  __pyx_t_3 = PyTuple_New(1); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 67; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __Pyx_GOTREF(__pyx_t_3);
-  PyTuple_SET_ITEM(__pyx_t_3, 0, __pyx_t_2);
-  __Pyx_GIVEREF(__pyx_t_2);
-  __pyx_t_2 = 0;
-  __pyx_t_2 = PyObject_Call(__pyx_t_1, ((PyObject *)__pyx_t_3), NULL); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 67; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_2 = ((struct __pyx_vtabstruct_5_cdec_HypergraphNode *)((struct __pyx_obj_5_cdec_HypergraphNode *)__pyx_t_1)->__pyx_vtab)->init(((struct __pyx_obj_5_cdec_HypergraphNode *)__pyx_t_1), __pyx_v_self->hg, __pyx_v_self->edge->head_node_); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 164; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __Pyx_GOTREF(__pyx_t_2);
   __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
-  __Pyx_DECREF(((PyObject *)__pyx_t_3)); __pyx_t_3 = 0;
-  __pyx_t_3 = PyObject_GetAttr(__pyx_t_2, __pyx_n_s__encode); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 67; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __Pyx_GOTREF(__pyx_t_3);
-  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
-  __pyx_t_2 = PyObject_Call(__pyx_t_3, ((PyObject *)__pyx_k_tuple_36), NULL); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 67; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __Pyx_GOTREF(__pyx_t_2);
-  __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
   __pyx_r = __pyx_t_2;
   __pyx_t_2 = 0;
   goto __pyx_L0;
@@ -9954,166 +9948,160 @@ static PyObject *__pyx_pf_5_cdec_7Lattice_15todot(struct __pyx_obj_5_cdec_Lattic
   __pyx_L1_error:;
   __Pyx_XDECREF(__pyx_t_1);
   __Pyx_XDECREF(__pyx_t_2);
-  __Pyx_XDECREF(__pyx_t_3);
-  __Pyx_AddTraceback("_cdec.Lattice.todot", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __Pyx_AddTraceback("_cdec.HypergraphEdge.head_node.__get__", __pyx_clineno, __pyx_lineno, __pyx_filename);
   __pyx_r = NULL;
   __pyx_L0:;
-  __Pyx_XDECREF(__pyx_v_lines);
-  __Pyx_DECREF(((PyObject *)__pyx_cur_scope));
   __Pyx_XGIVEREF(__pyx_r);
   __Pyx_RefNannyFinishContext();
   return __pyx_r;
 }
+static PyObject *__pyx_gb_5_cdec_14HypergraphEdge_10tail_nodes_2generator10(__pyx_GeneratorObject *__pyx_generator, PyObject *__pyx_sent_value); /* proto */
 
-/* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":3
- * cimport mteval
- * 
- * cdef SufficientStats as_stats(x, y):             # <<<<<<<<<<<<<<
- *     if isinstance(x, SufficientStats):
- *         return x
- */
-
-static struct __pyx_obj_5_cdec_SufficientStats *__pyx_f_5_cdec_as_stats(PyObject *__pyx_v_x, PyObject *__pyx_v_y) {
-  struct __pyx_obj_5_cdec_SufficientStats *__pyx_v_stats = NULL;
-  struct __pyx_obj_5_cdec_SufficientStats *__pyx_r = NULL;
-  __Pyx_RefNannyDeclarations
-  PyObject *__pyx_t_1 = NULL;
-  int __pyx_t_2;
-  int __pyx_t_3;
-  int __pyx_t_4;
-  int __pyx_lineno = 0;
-  const char *__pyx_filename = NULL;
-  int __pyx_clineno = 0;
-  __Pyx_RefNannySetupContext("as_stats", 0);
+/* Python wrapper */
+static PyObject *__pyx_pw_5_cdec_14HypergraphEdge_10tail_nodes_1__get__(PyObject *__pyx_v_self); /*proto*/
+static PyObject *__pyx_pw_5_cdec_14HypergraphEdge_10tail_nodes_1__get__(PyObject *__pyx_v_self) {
+  PyObject *__pyx_r = 0;
+  __Pyx_RefNannyDeclarations
+  __Pyx_RefNannySetupContext("__get__ (wrapper)", 0);
+  __pyx_r = __pyx_pf_5_cdec_14HypergraphEdge_10tail_nodes___get__(((struct __pyx_obj_5_cdec_HypergraphEdge *)__pyx_v_self));
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":4
+/* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":167
  * 
- * cdef SufficientStats as_stats(x, y):
- *     if isinstance(x, SufficientStats):             # <<<<<<<<<<<<<<
- *         return x
- *     elif x == 0 and isinstance(y, SufficientStats):
+ *     property tail_nodes:
+ *         def __get__(self):             # <<<<<<<<<<<<<<
+ *             cdef unsigned i
+ *             for i in range(self.edge.tail_nodes_.size()):
  */
-  __pyx_t_1 = ((PyObject *)((PyObject*)__pyx_ptype_5_cdec_SufficientStats));
-  __Pyx_INCREF(__pyx_t_1);
-  __pyx_t_2 = __Pyx_TypeCheck(__pyx_v_x, __pyx_t_1); 
-  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
-  if (__pyx_t_2) {
 
-    /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":5
- * cdef SufficientStats as_stats(x, y):
- *     if isinstance(x, SufficientStats):
- *         return x             # <<<<<<<<<<<<<<
- *     elif x == 0 and isinstance(y, SufficientStats):
- *         stats = SufficientStats()
- */
-    __Pyx_XDECREF(((PyObject *)__pyx_r));
-    if (!(likely(((__pyx_v_x) == Py_None) || likely(__Pyx_TypeTest(__pyx_v_x, __pyx_ptype_5_cdec_SufficientStats))))) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 5; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-    __Pyx_INCREF(__pyx_v_x);
-    __pyx_r = ((struct __pyx_obj_5_cdec_SufficientStats *)__pyx_v_x);
-    goto __pyx_L0;
-    goto __pyx_L3;
+static PyObject *__pyx_pf_5_cdec_14HypergraphEdge_10tail_nodes___get__(struct __pyx_obj_5_cdec_HypergraphEdge *__pyx_v_self) {
+  struct __pyx_obj_5_cdec___pyx_scope_struct_14___get__ *__pyx_cur_scope;
+  PyObject *__pyx_r = NULL;
+  __Pyx_RefNannyDeclarations
+  int __pyx_lineno = 0;
+  const char *__pyx_filename = NULL;
+  int __pyx_clineno = 0;
+  __Pyx_RefNannySetupContext("__get__", 0);
+  __pyx_cur_scope = (struct __pyx_obj_5_cdec___pyx_scope_struct_14___get__ *)__pyx_ptype_5_cdec___pyx_scope_struct_14___get__->tp_new(__pyx_ptype_5_cdec___pyx_scope_struct_14___get__, __pyx_empty_tuple, NULL);
+  if (unlikely(!__pyx_cur_scope)) {
+    __Pyx_RefNannyFinishContext();
+    return NULL;
   }
-
-  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":6
- *     if isinstance(x, SufficientStats):
- *         return x
- *     elif x == 0 and isinstance(y, SufficientStats):             # <<<<<<<<<<<<<<
- *         stats = SufficientStats()
- *         stats.stats = new mteval.SufficientStats()
- */
-  __pyx_t_1 = PyObject_RichCompare(__pyx_v_x, __pyx_int_0, Py_EQ); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 6; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __Pyx_GOTREF(__pyx_t_1);
-  __pyx_t_2 = __Pyx_PyObject_IsTrue(__pyx_t_1); if (unlikely(__pyx_t_2 < 0)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 6; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
-  if (__pyx_t_2) {
-    __pyx_t_1 = ((PyObject *)((PyObject*)__pyx_ptype_5_cdec_SufficientStats));
-    __Pyx_INCREF(__pyx_t_1);
-    __pyx_t_3 = __Pyx_TypeCheck(__pyx_v_y, __pyx_t_1); 
-    __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
-    __pyx_t_4 = __pyx_t_3;
-  } else {
-    __pyx_t_4 = __pyx_t_2;
+  __Pyx_GOTREF(__pyx_cur_scope);
+  __pyx_cur_scope->__pyx_v_self = __pyx_v_self;
+  __Pyx_INCREF((PyObject *)__pyx_cur_scope->__pyx_v_self);
+  __Pyx_GIVEREF((PyObject *)__pyx_cur_scope->__pyx_v_self);
+  {
+    __pyx_GeneratorObject *gen = __Pyx_Generator_New((__pyx_generator_body_t) __pyx_gb_5_cdec_14HypergraphEdge_10tail_nodes_2generator10, (PyObject *) __pyx_cur_scope); if (unlikely(!gen)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 167; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_DECREF(__pyx_cur_scope);
+    __Pyx_RefNannyFinishContext();
+    return (PyObject *) gen;
   }
-  if (__pyx_t_4) {
 
-    /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":7
- *         return x
- *     elif x == 0 and isinstance(y, SufficientStats):
- *         stats = SufficientStats()             # <<<<<<<<<<<<<<
- *         stats.stats = new mteval.SufficientStats()
- *         stats.metric = (<SufficientStats> y).metric
- */
-    __pyx_t_1 = PyObject_Call(((PyObject *)((PyObject*)__pyx_ptype_5_cdec_SufficientStats)), ((PyObject *)__pyx_empty_tuple), NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 7; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-    __Pyx_GOTREF(__pyx_t_1);
-    __pyx_v_stats = ((struct __pyx_obj_5_cdec_SufficientStats *)__pyx_t_1);
-    __pyx_t_1 = 0;
+  __pyx_r = Py_None; __Pyx_INCREF(Py_None);
+  goto __pyx_L0;
+  __pyx_L1_error:;
+  __Pyx_AddTraceback("_cdec.HypergraphEdge.tail_nodes.__get__", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __pyx_r = NULL;
+  __pyx_L0:;
+  __Pyx_DECREF(((PyObject *)__pyx_cur_scope));
+  __Pyx_XGIVEREF(__pyx_r);
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
 
-    /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":8
- *     elif x == 0 and isinstance(y, SufficientStats):
- *         stats = SufficientStats()
- *         stats.stats = new mteval.SufficientStats()             # <<<<<<<<<<<<<<
- *         stats.metric = (<SufficientStats> y).metric
- *         return stats
- */
-    __pyx_v_stats->stats = new SufficientStats();
+static PyObject *__pyx_gb_5_cdec_14HypergraphEdge_10tail_nodes_2generator10(__pyx_GeneratorObject *__pyx_generator, PyObject *__pyx_sent_value) /* generator body */
+{
+  struct __pyx_obj_5_cdec___pyx_scope_struct_14___get__ *__pyx_cur_scope = ((struct __pyx_obj_5_cdec___pyx_scope_struct_14___get__ *)__pyx_generator->closure);
+  PyObject *__pyx_r = NULL;
+  unsigned int __pyx_t_1;
+  unsigned int __pyx_t_2;
+  PyObject *__pyx_t_3 = NULL;
+  PyObject *__pyx_t_4 = NULL;
+  __Pyx_RefNannyDeclarations
+  __Pyx_RefNannySetupContext("None", 0);
+  switch (__pyx_generator->resume_label) {
+    case 0: goto __pyx_L3_first_run;
+    case 1: goto __pyx_L6_resume_from_yield;
+    default: /* CPython raises the right error here */
+    __Pyx_RefNannyFinishContext();
+    return NULL;
+  }
+  __pyx_L3_first_run:;
+  if (unlikely(!__pyx_sent_value)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 167; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
 
-    /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":9
- *         stats = SufficientStats()
- *         stats.stats = new mteval.SufficientStats()
- *         stats.metric = (<SufficientStats> y).metric             # <<<<<<<<<<<<<<
- *         return stats
+  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":169
+ *         def __get__(self):
+ *             cdef unsigned i
+ *             for i in range(self.edge.tail_nodes_.size()):             # <<<<<<<<<<<<<<
+ *                 yield HypergraphNode().init(self.hg, self.edge.tail_nodes_[i])
  * 
  */
-    __pyx_v_stats->metric = ((struct __pyx_obj_5_cdec_SufficientStats *)__pyx_v_y)->metric;
+  __pyx_t_1 = __pyx_cur_scope->__pyx_v_self->edge->tail_nodes_.size();
+  for (__pyx_t_2 = 0; __pyx_t_2 < __pyx_t_1; __pyx_t_2+=1) {
+    __pyx_cur_scope->__pyx_v_i = __pyx_t_2;
 
-    /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":10
- *         stats.stats = new mteval.SufficientStats()
- *         stats.metric = (<SufficientStats> y).metric
- *         return stats             # <<<<<<<<<<<<<<
+    /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":170
+ *             cdef unsigned i
+ *             for i in range(self.edge.tail_nodes_.size()):
+ *                 yield HypergraphNode().init(self.hg, self.edge.tail_nodes_[i])             # <<<<<<<<<<<<<<
  * 
- * cdef class Candidate:
+ *     property span:
  */
-    __Pyx_XDECREF(((PyObject *)__pyx_r));
-    __Pyx_INCREF(((PyObject *)__pyx_v_stats));
-    __pyx_r = __pyx_v_stats;
-    goto __pyx_L0;
-    goto __pyx_L3;
+    __pyx_t_3 = PyObject_Call(((PyObject *)((PyObject*)__pyx_ptype_5_cdec_HypergraphNode)), ((PyObject *)__pyx_empty_tuple), NULL); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 170; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_3);
+    __pyx_t_4 = ((struct __pyx_vtabstruct_5_cdec_HypergraphNode *)((struct __pyx_obj_5_cdec_HypergraphNode *)__pyx_t_3)->__pyx_vtab)->init(((struct __pyx_obj_5_cdec_HypergraphNode *)__pyx_t_3), __pyx_cur_scope->__pyx_v_self->hg, (__pyx_cur_scope->__pyx_v_self->edge->tail_nodes_[__pyx_cur_scope->__pyx_v_i])); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 170; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_4);
+    __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
+    __pyx_r = __pyx_t_4;
+    __pyx_t_4 = 0;
+    __pyx_cur_scope->__pyx_t_0 = __pyx_t_1;
+    __pyx_cur_scope->__pyx_t_1 = __pyx_t_2;
+    __Pyx_XGIVEREF(__pyx_r);
+    __Pyx_RefNannyFinishContext();
+    /* return from generator, yielding value */
+    __pyx_generator->resume_label = 1;
+    return __pyx_r;
+    __pyx_L6_resume_from_yield:;
+    __pyx_t_1 = __pyx_cur_scope->__pyx_t_0;
+    __pyx_t_2 = __pyx_cur_scope->__pyx_t_1;
+    if (unlikely(!__pyx_sent_value)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 170; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   }
-  __pyx_L3:;
-
-  __pyx_r = ((struct __pyx_obj_5_cdec_SufficientStats *)Py_None); __Pyx_INCREF(Py_None);
+  PyErr_SetNone(PyExc_StopIteration);
   goto __pyx_L0;
   __pyx_L1_error:;
-  __Pyx_XDECREF(__pyx_t_1);
-  __Pyx_AddTraceback("_cdec.as_stats", __pyx_clineno, __pyx_lineno, __pyx_filename);
-  __pyx_r = 0;
+  __Pyx_XDECREF(__pyx_t_3);
+  __Pyx_XDECREF(__pyx_t_4);
+  __Pyx_AddTraceback("__get__", __pyx_clineno, __pyx_lineno, __pyx_filename);
   __pyx_L0:;
-  __Pyx_XDECREF((PyObject *)__pyx_v_stats);
-  __Pyx_XGIVEREF((PyObject *)__pyx_r);
+  __Pyx_XDECREF(__pyx_r);
+  __pyx_generator->resume_label = -1;
   __Pyx_RefNannyFinishContext();
-  return __pyx_r;
+  return NULL;
 }
 
 /* Python wrapper */
-static PyObject *__pyx_pw_5_cdec_9Candidate_5words_1__get__(PyObject *__pyx_v_self); /*proto*/
-static PyObject *__pyx_pw_5_cdec_9Candidate_5words_1__get__(PyObject *__pyx_v_self) {
+static PyObject *__pyx_pw_5_cdec_14HypergraphEdge_4span_1__get__(PyObject *__pyx_v_self); /*proto*/
+static PyObject *__pyx_pw_5_cdec_14HypergraphEdge_4span_1__get__(PyObject *__pyx_v_self) {
   PyObject *__pyx_r = 0;
   __Pyx_RefNannyDeclarations
   __Pyx_RefNannySetupContext("__get__ (wrapper)", 0);
-  __pyx_r = __pyx_pf_5_cdec_9Candidate_5words___get__(((struct __pyx_obj_5_cdec_Candidate *)__pyx_v_self));
+  __pyx_r = __pyx_pf_5_cdec_14HypergraphEdge_4span___get__(((struct __pyx_obj_5_cdec_HypergraphEdge *)__pyx_v_self));
   __Pyx_RefNannyFinishContext();
   return __pyx_r;
 }
 
-/* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":17
+/* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":173
  * 
- *     property words:
+ *     property span:
  *         def __get__(self):             # <<<<<<<<<<<<<<
- *             return unicode(GetString(self.candidate.ewords).c_str(), encoding='utf8')
+ *             return (self.edge.i_, self.edge.j_)
  * 
  */
 
-static PyObject *__pyx_pf_5_cdec_9Candidate_5words___get__(struct __pyx_obj_5_cdec_Candidate *__pyx_v_self) {
+static PyObject *__pyx_pf_5_cdec_14HypergraphEdge_4span___get__(struct __pyx_obj_5_cdec_HypergraphEdge *__pyx_v_self) {
   PyObject *__pyx_r = NULL;
   __Pyx_RefNannyDeclarations
   PyObject *__pyx_t_1 = NULL;
@@ -10124,29 +10112,27 @@ static PyObject *__pyx_pf_5_cdec_9Candidate_5words___get__(struct __pyx_obj_5_cd
   int __pyx_clineno = 0;
   __Pyx_RefNannySetupContext("__get__", 0);
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":18
- *     property words:
+  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":174
+ *     property span:
  *         def __get__(self):
- *             return unicode(GetString(self.candidate.ewords).c_str(), encoding='utf8')             # <<<<<<<<<<<<<<
+ *             return (self.edge.i_, self.edge.j_)             # <<<<<<<<<<<<<<
  * 
- *     property fmap:
+ *     property feature_values:
  */
   __Pyx_XDECREF(__pyx_r);
-  __pyx_t_1 = PyBytes_FromString(TD::GetString(__pyx_v_self->candidate->ewords).c_str()); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 18; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __Pyx_GOTREF(((PyObject *)__pyx_t_1));
-  __pyx_t_2 = PyTuple_New(1); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 18; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_1 = PyInt_FromLong(__pyx_v_self->edge->i_); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 174; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_1);
+  __pyx_t_2 = PyInt_FromLong(__pyx_v_self->edge->j_); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 174; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __Pyx_GOTREF(__pyx_t_2);
-  PyTuple_SET_ITEM(__pyx_t_2, 0, ((PyObject *)__pyx_t_1));
-  __Pyx_GIVEREF(((PyObject *)__pyx_t_1));
-  __pyx_t_1 = 0;
-  __pyx_t_1 = PyDict_New(); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 18; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __Pyx_GOTREF(((PyObject *)__pyx_t_1));
-  if (PyDict_SetItem(__pyx_t_1, ((PyObject *)__pyx_n_s__encoding), ((PyObject *)__pyx_n_s__utf8)) < 0) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 18; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __pyx_t_3 = PyObject_Call(((PyObject *)((PyObject*)(&PyUnicode_Type))), ((PyObject *)__pyx_t_2), ((PyObject *)__pyx_t_1)); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 18; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_3 = PyTuple_New(2); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 174; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __Pyx_GOTREF(__pyx_t_3);
-  __Pyx_DECREF(((PyObject *)__pyx_t_2)); __pyx_t_2 = 0;
-  __Pyx_DECREF(((PyObject *)__pyx_t_1)); __pyx_t_1 = 0;
-  __pyx_r = __pyx_t_3;
+  PyTuple_SET_ITEM(__pyx_t_3, 0, __pyx_t_1);
+  __Pyx_GIVEREF(__pyx_t_1);
+  PyTuple_SET_ITEM(__pyx_t_3, 1, __pyx_t_2);
+  __Pyx_GIVEREF(__pyx_t_2);
+  __pyx_t_1 = 0;
+  __pyx_t_2 = 0;
+  __pyx_r = ((PyObject *)__pyx_t_3);
   __pyx_t_3 = 0;
   goto __pyx_L0;
 
@@ -10156,7 +10142,7 @@ static PyObject *__pyx_pf_5_cdec_9Candidate_5words___get__(struct __pyx_obj_5_cd
   __Pyx_XDECREF(__pyx_t_1);
   __Pyx_XDECREF(__pyx_t_2);
   __Pyx_XDECREF(__pyx_t_3);
-  __Pyx_AddTraceback("_cdec.Candidate.words.__get__", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __Pyx_AddTraceback("_cdec.HypergraphEdge.span.__get__", __pyx_clineno, __pyx_lineno, __pyx_filename);
   __pyx_r = NULL;
   __pyx_L0:;
   __Pyx_XGIVEREF(__pyx_r);
@@ -10165,26 +10151,26 @@ static PyObject *__pyx_pf_5_cdec_9Candidate_5words___get__(struct __pyx_obj_5_cd
 }
 
 /* Python wrapper */
-static PyObject *__pyx_pw_5_cdec_9Candidate_4fmap_1__get__(PyObject *__pyx_v_self); /*proto*/
-static PyObject *__pyx_pw_5_cdec_9Candidate_4fmap_1__get__(PyObject *__pyx_v_self) {
+static PyObject *__pyx_pw_5_cdec_14HypergraphEdge_14feature_values_1__get__(PyObject *__pyx_v_self); /*proto*/
+static PyObject *__pyx_pw_5_cdec_14HypergraphEdge_14feature_values_1__get__(PyObject *__pyx_v_self) {
   PyObject *__pyx_r = 0;
   __Pyx_RefNannyDeclarations
   __Pyx_RefNannySetupContext("__get__ (wrapper)", 0);
-  __pyx_r = __pyx_pf_5_cdec_9Candidate_4fmap___get__(((struct __pyx_obj_5_cdec_Candidate *)__pyx_v_self));
+  __pyx_r = __pyx_pf_5_cdec_14HypergraphEdge_14feature_values___get__(((struct __pyx_obj_5_cdec_HypergraphEdge *)__pyx_v_self));
   __Pyx_RefNannyFinishContext();
   return __pyx_r;
 }
 
-/* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":21
+/* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":177
  * 
- *     property fmap:
+ *     property feature_values:
  *         def __get__(self):             # <<<<<<<<<<<<<<
- *             cdef SparseVector fmap = SparseVector()
- *             fmap.vector = new FastSparseVector[weight_t](self.candidate.fmap)
+ *             cdef SparseVector vector = SparseVector()
+ *             vector.vector = new FastSparseVector[double](self.edge.feature_values_)
  */
 
-static PyObject *__pyx_pf_5_cdec_9Candidate_4fmap___get__(struct __pyx_obj_5_cdec_Candidate *__pyx_v_self) {
-  struct __pyx_obj_5_cdec_SparseVector *__pyx_v_fmap = 0;
+static PyObject *__pyx_pf_5_cdec_14HypergraphEdge_14feature_values___get__(struct __pyx_obj_5_cdec_HypergraphEdge *__pyx_v_self) {
+  struct __pyx_obj_5_cdec_SparseVector *__pyx_v_vector = 0;
   PyObject *__pyx_r = NULL;
   __Pyx_RefNannyDeclarations
   PyObject *__pyx_t_1 = NULL;
@@ -10193,72 +10179,72 @@ static PyObject *__pyx_pf_5_cdec_9Candidate_4fmap___get__(struct __pyx_obj_5_cde
   int __pyx_clineno = 0;
   __Pyx_RefNannySetupContext("__get__", 0);
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":22
- *     property fmap:
+  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":178
+ *     property feature_values:
  *         def __get__(self):
- *             cdef SparseVector fmap = SparseVector()             # <<<<<<<<<<<<<<
- *             fmap.vector = new FastSparseVector[weight_t](self.candidate.fmap)
- *             return fmap
+ *             cdef SparseVector vector = SparseVector()             # <<<<<<<<<<<<<<
+ *             vector.vector = new FastSparseVector[double](self.edge.feature_values_)
+ *             return vector
  */
-  __pyx_t_1 = PyObject_Call(((PyObject *)((PyObject*)__pyx_ptype_5_cdec_SparseVector)), ((PyObject *)__pyx_empty_tuple), NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 22; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_1 = PyObject_Call(((PyObject *)((PyObject*)__pyx_ptype_5_cdec_SparseVector)), ((PyObject *)__pyx_empty_tuple), NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 178; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __Pyx_GOTREF(__pyx_t_1);
-  __pyx_v_fmap = ((struct __pyx_obj_5_cdec_SparseVector *)__pyx_t_1);
+  __pyx_v_vector = ((struct __pyx_obj_5_cdec_SparseVector *)__pyx_t_1);
   __pyx_t_1 = 0;
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":23
+  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":179
  *         def __get__(self):
- *             cdef SparseVector fmap = SparseVector()
- *             fmap.vector = new FastSparseVector[weight_t](self.candidate.fmap)             # <<<<<<<<<<<<<<
- *             return fmap
+ *             cdef SparseVector vector = SparseVector()
+ *             vector.vector = new FastSparseVector[double](self.edge.feature_values_)             # <<<<<<<<<<<<<<
+ *             return vector
  * 
  */
-  __pyx_v_fmap->vector = new FastSparseVector<weight_t>(__pyx_v_self->candidate->fmap);
+  __pyx_v_vector->vector = new FastSparseVector<double>(__pyx_v_self->edge->feature_values_);
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":24
- *             cdef SparseVector fmap = SparseVector()
- *             fmap.vector = new FastSparseVector[weight_t](self.candidate.fmap)
- *             return fmap             # <<<<<<<<<<<<<<
+  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":180
+ *             cdef SparseVector vector = SparseVector()
+ *             vector.vector = new FastSparseVector[double](self.edge.feature_values_)
+ *             return vector             # <<<<<<<<<<<<<<
  * 
- * cdef class SufficientStats:
+ *     property prob:
  */
   __Pyx_XDECREF(__pyx_r);
-  __Pyx_INCREF(((PyObject *)__pyx_v_fmap));
-  __pyx_r = ((PyObject *)__pyx_v_fmap);
+  __Pyx_INCREF(((PyObject *)__pyx_v_vector));
+  __pyx_r = ((PyObject *)__pyx_v_vector);
   goto __pyx_L0;
 
   __pyx_r = Py_None; __Pyx_INCREF(Py_None);
   goto __pyx_L0;
   __pyx_L1_error:;
   __Pyx_XDECREF(__pyx_t_1);
-  __Pyx_AddTraceback("_cdec.Candidate.fmap.__get__", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __Pyx_AddTraceback("_cdec.HypergraphEdge.feature_values.__get__", __pyx_clineno, __pyx_lineno, __pyx_filename);
   __pyx_r = NULL;
   __pyx_L0:;
-  __Pyx_XDECREF((PyObject *)__pyx_v_fmap);
+  __Pyx_XDECREF((PyObject *)__pyx_v_vector);
   __Pyx_XGIVEREF(__pyx_r);
   __Pyx_RefNannyFinishContext();
   return __pyx_r;
 }
 
 /* Python wrapper */
-static PyObject *__pyx_pw_5_cdec_9Candidate_5score_1__get__(PyObject *__pyx_v_self); /*proto*/
-static PyObject *__pyx_pw_5_cdec_9Candidate_5score_1__get__(PyObject *__pyx_v_self) {
+static PyObject *__pyx_pw_5_cdec_14HypergraphEdge_4prob_1__get__(PyObject *__pyx_v_self); /*proto*/
+static PyObject *__pyx_pw_5_cdec_14HypergraphEdge_4prob_1__get__(PyObject *__pyx_v_self) {
   PyObject *__pyx_r = 0;
   __Pyx_RefNannyDeclarations
   __Pyx_RefNannySetupContext("__get__ (wrapper)", 0);
-  __pyx_r = __pyx_pf_5_cdec_9Candidate_5score___get__(((struct __pyx_obj_5_cdec_Candidate *)__pyx_v_self));
+  __pyx_r = __pyx_pf_5_cdec_14HypergraphEdge_4prob___get__(((struct __pyx_obj_5_cdec_HypergraphEdge *)__pyx_v_self));
   __Pyx_RefNannyFinishContext();
   return __pyx_r;
 }
 
-/* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":14
- * cdef class Candidate:
- *     cdef mteval.Candidate* candidate
- *     cdef public float score             # <<<<<<<<<<<<<<
+/* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":183
+ * 
+ *     property prob:
+ *         def __get__(self):             # <<<<<<<<<<<<<<
+ *             return self.edge.edge_prob_.as_float()
  * 
- *     property words:
  */
 
-static PyObject *__pyx_pf_5_cdec_9Candidate_5score___get__(struct __pyx_obj_5_cdec_Candidate *__pyx_v_self) {
+static PyObject *__pyx_pf_5_cdec_14HypergraphEdge_4prob___get__(struct __pyx_obj_5_cdec_HypergraphEdge *__pyx_v_self) {
   PyObject *__pyx_r = NULL;
   __Pyx_RefNannyDeclarations
   PyObject *__pyx_t_1 = NULL;
@@ -10266,8 +10252,16 @@ static PyObject *__pyx_pf_5_cdec_9Candidate_5score___get__(struct __pyx_obj_5_cd
   const char *__pyx_filename = NULL;
   int __pyx_clineno = 0;
   __Pyx_RefNannySetupContext("__get__", 0);
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":184
+ *     property prob:
+ *         def __get__(self):
+ *             return self.edge.edge_prob_.as_float()             # <<<<<<<<<<<<<<
+ * 
+ *     def __richcmp__(HypergraphEdge x, HypergraphEdge y, int op):
+ */
   __Pyx_XDECREF(__pyx_r);
-  __pyx_t_1 = PyFloat_FromDouble(__pyx_v_self->score); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 14; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_1 = PyFloat_FromDouble(__pyx_v_self->edge->edge_prob_.as_float()); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 184; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __Pyx_GOTREF(__pyx_t_1);
   __pyx_r = __pyx_t_1;
   __pyx_t_1 = 0;
@@ -10277,7 +10271,7 @@ static PyObject *__pyx_pf_5_cdec_9Candidate_5score___get__(struct __pyx_obj_5_cd
   goto __pyx_L0;
   __pyx_L1_error:;
   __Pyx_XDECREF(__pyx_t_1);
-  __Pyx_AddTraceback("_cdec.Candidate.score.__get__", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __Pyx_AddTraceback("_cdec.HypergraphEdge.prob.__get__", __pyx_clineno, __pyx_lineno, __pyx_filename);
   __pyx_r = NULL;
   __pyx_L0:;
   __Pyx_XGIVEREF(__pyx_r);
@@ -10286,117 +10280,120 @@ static PyObject *__pyx_pf_5_cdec_9Candidate_5score___get__(struct __pyx_obj_5_cd
 }
 
 /* Python wrapper */
-static int __pyx_pw_5_cdec_9Candidate_5score_3__set__(PyObject *__pyx_v_self, PyObject *__pyx_v_value); /*proto*/
-static int __pyx_pw_5_cdec_9Candidate_5score_3__set__(PyObject *__pyx_v_self, PyObject *__pyx_v_value) {
-  int __pyx_r;
-  __Pyx_RefNannyDeclarations
-  __Pyx_RefNannySetupContext("__set__ (wrapper)", 0);
-  __pyx_r = __pyx_pf_5_cdec_9Candidate_5score_2__set__(((struct __pyx_obj_5_cdec_Candidate *)__pyx_v_self), ((PyObject *)__pyx_v_value));
-  __Pyx_RefNannyFinishContext();
-  return __pyx_r;
-}
-
-static int __pyx_pf_5_cdec_9Candidate_5score_2__set__(struct __pyx_obj_5_cdec_Candidate *__pyx_v_self, PyObject *__pyx_v_value) {
-  int __pyx_r;
+static PyObject *__pyx_pw_5_cdec_14HypergraphEdge_3__richcmp__(PyObject *__pyx_v_x, PyObject *__pyx_v_y, int __pyx_v_op); /*proto*/
+static PyObject *__pyx_pw_5_cdec_14HypergraphEdge_3__richcmp__(PyObject *__pyx_v_x, PyObject *__pyx_v_y, int __pyx_v_op) {
+  PyObject *__pyx_r = 0;
   __Pyx_RefNannyDeclarations
-  float __pyx_t_1;
-  int __pyx_lineno = 0;
-  const char *__pyx_filename = NULL;
-  int __pyx_clineno = 0;
-  __Pyx_RefNannySetupContext("__set__", 0);
-  __pyx_t_1 = __pyx_PyFloat_AsFloat(__pyx_v_value); if (unlikely((__pyx_t_1 == (float)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 14; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __pyx_v_self->score = __pyx_t_1;
-
-  __pyx_r = 0;
+  __Pyx_RefNannySetupContext("__richcmp__ (wrapper)", 0);
+  if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_x), __pyx_ptype_5_cdec_HypergraphEdge, 1, "x", 0))) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 186; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_y), __pyx_ptype_5_cdec_HypergraphEdge, 1, "y", 0))) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 186; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_r = __pyx_pf_5_cdec_14HypergraphEdge_2__richcmp__(((struct __pyx_obj_5_cdec_HypergraphEdge *)__pyx_v_x), ((struct __pyx_obj_5_cdec_HypergraphEdge *)__pyx_v_y), ((int)__pyx_v_op));
   goto __pyx_L0;
   __pyx_L1_error:;
-  __Pyx_AddTraceback("_cdec.Candidate.score.__set__", __pyx_clineno, __pyx_lineno, __pyx_filename);
-  __pyx_r = -1;
+  __pyx_r = NULL;
   __pyx_L0:;
   __Pyx_RefNannyFinishContext();
   return __pyx_r;
 }
 
-/* Python wrapper */
-static void __pyx_pw_5_cdec_15SufficientStats_1__dealloc__(PyObject *__pyx_v_self); /*proto*/
-static void __pyx_pw_5_cdec_15SufficientStats_1__dealloc__(PyObject *__pyx_v_self) {
-  __Pyx_RefNannyDeclarations
-  __Pyx_RefNannySetupContext("__dealloc__ (wrapper)", 0);
-  __pyx_pf_5_cdec_15SufficientStats___dealloc__(((struct __pyx_obj_5_cdec_SufficientStats *)__pyx_v_self));
-  __Pyx_RefNannyFinishContext();
-}
-
-/* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":30
- *     cdef mteval.EvaluationMetric* metric
- * 
- *     def __dealloc__(self):             # <<<<<<<<<<<<<<
- *         del self.stats
+/* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":186
+ *             return self.edge.edge_prob_.as_float()
  * 
+ *     def __richcmp__(HypergraphEdge x, HypergraphEdge y, int op):             # <<<<<<<<<<<<<<
+ *         if op == 2: # ==
+ *             return x.edge == y.edge
  */
 
-static void __pyx_pf_5_cdec_15SufficientStats___dealloc__(CYTHON_UNUSED struct __pyx_obj_5_cdec_SufficientStats *__pyx_v_self) {
+static PyObject *__pyx_pf_5_cdec_14HypergraphEdge_2__richcmp__(struct __pyx_obj_5_cdec_HypergraphEdge *__pyx_v_x, struct __pyx_obj_5_cdec_HypergraphEdge *__pyx_v_y, int __pyx_v_op) {
+  PyObject *__pyx_r = NULL;
   __Pyx_RefNannyDeclarations
-  __Pyx_RefNannySetupContext("__dealloc__", 0);
+  PyObject *__pyx_t_1 = NULL;
+  int __pyx_t_2;
+  int __pyx_lineno = 0;
+  const char *__pyx_filename = NULL;
+  int __pyx_clineno = 0;
+  __Pyx_RefNannySetupContext("__richcmp__", 0);
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":31
- * 
- *     def __dealloc__(self):
- *         del self.stats             # <<<<<<<<<<<<<<
+  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":189
+ *         if op == 2: # ==
+ *             return x.edge == y.edge
+ *         elif op == 3: # !=             # <<<<<<<<<<<<<<
+ *             return not (x == y)
+ *         raise NotImplemented('comparison not implemented for HypergraphEdge')
+ */
+  switch (__pyx_v_op) {
+
+    /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":187
  * 
- *     property score:
+ *     def __richcmp__(HypergraphEdge x, HypergraphEdge y, int op):
+ *         if op == 2: # ==             # <<<<<<<<<<<<<<
+ *             return x.edge == y.edge
+ *         elif op == 3: # !=
  */
-  delete __pyx_v_self->stats;
+    case 2:
 
-  __Pyx_RefNannyFinishContext();
-}
+    /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":188
+ *     def __richcmp__(HypergraphEdge x, HypergraphEdge y, int op):
+ *         if op == 2: # ==
+ *             return x.edge == y.edge             # <<<<<<<<<<<<<<
+ *         elif op == 3: # !=
+ *             return not (x == y)
+ */
+    __Pyx_XDECREF(__pyx_r);
+    __pyx_t_1 = __Pyx_PyBool_FromLong((__pyx_v_x->edge == __pyx_v_y->edge)); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 188; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_1);
+    __pyx_r = __pyx_t_1;
+    __pyx_t_1 = 0;
+    goto __pyx_L0;
+    break;
 
-/* Python wrapper */
-static PyObject *__pyx_pw_5_cdec_15SufficientStats_5score_1__get__(PyObject *__pyx_v_self); /*proto*/
-static PyObject *__pyx_pw_5_cdec_15SufficientStats_5score_1__get__(PyObject *__pyx_v_self) {
-  PyObject *__pyx_r = 0;
-  __Pyx_RefNannyDeclarations
-  __Pyx_RefNannySetupContext("__get__ (wrapper)", 0);
-  __pyx_r = __pyx_pf_5_cdec_15SufficientStats_5score___get__(((struct __pyx_obj_5_cdec_SufficientStats *)__pyx_v_self));
-  __Pyx_RefNannyFinishContext();
-  return __pyx_r;
-}
+    /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":189
+ *         if op == 2: # ==
+ *             return x.edge == y.edge
+ *         elif op == 3: # !=             # <<<<<<<<<<<<<<
+ *             return not (x == y)
+ *         raise NotImplemented('comparison not implemented for HypergraphEdge')
+ */
+    case 3:
 
-/* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":34
- * 
- *     property score:
- *         def __get__(self):             # <<<<<<<<<<<<<<
- *             return self.metric.ComputeScore(self.stats[0])
+    /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":190
+ *             return x.edge == y.edge
+ *         elif op == 3: # !=
+ *             return not (x == y)             # <<<<<<<<<<<<<<
+ *         raise NotImplemented('comparison not implemented for HypergraphEdge')
  * 
  */
+    __Pyx_XDECREF(__pyx_r);
+    __pyx_t_1 = PyObject_RichCompare(((PyObject *)__pyx_v_x), ((PyObject *)__pyx_v_y), Py_EQ); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 190; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_1);
+    __pyx_t_2 = __Pyx_PyObject_IsTrue(__pyx_t_1); if (unlikely(__pyx_t_2 < 0)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 190; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+    __pyx_t_1 = __Pyx_PyBool_FromLong((!__pyx_t_2)); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 190; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_1);
+    __pyx_r = __pyx_t_1;
+    __pyx_t_1 = 0;
+    goto __pyx_L0;
+    break;
+  }
 
-static PyObject *__pyx_pf_5_cdec_15SufficientStats_5score___get__(struct __pyx_obj_5_cdec_SufficientStats *__pyx_v_self) {
-  PyObject *__pyx_r = NULL;
-  __Pyx_RefNannyDeclarations
-  PyObject *__pyx_t_1 = NULL;
-  int __pyx_lineno = 0;
-  const char *__pyx_filename = NULL;
-  int __pyx_clineno = 0;
-  __Pyx_RefNannySetupContext("__get__", 0);
-
-  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":35
- *     property score:
- *         def __get__(self):
- *             return self.metric.ComputeScore(self.stats[0])             # <<<<<<<<<<<<<<
+  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":191
+ *         elif op == 3: # !=
+ *             return not (x == y)
+ *         raise NotImplemented('comparison not implemented for HypergraphEdge')             # <<<<<<<<<<<<<<
  * 
- *     property detail:
+ * cdef class HypergraphNode:
  */
-  __Pyx_XDECREF(__pyx_r);
-  __pyx_t_1 = PyFloat_FromDouble(__pyx_v_self->metric->ComputeScore((__pyx_v_self->stats[0]))); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 35; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_1 = PyObject_Call(__pyx_builtin_NotImplemented, ((PyObject *)__pyx_k_tuple_18), NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 191; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __Pyx_GOTREF(__pyx_t_1);
-  __pyx_r = __pyx_t_1;
-  __pyx_t_1 = 0;
-  goto __pyx_L0;
+  __Pyx_Raise(__pyx_t_1, 0, 0, 0);
+  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+  {__pyx_filename = __pyx_f[3]; __pyx_lineno = 191; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
 
   __pyx_r = Py_None; __Pyx_INCREF(Py_None);
   goto __pyx_L0;
   __pyx_L1_error:;
   __Pyx_XDECREF(__pyx_t_1);
-  __Pyx_AddTraceback("_cdec.SufficientStats.score.__get__", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __Pyx_AddTraceback("_cdec.HypergraphEdge.__richcmp__", __pyx_clineno, __pyx_lineno, __pyx_filename);
   __pyx_r = NULL;
   __pyx_L0:;
   __Pyx_XGIVEREF(__pyx_r);
@@ -10405,53 +10402,34 @@ static PyObject *__pyx_pf_5_cdec_15SufficientStats_5score___get__(struct __pyx_o
 }
 
 /* Python wrapper */
-static PyObject *__pyx_pw_5_cdec_15SufficientStats_6detail_1__get__(PyObject *__pyx_v_self); /*proto*/
-static PyObject *__pyx_pw_5_cdec_15SufficientStats_6detail_1__get__(PyObject *__pyx_v_self) {
+static PyObject *__pyx_pw_5_cdec_14HypergraphEdge_5trule_1__get__(PyObject *__pyx_v_self); /*proto*/
+static PyObject *__pyx_pw_5_cdec_14HypergraphEdge_5trule_1__get__(PyObject *__pyx_v_self) {
   PyObject *__pyx_r = 0;
   __Pyx_RefNannyDeclarations
   __Pyx_RefNannySetupContext("__get__ (wrapper)", 0);
-  __pyx_r = __pyx_pf_5_cdec_15SufficientStats_6detail___get__(((struct __pyx_obj_5_cdec_SufficientStats *)__pyx_v_self));
+  __pyx_r = __pyx_pf_5_cdec_14HypergraphEdge_5trule___get__(((struct __pyx_obj_5_cdec_HypergraphEdge *)__pyx_v_self));
   __Pyx_RefNannyFinishContext();
   return __pyx_r;
 }
 
-/* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":38
- * 
- *     property detail:
- *         def __get__(self):             # <<<<<<<<<<<<<<
- *             return self.metric.DetailedScore(self.stats[0]).c_str()
+/* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":150
+ *     cdef hypergraph.Hypergraph* hg
+ *     cdef hypergraph.HypergraphEdge* edge
+ *     cdef public BaseTRule trule             # <<<<<<<<<<<<<<
  * 
+ *     cdef init(self, hypergraph.Hypergraph* hg, unsigned i):
  */
 
-static PyObject *__pyx_pf_5_cdec_15SufficientStats_6detail___get__(struct __pyx_obj_5_cdec_SufficientStats *__pyx_v_self) {
+static PyObject *__pyx_pf_5_cdec_14HypergraphEdge_5trule___get__(struct __pyx_obj_5_cdec_HypergraphEdge *__pyx_v_self) {
   PyObject *__pyx_r = NULL;
   __Pyx_RefNannyDeclarations
-  PyObject *__pyx_t_1 = NULL;
-  int __pyx_lineno = 0;
-  const char *__pyx_filename = NULL;
-  int __pyx_clineno = 0;
   __Pyx_RefNannySetupContext("__get__", 0);
-
-  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":39
- *     property detail:
- *         def __get__(self):
- *             return self.metric.DetailedScore(self.stats[0]).c_str()             # <<<<<<<<<<<<<<
- * 
- *     def __len__(self):
- */
   __Pyx_XDECREF(__pyx_r);
-  __pyx_t_1 = PyBytes_FromString(__pyx_v_self->metric->DetailedScore((__pyx_v_self->stats[0])).c_str()); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 39; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __Pyx_GOTREF(((PyObject *)__pyx_t_1));
-  __pyx_r = ((PyObject *)__pyx_t_1);
-  __pyx_t_1 = 0;
+  __Pyx_INCREF(((PyObject *)__pyx_v_self->trule));
+  __pyx_r = ((PyObject *)__pyx_v_self->trule);
   goto __pyx_L0;
 
   __pyx_r = Py_None; __Pyx_INCREF(Py_None);
-  goto __pyx_L0;
-  __pyx_L1_error:;
-  __Pyx_XDECREF(__pyx_t_1);
-  __Pyx_AddTraceback("_cdec.SufficientStats.detail.__get__", __pyx_clineno, __pyx_lineno, __pyx_filename);
-  __pyx_r = NULL;
   __pyx_L0:;
   __Pyx_XGIVEREF(__pyx_r);
   __Pyx_RefNannyFinishContext();
@@ -10459,74 +10437,145 @@ static PyObject *__pyx_pf_5_cdec_15SufficientStats_6detail___get__(struct __pyx_
 }
 
 /* Python wrapper */
-static Py_ssize_t __pyx_pw_5_cdec_15SufficientStats_3__len__(PyObject *__pyx_v_self); /*proto*/
-static Py_ssize_t __pyx_pw_5_cdec_15SufficientStats_3__len__(PyObject *__pyx_v_self) {
-  Py_ssize_t __pyx_r;
+static int __pyx_pw_5_cdec_14HypergraphEdge_5trule_3__set__(PyObject *__pyx_v_self, PyObject *__pyx_v_value); /*proto*/
+static int __pyx_pw_5_cdec_14HypergraphEdge_5trule_3__set__(PyObject *__pyx_v_self, PyObject *__pyx_v_value) {
+  int __pyx_r;
   __Pyx_RefNannyDeclarations
-  __Pyx_RefNannySetupContext("__len__ (wrapper)", 0);
-  __pyx_r = __pyx_pf_5_cdec_15SufficientStats_2__len__(((struct __pyx_obj_5_cdec_SufficientStats *)__pyx_v_self));
+  __Pyx_RefNannySetupContext("__set__ (wrapper)", 0);
+  __pyx_r = __pyx_pf_5_cdec_14HypergraphEdge_5trule_2__set__(((struct __pyx_obj_5_cdec_HypergraphEdge *)__pyx_v_self), ((PyObject *)__pyx_v_value));
   __Pyx_RefNannyFinishContext();
   return __pyx_r;
 }
 
-/* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":41
- *             return self.metric.DetailedScore(self.stats[0]).c_str()
- * 
- *     def __len__(self):             # <<<<<<<<<<<<<<
- *         return self.stats.size()
+static int __pyx_pf_5_cdec_14HypergraphEdge_5trule_2__set__(struct __pyx_obj_5_cdec_HypergraphEdge *__pyx_v_self, PyObject *__pyx_v_value) {
+  int __pyx_r;
+  __Pyx_RefNannyDeclarations
+  int __pyx_lineno = 0;
+  const char *__pyx_filename = NULL;
+  int __pyx_clineno = 0;
+  __Pyx_RefNannySetupContext("__set__", 0);
+  if (!(likely(((__pyx_v_value) == Py_None) || likely(__Pyx_TypeTest(__pyx_v_value, __pyx_ptype_5_cdec_BaseTRule))))) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 150; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_INCREF(__pyx_v_value);
+  __Pyx_GIVEREF(__pyx_v_value);
+  __Pyx_GOTREF(__pyx_v_self->trule);
+  __Pyx_DECREF(((PyObject *)__pyx_v_self->trule));
+  __pyx_v_self->trule = ((struct __pyx_obj_5_cdec_BaseTRule *)__pyx_v_value);
+
+  __pyx_r = 0;
+  goto __pyx_L0;
+  __pyx_L1_error:;
+  __Pyx_AddTraceback("_cdec.HypergraphEdge.trule.__set__", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __pyx_r = -1;
+  __pyx_L0:;
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+/* Python wrapper */
+static int __pyx_pw_5_cdec_14HypergraphEdge_5trule_5__del__(PyObject *__pyx_v_self); /*proto*/
+static int __pyx_pw_5_cdec_14HypergraphEdge_5trule_5__del__(PyObject *__pyx_v_self) {
+  int __pyx_r;
+  __Pyx_RefNannyDeclarations
+  __Pyx_RefNannySetupContext("__del__ (wrapper)", 0);
+  __pyx_r = __pyx_pf_5_cdec_14HypergraphEdge_5trule_4__del__(((struct __pyx_obj_5_cdec_HypergraphEdge *)__pyx_v_self));
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+static int __pyx_pf_5_cdec_14HypergraphEdge_5trule_4__del__(struct __pyx_obj_5_cdec_HypergraphEdge *__pyx_v_self) {
+  int __pyx_r;
+  __Pyx_RefNannyDeclarations
+  __Pyx_RefNannySetupContext("__del__", 0);
+  __Pyx_INCREF(Py_None);
+  __Pyx_GIVEREF(Py_None);
+  __Pyx_GOTREF(__pyx_v_self->trule);
+  __Pyx_DECREF(((PyObject *)__pyx_v_self->trule));
+  __pyx_v_self->trule = ((struct __pyx_obj_5_cdec_BaseTRule *)Py_None);
+
+  __pyx_r = 0;
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+/* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":197
+ *     cdef hypergraph.HypergraphNode* node
  * 
+ *     cdef init(self, hypergraph.Hypergraph* hg, unsigned i):             # <<<<<<<<<<<<<<
+ *         self.hg = hg
+ *         self.node = &hg.nodes_[i]
  */
 
-static Py_ssize_t __pyx_pf_5_cdec_15SufficientStats_2__len__(struct __pyx_obj_5_cdec_SufficientStats *__pyx_v_self) {
-  Py_ssize_t __pyx_r;
+static PyObject *__pyx_f_5_cdec_14HypergraphNode_init(struct __pyx_obj_5_cdec_HypergraphNode *__pyx_v_self, Hypergraph *__pyx_v_hg, unsigned int __pyx_v_i) {
+  PyObject *__pyx_r = NULL;
   __Pyx_RefNannyDeclarations
-  __Pyx_RefNannySetupContext("__len__", 0);
+  __Pyx_RefNannySetupContext("init", 0);
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":42
+  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":198
  * 
- *     def __len__(self):
- *         return self.stats.size()             # <<<<<<<<<<<<<<
+ *     cdef init(self, hypergraph.Hypergraph* hg, unsigned i):
+ *         self.hg = hg             # <<<<<<<<<<<<<<
+ *         self.node = &hg.nodes_[i]
+ *         return self
+ */
+  __pyx_v_self->hg = __pyx_v_hg;
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":199
+ *     cdef init(self, hypergraph.Hypergraph* hg, unsigned i):
+ *         self.hg = hg
+ *         self.node = &hg.nodes_[i]             # <<<<<<<<<<<<<<
+ *         return self
  * 
- *     def __iter__(self):
  */
-  __pyx_r = __pyx_v_self->stats->size();
+  __pyx_v_self->node = (&(__pyx_v_hg->nodes_[__pyx_v_i]));
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":200
+ *         self.hg = hg
+ *         self.node = &hg.nodes_[i]
+ *         return self             # <<<<<<<<<<<<<<
+ * 
+ *     property in_edges:
+ */
+  __Pyx_XDECREF(__pyx_r);
+  __Pyx_INCREF(((PyObject *)__pyx_v_self));
+  __pyx_r = ((PyObject *)__pyx_v_self);
   goto __pyx_L0;
 
-  __pyx_r = 0;
+  __pyx_r = Py_None; __Pyx_INCREF(Py_None);
   __pyx_L0:;
+  __Pyx_XGIVEREF(__pyx_r);
   __Pyx_RefNannyFinishContext();
   return __pyx_r;
 }
-static PyObject *__pyx_gb_5_cdec_15SufficientStats_6generator12(__pyx_GeneratorObject *__pyx_generator, PyObject *__pyx_sent_value); /* proto */
+static PyObject *__pyx_gb_5_cdec_14HypergraphNode_8in_edges_2generator11(__pyx_GeneratorObject *__pyx_generator, PyObject *__pyx_sent_value); /* proto */
 
 /* Python wrapper */
-static PyObject *__pyx_pw_5_cdec_15SufficientStats_5__iter__(PyObject *__pyx_v_self); /*proto*/
-static PyObject *__pyx_pw_5_cdec_15SufficientStats_5__iter__(PyObject *__pyx_v_self) {
+static PyObject *__pyx_pw_5_cdec_14HypergraphNode_8in_edges_1__get__(PyObject *__pyx_v_self); /*proto*/
+static PyObject *__pyx_pw_5_cdec_14HypergraphNode_8in_edges_1__get__(PyObject *__pyx_v_self) {
   PyObject *__pyx_r = 0;
   __Pyx_RefNannyDeclarations
-  __Pyx_RefNannySetupContext("__iter__ (wrapper)", 0);
-  __pyx_r = __pyx_pf_5_cdec_15SufficientStats_4__iter__(((struct __pyx_obj_5_cdec_SufficientStats *)__pyx_v_self));
+  __Pyx_RefNannySetupContext("__get__ (wrapper)", 0);
+  __pyx_r = __pyx_pf_5_cdec_14HypergraphNode_8in_edges___get__(((struct __pyx_obj_5_cdec_HypergraphNode *)__pyx_v_self));
   __Pyx_RefNannyFinishContext();
   return __pyx_r;
 }
 
-/* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":44
- *         return self.stats.size()
+/* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":203
  * 
- *     def __iter__(self):             # <<<<<<<<<<<<<<
- *         for i in range(len(self)):
- *             yield self.stats[0][i]
+ *     property in_edges:
+ *         def __get__(self):             # <<<<<<<<<<<<<<
+ *             cdef unsigned i
+ *             for i in range(self.node.in_edges_.size()):
  */
 
-static PyObject *__pyx_pf_5_cdec_15SufficientStats_4__iter__(struct __pyx_obj_5_cdec_SufficientStats *__pyx_v_self) {
-  struct __pyx_obj_5_cdec___pyx_scope_struct_18___iter__ *__pyx_cur_scope;
+static PyObject *__pyx_pf_5_cdec_14HypergraphNode_8in_edges___get__(struct __pyx_obj_5_cdec_HypergraphNode *__pyx_v_self) {
+  struct __pyx_obj_5_cdec___pyx_scope_struct_15___get__ *__pyx_cur_scope;
   PyObject *__pyx_r = NULL;
   __Pyx_RefNannyDeclarations
   int __pyx_lineno = 0;
   const char *__pyx_filename = NULL;
   int __pyx_clineno = 0;
-  __Pyx_RefNannySetupContext("__iter__", 0);
-  __pyx_cur_scope = (struct __pyx_obj_5_cdec___pyx_scope_struct_18___iter__ *)__pyx_ptype_5_cdec___pyx_scope_struct_18___iter__->tp_new(__pyx_ptype_5_cdec___pyx_scope_struct_18___iter__, __pyx_empty_tuple, NULL);
+  __Pyx_RefNannySetupContext("__get__", 0);
+  __pyx_cur_scope = (struct __pyx_obj_5_cdec___pyx_scope_struct_15___get__ *)__pyx_ptype_5_cdec___pyx_scope_struct_15___get__->tp_new(__pyx_ptype_5_cdec___pyx_scope_struct_15___get__, __pyx_empty_tuple, NULL);
   if (unlikely(!__pyx_cur_scope)) {
     __Pyx_RefNannyFinishContext();
     return NULL;
@@ -10536,7 +10585,7 @@ static PyObject *__pyx_pf_5_cdec_15SufficientStats_4__iter__(struct __pyx_obj_5_
   __Pyx_INCREF((PyObject *)__pyx_cur_scope->__pyx_v_self);
   __Pyx_GIVEREF((PyObject *)__pyx_cur_scope->__pyx_v_self);
   {
-    __pyx_GeneratorObject *gen = __Pyx_Generator_New((__pyx_generator_body_t) __pyx_gb_5_cdec_15SufficientStats_6generator12, (PyObject *) __pyx_cur_scope); if (unlikely(!gen)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 44; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_GeneratorObject *gen = __Pyx_Generator_New((__pyx_generator_body_t) __pyx_gb_5_cdec_14HypergraphNode_8in_edges_2generator11, (PyObject *) __pyx_cur_scope); if (unlikely(!gen)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 203; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
     __Pyx_DECREF(__pyx_cur_scope);
     __Pyx_RefNannyFinishContext();
     return (PyObject *) gen;
@@ -10545,7 +10594,7 @@ static PyObject *__pyx_pf_5_cdec_15SufficientStats_4__iter__(struct __pyx_obj_5_
   __pyx_r = Py_None; __Pyx_INCREF(Py_None);
   goto __pyx_L0;
   __pyx_L1_error:;
-  __Pyx_AddTraceback("_cdec.SufficientStats.__iter__", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __Pyx_AddTraceback("_cdec.HypergraphNode.in_edges.__get__", __pyx_clineno, __pyx_lineno, __pyx_filename);
   __pyx_r = NULL;
   __pyx_L0:;
   __Pyx_DECREF(((PyObject *)__pyx_cur_scope));
@@ -10554,15 +10603,14 @@ static PyObject *__pyx_pf_5_cdec_15SufficientStats_4__iter__(struct __pyx_obj_5_
   return __pyx_r;
 }
 
-static PyObject *__pyx_gb_5_cdec_15SufficientStats_6generator12(__pyx_GeneratorObject *__pyx_generator, PyObject *__pyx_sent_value) /* generator body */
+static PyObject *__pyx_gb_5_cdec_14HypergraphNode_8in_edges_2generator11(__pyx_GeneratorObject *__pyx_generator, PyObject *__pyx_sent_value) /* generator body */
 {
-  struct __pyx_obj_5_cdec___pyx_scope_struct_18___iter__ *__pyx_cur_scope = ((struct __pyx_obj_5_cdec___pyx_scope_struct_18___iter__ *)__pyx_generator->closure);
+  struct __pyx_obj_5_cdec___pyx_scope_struct_15___get__ *__pyx_cur_scope = ((struct __pyx_obj_5_cdec___pyx_scope_struct_15___get__ *)__pyx_generator->closure);
   PyObject *__pyx_r = NULL;
-  Py_ssize_t __pyx_t_1;
-  PyObject *__pyx_t_2 = NULL;
+  size_t __pyx_t_1;
+  unsigned int __pyx_t_2;
   PyObject *__pyx_t_3 = NULL;
-  PyObject *(*__pyx_t_4)(PyObject *);
-  unsigned int __pyx_t_5;
+  PyObject *__pyx_t_4 = NULL;
   __Pyx_RefNannyDeclarations
   __Pyx_RefNannySetupContext("None", 0);
   switch (__pyx_generator->resume_label) {
@@ -10573,75 +10621,35 @@ static PyObject *__pyx_gb_5_cdec_15SufficientStats_6generator12(__pyx_GeneratorO
     return NULL;
   }
   __pyx_L3_first_run:;
-  if (unlikely(!__pyx_sent_value)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 44; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (unlikely(!__pyx_sent_value)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 203; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":45
- * 
- *     def __iter__(self):
- *         for i in range(len(self)):             # <<<<<<<<<<<<<<
- *             yield self.stats[0][i]
+  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":205
+ *         def __get__(self):
+ *             cdef unsigned i
+ *             for i in range(self.node.in_edges_.size()):             # <<<<<<<<<<<<<<
+ *                 yield HypergraphEdge().init(self.hg, self.node.in_edges_[i])
  * 
  */
-  __pyx_t_1 = PyObject_Length(((PyObject *)__pyx_cur_scope->__pyx_v_self)); if (unlikely(__pyx_t_1 == -1)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 45; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __pyx_t_2 = PyInt_FromSsize_t(__pyx_t_1); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 45; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __Pyx_GOTREF(__pyx_t_2);
-  __pyx_t_3 = PyTuple_New(1); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 45; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __Pyx_GOTREF(__pyx_t_3);
-  PyTuple_SET_ITEM(__pyx_t_3, 0, __pyx_t_2);
-  __Pyx_GIVEREF(__pyx_t_2);
-  __pyx_t_2 = 0;
-  __pyx_t_2 = PyObject_Call(__pyx_builtin_range, ((PyObject *)__pyx_t_3), NULL); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 45; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __Pyx_GOTREF(__pyx_t_2);
-  __Pyx_DECREF(((PyObject *)__pyx_t_3)); __pyx_t_3 = 0;
-  if (PyList_CheckExact(__pyx_t_2) || PyTuple_CheckExact(__pyx_t_2)) {
-    __pyx_t_3 = __pyx_t_2; __Pyx_INCREF(__pyx_t_3); __pyx_t_1 = 0;
-    __pyx_t_4 = NULL;
-  } else {
-    __pyx_t_1 = -1; __pyx_t_3 = PyObject_GetIter(__pyx_t_2); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 45; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-    __Pyx_GOTREF(__pyx_t_3);
-    __pyx_t_4 = Py_TYPE(__pyx_t_3)->tp_iternext;
-  }
-  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
-  for (;;) {
-    if (!__pyx_t_4 && PyList_CheckExact(__pyx_t_3)) {
-      if (__pyx_t_1 >= PyList_GET_SIZE(__pyx_t_3)) break;
-      __pyx_t_2 = PyList_GET_ITEM(__pyx_t_3, __pyx_t_1); __Pyx_INCREF(__pyx_t_2); __pyx_t_1++;
-    } else if (!__pyx_t_4 && PyTuple_CheckExact(__pyx_t_3)) {
-      if (__pyx_t_1 >= PyTuple_GET_SIZE(__pyx_t_3)) break;
-      __pyx_t_2 = PyTuple_GET_ITEM(__pyx_t_3, __pyx_t_1); __Pyx_INCREF(__pyx_t_2); __pyx_t_1++;
-    } else {
-      __pyx_t_2 = __pyx_t_4(__pyx_t_3);
-      if (unlikely(!__pyx_t_2)) {
-        if (PyErr_Occurred()) {
-          if (likely(PyErr_ExceptionMatches(PyExc_StopIteration))) PyErr_Clear();
-          else {__pyx_filename = __pyx_f[5]; __pyx_lineno = 45; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-        }
-        break;
-      }
-      __Pyx_GOTREF(__pyx_t_2);
-    }
-    __Pyx_XGOTREF(__pyx_cur_scope->__pyx_v_i);
-    __Pyx_XDECREF(__pyx_cur_scope->__pyx_v_i);
-    __Pyx_GIVEREF(__pyx_t_2);
+  __pyx_t_1 = __pyx_cur_scope->__pyx_v_self->node->in_edges_.size();
+  for (__pyx_t_2 = 0; __pyx_t_2 < __pyx_t_1; __pyx_t_2+=1) {
     __pyx_cur_scope->__pyx_v_i = __pyx_t_2;
-    __pyx_t_2 = 0;
 
-    /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":46
- *     def __iter__(self):
- *         for i in range(len(self)):
- *             yield self.stats[0][i]             # <<<<<<<<<<<<<<
+    /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":206
+ *             cdef unsigned i
+ *             for i in range(self.node.in_edges_.size()):
+ *                 yield HypergraphEdge().init(self.hg, self.node.in_edges_[i])             # <<<<<<<<<<<<<<
  * 
- *     def __iadd__(SufficientStats self, SufficientStats other):
+ *     property out_edges:
  */
-    __pyx_t_5 = __Pyx_PyInt_AsUnsignedInt(__pyx_cur_scope->__pyx_v_i); if (unlikely((__pyx_t_5 == (unsigned int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 46; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-    __pyx_t_2 = PyFloat_FromDouble(((__pyx_cur_scope->__pyx_v_self->stats[0])[__pyx_t_5])); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 46; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-    __Pyx_GOTREF(__pyx_t_2);
-    __pyx_r = __pyx_t_2;
-    __pyx_t_2 = 0;
+    __pyx_t_3 = PyObject_Call(((PyObject *)((PyObject*)__pyx_ptype_5_cdec_HypergraphEdge)), ((PyObject *)__pyx_empty_tuple), NULL); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 206; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_3);
+    __pyx_t_4 = ((struct __pyx_vtabstruct_5_cdec_HypergraphEdge *)((struct __pyx_obj_5_cdec_HypergraphEdge *)__pyx_t_3)->__pyx_vtab)->init(((struct __pyx_obj_5_cdec_HypergraphEdge *)__pyx_t_3), __pyx_cur_scope->__pyx_v_self->hg, (__pyx_cur_scope->__pyx_v_self->node->in_edges_[__pyx_cur_scope->__pyx_v_i])); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 206; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_4);
+    __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
+    __pyx_r = __pyx_t_4;
+    __pyx_t_4 = 0;
     __pyx_cur_scope->__pyx_t_0 = __pyx_t_1;
-    __Pyx_XGIVEREF(__pyx_t_3);
-    __pyx_cur_scope->__pyx_t_1 = __pyx_t_3;
-    __pyx_cur_scope->__pyx_t_2 = __pyx_t_4;
+    __pyx_cur_scope->__pyx_t_1 = __pyx_t_2;
     __Pyx_XGIVEREF(__pyx_r);
     __Pyx_RefNannyFinishContext();
     /* return from generator, yielding value */
@@ -10649,2385 +10657,2303 @@ static PyObject *__pyx_gb_5_cdec_15SufficientStats_6generator12(__pyx_GeneratorO
     return __pyx_r;
     __pyx_L6_resume_from_yield:;
     __pyx_t_1 = __pyx_cur_scope->__pyx_t_0;
-    __pyx_t_3 = __pyx_cur_scope->__pyx_t_1;
-    __pyx_cur_scope->__pyx_t_1 = 0;
-    __Pyx_XGOTREF(__pyx_t_3);
-    __pyx_t_4 = __pyx_cur_scope->__pyx_t_2;
-    if (unlikely(!__pyx_sent_value)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 46; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_t_2 = __pyx_cur_scope->__pyx_t_1;
+    if (unlikely(!__pyx_sent_value)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 206; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   }
-  __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
   PyErr_SetNone(PyExc_StopIteration);
   goto __pyx_L0;
   __pyx_L1_error:;
-  __Pyx_XDECREF(__pyx_t_2);
   __Pyx_XDECREF(__pyx_t_3);
-  __Pyx_AddTraceback("__iter__", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __Pyx_XDECREF(__pyx_t_4);
+  __Pyx_AddTraceback("__get__", __pyx_clineno, __pyx_lineno, __pyx_filename);
   __pyx_L0:;
   __Pyx_XDECREF(__pyx_r);
   __pyx_generator->resume_label = -1;
   __Pyx_RefNannyFinishContext();
   return NULL;
 }
+static PyObject *__pyx_gb_5_cdec_14HypergraphNode_9out_edges_2generator12(__pyx_GeneratorObject *__pyx_generator, PyObject *__pyx_sent_value); /* proto */
 
 /* Python wrapper */
-static PyObject *__pyx_pw_5_cdec_15SufficientStats_8__iadd__(PyObject *__pyx_v_self, PyObject *__pyx_v_other); /*proto*/
-static PyObject *__pyx_pw_5_cdec_15SufficientStats_8__iadd__(PyObject *__pyx_v_self, PyObject *__pyx_v_other) {
+static PyObject *__pyx_pw_5_cdec_14HypergraphNode_9out_edges_1__get__(PyObject *__pyx_v_self); /*proto*/
+static PyObject *__pyx_pw_5_cdec_14HypergraphNode_9out_edges_1__get__(PyObject *__pyx_v_self) {
   PyObject *__pyx_r = 0;
   __Pyx_RefNannyDeclarations
-  __Pyx_RefNannySetupContext("__iadd__ (wrapper)", 0);
-  if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_other), __pyx_ptype_5_cdec_SufficientStats, 1, "other", 0))) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 48; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __pyx_r = __pyx_pf_5_cdec_15SufficientStats_7__iadd__(((struct __pyx_obj_5_cdec_SufficientStats *)__pyx_v_self), ((struct __pyx_obj_5_cdec_SufficientStats *)__pyx_v_other));
-  goto __pyx_L0;
-  __pyx_L1_error:;
-  __pyx_r = NULL;
-  __pyx_L0:;
+  __Pyx_RefNannySetupContext("__get__ (wrapper)", 0);
+  __pyx_r = __pyx_pf_5_cdec_14HypergraphNode_9out_edges___get__(((struct __pyx_obj_5_cdec_HypergraphNode *)__pyx_v_self));
   __Pyx_RefNannyFinishContext();
   return __pyx_r;
 }
 
-/* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":48
- *             yield self.stats[0][i]
+/* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":209
  * 
- *     def __iadd__(SufficientStats self, SufficientStats other):             # <<<<<<<<<<<<<<
- *         self.stats[0] += other.stats[0]
- *         return self
+ *     property out_edges:
+ *         def __get__(self):             # <<<<<<<<<<<<<<
+ *             cdef unsigned i
+ *             for i in range(self.node.out_edges_.size()):
  */
 
-static PyObject *__pyx_pf_5_cdec_15SufficientStats_7__iadd__(struct __pyx_obj_5_cdec_SufficientStats *__pyx_v_self, struct __pyx_obj_5_cdec_SufficientStats *__pyx_v_other) {
+static PyObject *__pyx_pf_5_cdec_14HypergraphNode_9out_edges___get__(struct __pyx_obj_5_cdec_HypergraphNode *__pyx_v_self) {
+  struct __pyx_obj_5_cdec___pyx_scope_struct_16___get__ *__pyx_cur_scope;
   PyObject *__pyx_r = NULL;
   __Pyx_RefNannyDeclarations
-  __Pyx_RefNannySetupContext("__iadd__", 0);
-
-  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":49
- * 
- *     def __iadd__(SufficientStats self, SufficientStats other):
- *         self.stats[0] += other.stats[0]             # <<<<<<<<<<<<<<
- *         return self
- * 
- */
-  (__pyx_v_self->stats[0]) += (__pyx_v_other->stats[0]);
-
-  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":50
- *     def __iadd__(SufficientStats self, SufficientStats other):
- *         self.stats[0] += other.stats[0]
- *         return self             # <<<<<<<<<<<<<<
- * 
- *     def __add__(x, y):
- */
-  __Pyx_XDECREF(__pyx_r);
-  __Pyx_INCREF(((PyObject *)__pyx_v_self));
-  __pyx_r = ((PyObject *)__pyx_v_self);
-  goto __pyx_L0;
+  int __pyx_lineno = 0;
+  const char *__pyx_filename = NULL;
+  int __pyx_clineno = 0;
+  __Pyx_RefNannySetupContext("__get__", 0);
+  __pyx_cur_scope = (struct __pyx_obj_5_cdec___pyx_scope_struct_16___get__ *)__pyx_ptype_5_cdec___pyx_scope_struct_16___get__->tp_new(__pyx_ptype_5_cdec___pyx_scope_struct_16___get__, __pyx_empty_tuple, NULL);
+  if (unlikely(!__pyx_cur_scope)) {
+    __Pyx_RefNannyFinishContext();
+    return NULL;
+  }
+  __Pyx_GOTREF(__pyx_cur_scope);
+  __pyx_cur_scope->__pyx_v_self = __pyx_v_self;
+  __Pyx_INCREF((PyObject *)__pyx_cur_scope->__pyx_v_self);
+  __Pyx_GIVEREF((PyObject *)__pyx_cur_scope->__pyx_v_self);
+  {
+    __pyx_GeneratorObject *gen = __Pyx_Generator_New((__pyx_generator_body_t) __pyx_gb_5_cdec_14HypergraphNode_9out_edges_2generator12, (PyObject *) __pyx_cur_scope); if (unlikely(!gen)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 209; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_DECREF(__pyx_cur_scope);
+    __Pyx_RefNannyFinishContext();
+    return (PyObject *) gen;
+  }
 
   __pyx_r = Py_None; __Pyx_INCREF(Py_None);
+  goto __pyx_L0;
+  __pyx_L1_error:;
+  __Pyx_AddTraceback("_cdec.HypergraphNode.out_edges.__get__", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __pyx_r = NULL;
   __pyx_L0:;
+  __Pyx_DECREF(((PyObject *)__pyx_cur_scope));
   __Pyx_XGIVEREF(__pyx_r);
   __Pyx_RefNannyFinishContext();
   return __pyx_r;
 }
 
+static PyObject *__pyx_gb_5_cdec_14HypergraphNode_9out_edges_2generator12(__pyx_GeneratorObject *__pyx_generator, PyObject *__pyx_sent_value) /* generator body */
+{
+  struct __pyx_obj_5_cdec___pyx_scope_struct_16___get__ *__pyx_cur_scope = ((struct __pyx_obj_5_cdec___pyx_scope_struct_16___get__ *)__pyx_generator->closure);
+  PyObject *__pyx_r = NULL;
+  size_t __pyx_t_1;
+  unsigned int __pyx_t_2;
+  PyObject *__pyx_t_3 = NULL;
+  PyObject *__pyx_t_4 = NULL;
+  __Pyx_RefNannyDeclarations
+  __Pyx_RefNannySetupContext("None", 0);
+  switch (__pyx_generator->resume_label) {
+    case 0: goto __pyx_L3_first_run;
+    case 1: goto __pyx_L6_resume_from_yield;
+    default: /* CPython raises the right error here */
+    __Pyx_RefNannyFinishContext();
+    return NULL;
+  }
+  __pyx_L3_first_run:;
+  if (unlikely(!__pyx_sent_value)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 209; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":211
+ *         def __get__(self):
+ *             cdef unsigned i
+ *             for i in range(self.node.out_edges_.size()):             # <<<<<<<<<<<<<<
+ *                 yield HypergraphEdge().init(self.hg, self.node.out_edges_[i])
+ * 
+ */
+  __pyx_t_1 = __pyx_cur_scope->__pyx_v_self->node->out_edges_.size();
+  for (__pyx_t_2 = 0; __pyx_t_2 < __pyx_t_1; __pyx_t_2+=1) {
+    __pyx_cur_scope->__pyx_v_i = __pyx_t_2;
+
+    /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":212
+ *             cdef unsigned i
+ *             for i in range(self.node.out_edges_.size()):
+ *                 yield HypergraphEdge().init(self.hg, self.node.out_edges_[i])             # <<<<<<<<<<<<<<
+ * 
+ *     property span:
+ */
+    __pyx_t_3 = PyObject_Call(((PyObject *)((PyObject*)__pyx_ptype_5_cdec_HypergraphEdge)), ((PyObject *)__pyx_empty_tuple), NULL); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 212; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_3);
+    __pyx_t_4 = ((struct __pyx_vtabstruct_5_cdec_HypergraphEdge *)((struct __pyx_obj_5_cdec_HypergraphEdge *)__pyx_t_3)->__pyx_vtab)->init(((struct __pyx_obj_5_cdec_HypergraphEdge *)__pyx_t_3), __pyx_cur_scope->__pyx_v_self->hg, (__pyx_cur_scope->__pyx_v_self->node->out_edges_[__pyx_cur_scope->__pyx_v_i])); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 212; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_4);
+    __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
+    __pyx_r = __pyx_t_4;
+    __pyx_t_4 = 0;
+    __pyx_cur_scope->__pyx_t_0 = __pyx_t_1;
+    __pyx_cur_scope->__pyx_t_1 = __pyx_t_2;
+    __Pyx_XGIVEREF(__pyx_r);
+    __Pyx_RefNannyFinishContext();
+    /* return from generator, yielding value */
+    __pyx_generator->resume_label = 1;
+    return __pyx_r;
+    __pyx_L6_resume_from_yield:;
+    __pyx_t_1 = __pyx_cur_scope->__pyx_t_0;
+    __pyx_t_2 = __pyx_cur_scope->__pyx_t_1;
+    if (unlikely(!__pyx_sent_value)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 212; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  }
+  PyErr_SetNone(PyExc_StopIteration);
+  goto __pyx_L0;
+  __pyx_L1_error:;
+  __Pyx_XDECREF(__pyx_t_3);
+  __Pyx_XDECREF(__pyx_t_4);
+  __Pyx_AddTraceback("__get__", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __pyx_L0:;
+  __Pyx_XDECREF(__pyx_r);
+  __pyx_generator->resume_label = -1;
+  __Pyx_RefNannyFinishContext();
+  return NULL;
+}
+
 /* Python wrapper */
-static PyObject *__pyx_pw_5_cdec_15SufficientStats_10__add__(PyObject *__pyx_v_x, PyObject *__pyx_v_y); /*proto*/
-static PyObject *__pyx_pw_5_cdec_15SufficientStats_10__add__(PyObject *__pyx_v_x, PyObject *__pyx_v_y) {
+static PyObject *__pyx_pw_5_cdec_14HypergraphNode_4span_1__get__(PyObject *__pyx_v_self); /*proto*/
+static PyObject *__pyx_pw_5_cdec_14HypergraphNode_4span_1__get__(PyObject *__pyx_v_self) {
   PyObject *__pyx_r = 0;
   __Pyx_RefNannyDeclarations
-  __Pyx_RefNannySetupContext("__add__ (wrapper)", 0);
-  __pyx_r = __pyx_pf_5_cdec_15SufficientStats_9__add__(((PyObject *)__pyx_v_x), ((PyObject *)__pyx_v_y));
+  __Pyx_RefNannySetupContext("__get__ (wrapper)", 0);
+  __pyx_r = __pyx_pf_5_cdec_14HypergraphNode_4span___get__(((struct __pyx_obj_5_cdec_HypergraphNode *)__pyx_v_self));
   __Pyx_RefNannyFinishContext();
   return __pyx_r;
 }
 
-/* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":52
- *         return self
+/* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":215
+ * 
+ *     property span:
+ *         def __get__(self):             # <<<<<<<<<<<<<<
+ *             return next(self.in_edges).span
  * 
- *     def __add__(x, y):             # <<<<<<<<<<<<<<
- *         cdef SufficientStats sx = as_stats(x, y)
- *         cdef SufficientStats sy = as_stats(y, x)
  */
 
-static PyObject *__pyx_pf_5_cdec_15SufficientStats_9__add__(PyObject *__pyx_v_x, PyObject *__pyx_v_y) {
-  struct __pyx_obj_5_cdec_SufficientStats *__pyx_v_sx = 0;
-  struct __pyx_obj_5_cdec_SufficientStats *__pyx_v_sy = 0;
-  struct __pyx_obj_5_cdec_SufficientStats *__pyx_v_result = 0;
+static PyObject *__pyx_pf_5_cdec_14HypergraphNode_4span___get__(struct __pyx_obj_5_cdec_HypergraphNode *__pyx_v_self) {
   PyObject *__pyx_r = NULL;
   __Pyx_RefNannyDeclarations
   PyObject *__pyx_t_1 = NULL;
+  PyObject *__pyx_t_2 = NULL;
   int __pyx_lineno = 0;
   const char *__pyx_filename = NULL;
   int __pyx_clineno = 0;
-  __Pyx_RefNannySetupContext("__add__", 0);
+  __Pyx_RefNannySetupContext("__get__", 0);
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":53
+  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":216
+ *     property span:
+ *         def __get__(self):
+ *             return next(self.in_edges).span             # <<<<<<<<<<<<<<
  * 
- *     def __add__(x, y):
- *         cdef SufficientStats sx = as_stats(x, y)             # <<<<<<<<<<<<<<
- *         cdef SufficientStats sy = as_stats(y, x)
- *         cdef SufficientStats result = SufficientStats()
+ *     property cat:
  */
-  __pyx_t_1 = ((PyObject *)__pyx_f_5_cdec_as_stats(__pyx_v_x, __pyx_v_y)); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 53; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_XDECREF(__pyx_r);
+  __pyx_t_1 = PyObject_GetAttr(((PyObject *)__pyx_v_self), __pyx_n_s__in_edges); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 216; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __Pyx_GOTREF(__pyx_t_1);
-  __pyx_v_sx = ((struct __pyx_obj_5_cdec_SufficientStats *)__pyx_t_1);
-  __pyx_t_1 = 0;
-
-  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":54
- *     def __add__(x, y):
- *         cdef SufficientStats sx = as_stats(x, y)
- *         cdef SufficientStats sy = as_stats(y, x)             # <<<<<<<<<<<<<<
- *         cdef SufficientStats result = SufficientStats()
- *         result.stats = new mteval.SufficientStats(mteval.add(sx.stats[0], sy.stats[0]))
- */
-  __pyx_t_1 = ((PyObject *)__pyx_f_5_cdec_as_stats(__pyx_v_y, __pyx_v_x)); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 54; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_2 = __Pyx_PyIter_Next(__pyx_t_1); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 216; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_2);
+  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+  __pyx_t_1 = PyObject_GetAttr(__pyx_t_2, __pyx_n_s__span); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 216; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __Pyx_GOTREF(__pyx_t_1);
-  __pyx_v_sy = ((struct __pyx_obj_5_cdec_SufficientStats *)__pyx_t_1);
+  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+  __pyx_r = __pyx_t_1;
   __pyx_t_1 = 0;
+  goto __pyx_L0;
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":55
- *         cdef SufficientStats sx = as_stats(x, y)
- *         cdef SufficientStats sy = as_stats(y, x)
- *         cdef SufficientStats result = SufficientStats()             # <<<<<<<<<<<<<<
- *         result.stats = new mteval.SufficientStats(mteval.add(sx.stats[0], sy.stats[0]))
- *         result.metric = sx.metric
- */
-  __pyx_t_1 = PyObject_Call(((PyObject *)((PyObject*)__pyx_ptype_5_cdec_SufficientStats)), ((PyObject *)__pyx_empty_tuple), NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 55; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __Pyx_GOTREF(__pyx_t_1);
-  __pyx_v_result = ((struct __pyx_obj_5_cdec_SufficientStats *)__pyx_t_1);
-  __pyx_t_1 = 0;
+  __pyx_r = Py_None; __Pyx_INCREF(Py_None);
+  goto __pyx_L0;
+  __pyx_L1_error:;
+  __Pyx_XDECREF(__pyx_t_1);
+  __Pyx_XDECREF(__pyx_t_2);
+  __Pyx_AddTraceback("_cdec.HypergraphNode.span.__get__", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __pyx_r = NULL;
+  __pyx_L0:;
+  __Pyx_XGIVEREF(__pyx_r);
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":56
- *         cdef SufficientStats sy = as_stats(y, x)
- *         cdef SufficientStats result = SufficientStats()
- *         result.stats = new mteval.SufficientStats(mteval.add(sx.stats[0], sy.stats[0]))             # <<<<<<<<<<<<<<
- *         result.metric = sx.metric
- *         return result
+/* Python wrapper */
+static PyObject *__pyx_pw_5_cdec_14HypergraphNode_3cat_1__get__(PyObject *__pyx_v_self); /*proto*/
+static PyObject *__pyx_pw_5_cdec_14HypergraphNode_3cat_1__get__(PyObject *__pyx_v_self) {
+  PyObject *__pyx_r = 0;
+  __Pyx_RefNannyDeclarations
+  __Pyx_RefNannySetupContext("__get__ (wrapper)", 0);
+  __pyx_r = __pyx_pf_5_cdec_14HypergraphNode_3cat___get__(((struct __pyx_obj_5_cdec_HypergraphNode *)__pyx_v_self));
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+/* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":219
+ * 
+ *     property cat:
+ *         def __get__(self):             # <<<<<<<<<<<<<<
+ *             if self.node.cat_:
+ *                 return TDConvert(-self.node.cat_)
  */
-  __pyx_v_result->stats = new SufficientStats(operator+((__pyx_v_sx->stats[0]), (__pyx_v_sy->stats[0])));
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":57
- *         cdef SufficientStats result = SufficientStats()
- *         result.stats = new mteval.SufficientStats(mteval.add(sx.stats[0], sy.stats[0]))
- *         result.metric = sx.metric             # <<<<<<<<<<<<<<
- *         return result
+static PyObject *__pyx_pf_5_cdec_14HypergraphNode_3cat___get__(struct __pyx_obj_5_cdec_HypergraphNode *__pyx_v_self) {
+  PyObject *__pyx_r = NULL;
+  __Pyx_RefNannyDeclarations
+  PyObject *__pyx_t_1 = NULL;
+  int __pyx_lineno = 0;
+  const char *__pyx_filename = NULL;
+  int __pyx_clineno = 0;
+  __Pyx_RefNannySetupContext("__get__", 0);
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":220
+ *     property cat:
+ *         def __get__(self):
+ *             if self.node.cat_:             # <<<<<<<<<<<<<<
+ *                 return TDConvert(-self.node.cat_)
  * 
  */
-  __pyx_v_result->metric = __pyx_v_sx->metric;
+  if (__pyx_v_self->node->cat_) {
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":58
- *         result.stats = new mteval.SufficientStats(mteval.add(sx.stats[0], sy.stats[0]))
- *         result.metric = sx.metric
- *         return result             # <<<<<<<<<<<<<<
+    /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":221
+ *         def __get__(self):
+ *             if self.node.cat_:
+ *                 return TDConvert(-self.node.cat_)             # <<<<<<<<<<<<<<
  * 
- * cdef class CandidateSet:
+ *     def __richcmp__(HypergraphNode x, HypergraphNode y, int op):
  */
-  __Pyx_XDECREF(__pyx_r);
-  __Pyx_INCREF(((PyObject *)__pyx_v_result));
-  __pyx_r = ((PyObject *)__pyx_v_result);
-  goto __pyx_L0;
+    __Pyx_XDECREF(__pyx_r);
+    __pyx_t_1 = PyBytes_FromString(TD::Convert((-__pyx_v_self->node->cat_))); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 221; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(((PyObject *)__pyx_t_1));
+    __pyx_r = ((PyObject *)__pyx_t_1);
+    __pyx_t_1 = 0;
+    goto __pyx_L0;
+    goto __pyx_L3;
+  }
+  __pyx_L3:;
 
   __pyx_r = Py_None; __Pyx_INCREF(Py_None);
   goto __pyx_L0;
   __pyx_L1_error:;
   __Pyx_XDECREF(__pyx_t_1);
-  __Pyx_AddTraceback("_cdec.SufficientStats.__add__", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __Pyx_AddTraceback("_cdec.HypergraphNode.cat.__get__", __pyx_clineno, __pyx_lineno, __pyx_filename);
   __pyx_r = NULL;
   __pyx_L0:;
-  __Pyx_XDECREF((PyObject *)__pyx_v_sx);
-  __Pyx_XDECREF((PyObject *)__pyx_v_sy);
-  __Pyx_XDECREF((PyObject *)__pyx_v_result);
   __Pyx_XGIVEREF(__pyx_r);
   __Pyx_RefNannyFinishContext();
   return __pyx_r;
 }
 
 /* Python wrapper */
-static int __pyx_pw_5_cdec_12CandidateSet_1__cinit__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/
-static int __pyx_pw_5_cdec_12CandidateSet_1__cinit__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) {
-  struct __pyx_obj_5_cdec_SegmentEvaluator *__pyx_v_evaluator = 0;
-  static PyObject **__pyx_pyargnames[] = {&__pyx_n_s__evaluator,0};
-  int __pyx_r;
+static PyObject *__pyx_pw_5_cdec_14HypergraphNode_1__richcmp__(PyObject *__pyx_v_x, PyObject *__pyx_v_y, int __pyx_v_op); /*proto*/
+static PyObject *__pyx_pw_5_cdec_14HypergraphNode_1__richcmp__(PyObject *__pyx_v_x, PyObject *__pyx_v_y, int __pyx_v_op) {
+  PyObject *__pyx_r = 0;
   __Pyx_RefNannyDeclarations
-  __Pyx_RefNannySetupContext("__cinit__ (wrapper)", 0);
-  {
-    PyObject* values[1] = {0};
-    if (unlikely(__pyx_kwds)) {
-      Py_ssize_t kw_args;
-      const Py_ssize_t pos_args = PyTuple_GET_SIZE(__pyx_args);
-      switch (pos_args) {
-        case  1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0);
-        case  0: break;
-        default: goto __pyx_L5_argtuple_error;
-      }
-      kw_args = PyDict_Size(__pyx_kwds);
-      switch (pos_args) {
-        case  0:
-        values[0] = PyDict_GetItem(__pyx_kwds, __pyx_n_s__evaluator);
-        if (likely(values[0])) kw_args--;
-        else goto __pyx_L5_argtuple_error;
-      }
-      if (unlikely(kw_args > 0)) {
-        if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "__cinit__") < 0)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 65; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
-      }
-    } else if (PyTuple_GET_SIZE(__pyx_args) != 1) {
-      goto __pyx_L5_argtuple_error;
-    } else {
-      values[0] = PyTuple_GET_ITEM(__pyx_args, 0);
-    }
-    __pyx_v_evaluator = ((struct __pyx_obj_5_cdec_SegmentEvaluator *)values[0]);
-  }
-  goto __pyx_L4_argument_unpacking_done;
-  __pyx_L5_argtuple_error:;
-  __Pyx_RaiseArgtupleInvalid("__cinit__", 1, 1, 1, PyTuple_GET_SIZE(__pyx_args)); {__pyx_filename = __pyx_f[5]; __pyx_lineno = 65; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
-  __pyx_L3_error:;
-  __Pyx_AddTraceback("_cdec.CandidateSet.__cinit__", __pyx_clineno, __pyx_lineno, __pyx_filename);
-  __Pyx_RefNannyFinishContext();
-  return -1;
-  __pyx_L4_argument_unpacking_done:;
-  if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_evaluator), __pyx_ptype_5_cdec_SegmentEvaluator, 1, "evaluator", 0))) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 65; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __pyx_r = __pyx_pf_5_cdec_12CandidateSet___cinit__(((struct __pyx_obj_5_cdec_CandidateSet *)__pyx_v_self), __pyx_v_evaluator);
+  __Pyx_RefNannySetupContext("__richcmp__ (wrapper)", 0);
+  if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_x), __pyx_ptype_5_cdec_HypergraphNode, 1, "x", 0))) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 223; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_y), __pyx_ptype_5_cdec_HypergraphNode, 1, "y", 0))) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 223; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_r = __pyx_pf_5_cdec_14HypergraphNode___richcmp__(((struct __pyx_obj_5_cdec_HypergraphNode *)__pyx_v_x), ((struct __pyx_obj_5_cdec_HypergraphNode *)__pyx_v_y), ((int)__pyx_v_op));
   goto __pyx_L0;
   __pyx_L1_error:;
-  __pyx_r = -1;
+  __pyx_r = NULL;
   __pyx_L0:;
   __Pyx_RefNannyFinishContext();
   return __pyx_r;
 }
 
-/* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":65
- *     cdef mteval.CandidateSet* cs
+/* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":223
+ *                 return TDConvert(-self.node.cat_)
  * 
- *     def __cinit__(self, SegmentEvaluator evaluator):             # <<<<<<<<<<<<<<
- *         self.scorer = new shared_ptr[mteval.SegmentEvaluator](evaluator.scorer[0])
- *         self.metric = evaluator.metric
+ *     def __richcmp__(HypergraphNode x, HypergraphNode y, int op):             # <<<<<<<<<<<<<<
+ *         if op == 2: # ==
+ *             return x.node == y.node
  */
 
-static int __pyx_pf_5_cdec_12CandidateSet___cinit__(struct __pyx_obj_5_cdec_CandidateSet *__pyx_v_self, struct __pyx_obj_5_cdec_SegmentEvaluator *__pyx_v_evaluator) {
-  int __pyx_r;
+static PyObject *__pyx_pf_5_cdec_14HypergraphNode___richcmp__(struct __pyx_obj_5_cdec_HypergraphNode *__pyx_v_x, struct __pyx_obj_5_cdec_HypergraphNode *__pyx_v_y, int __pyx_v_op) {
+  PyObject *__pyx_r = NULL;
   __Pyx_RefNannyDeclarations
-  __Pyx_RefNannySetupContext("__cinit__", 0);
-
-  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":66
- * 
- *     def __cinit__(self, SegmentEvaluator evaluator):
- *         self.scorer = new shared_ptr[mteval.SegmentEvaluator](evaluator.scorer[0])             # <<<<<<<<<<<<<<
- *         self.metric = evaluator.metric
- *         self.cs = new mteval.CandidateSet()
- */
-  __pyx_v_self->scorer = new boost::shared_ptr<SegmentEvaluator>((__pyx_v_evaluator->scorer[0]));
+  PyObject *__pyx_t_1 = NULL;
+  int __pyx_t_2;
+  int __pyx_lineno = 0;
+  const char *__pyx_filename = NULL;
+  int __pyx_clineno = 0;
+  __Pyx_RefNannySetupContext("__richcmp__", 0);
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":67
- *     def __cinit__(self, SegmentEvaluator evaluator):
- *         self.scorer = new shared_ptr[mteval.SegmentEvaluator](evaluator.scorer[0])
- *         self.metric = evaluator.metric             # <<<<<<<<<<<<<<
- *         self.cs = new mteval.CandidateSet()
- * 
+  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":226
+ *         if op == 2: # ==
+ *             return x.node == y.node
+ *         elif op == 3: # !=             # <<<<<<<<<<<<<<
+ *             return not (x == y)
+ *         raise NotImplemented('comparison not implemented for HypergraphNode')
  */
-  __pyx_v_self->metric = __pyx_v_evaluator->metric;
+  switch (__pyx_v_op) {
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":68
- *         self.scorer = new shared_ptr[mteval.SegmentEvaluator](evaluator.scorer[0])
- *         self.metric = evaluator.metric
- *         self.cs = new mteval.CandidateSet()             # <<<<<<<<<<<<<<
+    /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":224
  * 
- *     def __dealloc__(self):
+ *     def __richcmp__(HypergraphNode x, HypergraphNode y, int op):
+ *         if op == 2: # ==             # <<<<<<<<<<<<<<
+ *             return x.node == y.node
+ *         elif op == 3: # !=
  */
-  __pyx_v_self->cs = new training::CandidateSet();
-
-  __pyx_r = 0;
-  __Pyx_RefNannyFinishContext();
-  return __pyx_r;
-}
-
-/* Python wrapper */
-static void __pyx_pw_5_cdec_12CandidateSet_3__dealloc__(PyObject *__pyx_v_self); /*proto*/
-static void __pyx_pw_5_cdec_12CandidateSet_3__dealloc__(PyObject *__pyx_v_self) {
-  __Pyx_RefNannyDeclarations
-  __Pyx_RefNannySetupContext("__dealloc__ (wrapper)", 0);
-  __pyx_pf_5_cdec_12CandidateSet_2__dealloc__(((struct __pyx_obj_5_cdec_CandidateSet *)__pyx_v_self));
-  __Pyx_RefNannyFinishContext();
-}
+    case 2:
 
-/* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":70
- *         self.cs = new mteval.CandidateSet()
- * 
- *     def __dealloc__(self):             # <<<<<<<<<<<<<<
- *         del self.scorer
- *         del self.cs
+    /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":225
+ *     def __richcmp__(HypergraphNode x, HypergraphNode y, int op):
+ *         if op == 2: # ==
+ *             return x.node == y.node             # <<<<<<<<<<<<<<
+ *         elif op == 3: # !=
+ *             return not (x == y)
  */
+    __Pyx_XDECREF(__pyx_r);
+    __pyx_t_1 = __Pyx_PyBool_FromLong((__pyx_v_x->node == __pyx_v_y->node)); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 225; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_1);
+    __pyx_r = __pyx_t_1;
+    __pyx_t_1 = 0;
+    goto __pyx_L0;
+    break;
 
-static void __pyx_pf_5_cdec_12CandidateSet_2__dealloc__(CYTHON_UNUSED struct __pyx_obj_5_cdec_CandidateSet *__pyx_v_self) {
-  __Pyx_RefNannyDeclarations
-  __Pyx_RefNannySetupContext("__dealloc__", 0);
-
-  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":71
- * 
- *     def __dealloc__(self):
- *         del self.scorer             # <<<<<<<<<<<<<<
- *         del self.cs
- * 
+    /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":226
+ *         if op == 2: # ==
+ *             return x.node == y.node
+ *         elif op == 3: # !=             # <<<<<<<<<<<<<<
+ *             return not (x == y)
+ *         raise NotImplemented('comparison not implemented for HypergraphNode')
  */
-  delete __pyx_v_self->scorer;
+    case 3:
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":72
- *     def __dealloc__(self):
- *         del self.scorer
- *         del self.cs             # <<<<<<<<<<<<<<
- * 
- *     def __len__(self):
+    /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":227
+ *             return x.node == y.node
+ *         elif op == 3: # !=
+ *             return not (x == y)             # <<<<<<<<<<<<<<
+ *         raise NotImplemented('comparison not implemented for HypergraphNode')
  */
-  delete __pyx_v_self->cs;
-
-  __Pyx_RefNannyFinishContext();
-}
-
-/* Python wrapper */
-static Py_ssize_t __pyx_pw_5_cdec_12CandidateSet_5__len__(PyObject *__pyx_v_self); /*proto*/
-static Py_ssize_t __pyx_pw_5_cdec_12CandidateSet_5__len__(PyObject *__pyx_v_self) {
-  Py_ssize_t __pyx_r;
-  __Pyx_RefNannyDeclarations
-  __Pyx_RefNannySetupContext("__len__ (wrapper)", 0);
-  __pyx_r = __pyx_pf_5_cdec_12CandidateSet_4__len__(((struct __pyx_obj_5_cdec_CandidateSet *)__pyx_v_self));
-  __Pyx_RefNannyFinishContext();
-  return __pyx_r;
-}
+    __Pyx_XDECREF(__pyx_r);
+    __pyx_t_1 = PyObject_RichCompare(((PyObject *)__pyx_v_x), ((PyObject *)__pyx_v_y), Py_EQ); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 227; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_1);
+    __pyx_t_2 = __Pyx_PyObject_IsTrue(__pyx_t_1); if (unlikely(__pyx_t_2 < 0)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 227; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+    __pyx_t_1 = __Pyx_PyBool_FromLong((!__pyx_t_2)); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 227; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_1);
+    __pyx_r = __pyx_t_1;
+    __pyx_t_1 = 0;
+    goto __pyx_L0;
+    break;
+  }
 
-/* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":74
- *         del self.cs
- * 
- *     def __len__(self):             # <<<<<<<<<<<<<<
- *         return self.cs.size()
- * 
+  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":228
+ *         elif op == 3: # !=
+ *             return not (x == y)
+ *         raise NotImplemented('comparison not implemented for HypergraphNode')             # <<<<<<<<<<<<<<
  */
+  __pyx_t_1 = PyObject_Call(__pyx_builtin_NotImplemented, ((PyObject *)__pyx_k_tuple_20), NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 228; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_1);
+  __Pyx_Raise(__pyx_t_1, 0, 0, 0);
+  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+  {__pyx_filename = __pyx_f[3]; __pyx_lineno = 228; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
 
-static Py_ssize_t __pyx_pf_5_cdec_12CandidateSet_4__len__(struct __pyx_obj_5_cdec_CandidateSet *__pyx_v_self) {
-  Py_ssize_t __pyx_r;
-  __Pyx_RefNannyDeclarations
-  __Pyx_RefNannySetupContext("__len__", 0);
-
-  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":75
- * 
- *     def __len__(self):
- *         return self.cs.size()             # <<<<<<<<<<<<<<
- * 
- *     def __getitem__(self,int k):
- */
-  __pyx_r = __pyx_v_self->cs->size();
+  __pyx_r = Py_None; __Pyx_INCREF(Py_None);
   goto __pyx_L0;
-
-  __pyx_r = 0;
+  __pyx_L1_error:;
+  __Pyx_XDECREF(__pyx_t_1);
+  __Pyx_AddTraceback("_cdec.HypergraphNode.__richcmp__", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __pyx_r = NULL;
   __pyx_L0:;
+  __Pyx_XGIVEREF(__pyx_r);
   __Pyx_RefNannyFinishContext();
   return __pyx_r;
 }
 
 /* Python wrapper */
-static PyObject *__pyx_pw_5_cdec_12CandidateSet_7__getitem__(PyObject *__pyx_v_self, PyObject *__pyx_arg_k); /*proto*/
-static PyObject *__pyx_pw_5_cdec_12CandidateSet_7__getitem__(PyObject *__pyx_v_self, PyObject *__pyx_arg_k) {
-  int __pyx_v_k;
-  PyObject *__pyx_r = 0;
+static int __pyx_pw_5_cdec_7Lattice_1__cinit__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/
+static int __pyx_pw_5_cdec_7Lattice_1__cinit__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) {
+  PyObject *__pyx_v_inp = 0;
+  static PyObject **__pyx_pyargnames[] = {&__pyx_n_s__inp,0};
+  int __pyx_r;
   __Pyx_RefNannyDeclarations
-  __Pyx_RefNannySetupContext("__getitem__ (wrapper)", 0);
-  assert(__pyx_arg_k); {
-    __pyx_v_k = __Pyx_PyInt_AsInt(__pyx_arg_k); if (unlikely((__pyx_v_k == (int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 77; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+  __Pyx_RefNannySetupContext("__cinit__ (wrapper)", 0);
+  {
+    PyObject* values[1] = {0};
+    if (unlikely(__pyx_kwds)) {
+      Py_ssize_t kw_args;
+      const Py_ssize_t pos_args = PyTuple_GET_SIZE(__pyx_args);
+      switch (pos_args) {
+        case  1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0);
+        case  0: break;
+        default: goto __pyx_L5_argtuple_error;
+      }
+      kw_args = PyDict_Size(__pyx_kwds);
+      switch (pos_args) {
+        case  0:
+        values[0] = PyDict_GetItem(__pyx_kwds, __pyx_n_s__inp);
+        if (likely(values[0])) kw_args--;
+        else goto __pyx_L5_argtuple_error;
+      }
+      if (unlikely(kw_args > 0)) {
+        if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "__cinit__") < 0)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 6; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+      }
+    } else if (PyTuple_GET_SIZE(__pyx_args) != 1) {
+      goto __pyx_L5_argtuple_error;
+    } else {
+      values[0] = PyTuple_GET_ITEM(__pyx_args, 0);
+    }
+    __pyx_v_inp = values[0];
   }
   goto __pyx_L4_argument_unpacking_done;
+  __pyx_L5_argtuple_error:;
+  __Pyx_RaiseArgtupleInvalid("__cinit__", 1, 1, 1, PyTuple_GET_SIZE(__pyx_args)); {__pyx_filename = __pyx_f[4]; __pyx_lineno = 6; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
   __pyx_L3_error:;
-  __Pyx_AddTraceback("_cdec.CandidateSet.__getitem__", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __Pyx_AddTraceback("_cdec.Lattice.__cinit__", __pyx_clineno, __pyx_lineno, __pyx_filename);
   __Pyx_RefNannyFinishContext();
-  return NULL;
+  return -1;
   __pyx_L4_argument_unpacking_done:;
-  __pyx_r = __pyx_pf_5_cdec_12CandidateSet_6__getitem__(((struct __pyx_obj_5_cdec_CandidateSet *)__pyx_v_self), ((int)__pyx_v_k));
+  __pyx_r = __pyx_pf_5_cdec_7Lattice___cinit__(((struct __pyx_obj_5_cdec_Lattice *)__pyx_v_self), __pyx_v_inp);
   __Pyx_RefNannyFinishContext();
   return __pyx_r;
 }
 
-/* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":77
- *         return self.cs.size()
+/* "/Users/vchahun/Sandbox/cdec/python/src/lattice.pxi":6
+ *     cdef lattice.Lattice* lattice
  * 
- *     def __getitem__(self,int k):             # <<<<<<<<<<<<<<
- *         if not 0 <= k < self.cs.size():
- *             raise IndexError('candidate set index out of range')
+ *     def __cinit__(self, inp):             # <<<<<<<<<<<<<<
+ *         if isinstance(inp, tuple):
+ *             self.lattice = new lattice.Lattice(len(inp))
  */
 
-static PyObject *__pyx_pf_5_cdec_12CandidateSet_6__getitem__(struct __pyx_obj_5_cdec_CandidateSet *__pyx_v_self, int __pyx_v_k) {
-  struct __pyx_obj_5_cdec_Candidate *__pyx_v_candidate = 0;
-  PyObject *__pyx_r = NULL;
-  __Pyx_RefNannyDeclarations
-  int __pyx_t_1;
+static int __pyx_pf_5_cdec_7Lattice___cinit__(struct __pyx_obj_5_cdec_Lattice *__pyx_v_self, PyObject *__pyx_v_inp) {
+  PyObject *__pyx_v_i = NULL;
+  PyObject *__pyx_v_arcs = NULL;
+  int __pyx_r;
+  __Pyx_RefNannyDeclarations
+  PyObject *__pyx_t_1 = NULL;
   int __pyx_t_2;
-  PyObject *__pyx_t_3 = NULL;
+  Py_ssize_t __pyx_t_3;
+  PyObject *__pyx_t_4 = NULL;
+  PyObject *(*__pyx_t_5)(PyObject *);
+  PyObject *__pyx_t_6 = NULL;
+  int __pyx_t_7;
+  char *__pyx_t_8;
   int __pyx_lineno = 0;
   const char *__pyx_filename = NULL;
   int __pyx_clineno = 0;
-  __Pyx_RefNannySetupContext("__getitem__", 0);
+  __Pyx_RefNannySetupContext("__cinit__", 0);
+  __Pyx_INCREF(__pyx_v_inp);
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":78
+  /* "/Users/vchahun/Sandbox/cdec/python/src/lattice.pxi":7
  * 
- *     def __getitem__(self,int k):
- *         if not 0 <= k < self.cs.size():             # <<<<<<<<<<<<<<
- *             raise IndexError('candidate set index out of range')
- *         cdef Candidate candidate = Candidate()
+ *     def __cinit__(self, inp):
+ *         if isinstance(inp, tuple):             # <<<<<<<<<<<<<<
+ *             self.lattice = new lattice.Lattice(len(inp))
+ *             for i, arcs in enumerate(inp):
  */
-  __pyx_t_1 = (0 <= __pyx_v_k);
-  if (__pyx_t_1) {
-    __pyx_t_1 = (__pyx_v_k < __pyx_v_self->cs->size());
-  }
-  __pyx_t_2 = (!__pyx_t_1);
+  __pyx_t_1 = ((PyObject *)((PyObject*)(&PyTuple_Type)));
+  __Pyx_INCREF(__pyx_t_1);
+  __pyx_t_2 = __Pyx_TypeCheck(__pyx_v_inp, __pyx_t_1); 
+  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
   if (__pyx_t_2) {
 
-    /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":79
- *     def __getitem__(self,int k):
- *         if not 0 <= k < self.cs.size():
- *             raise IndexError('candidate set index out of range')             # <<<<<<<<<<<<<<
- *         cdef Candidate candidate = Candidate()
- *         candidate.candidate = &self.cs[0][k]
+    /* "/Users/vchahun/Sandbox/cdec/python/src/lattice.pxi":8
+ *     def __cinit__(self, inp):
+ *         if isinstance(inp, tuple):
+ *             self.lattice = new lattice.Lattice(len(inp))             # <<<<<<<<<<<<<<
+ *             for i, arcs in enumerate(inp):
+ *                 self[i] = arcs
  */
-    __pyx_t_3 = PyObject_Call(__pyx_builtin_IndexError, ((PyObject *)__pyx_k_tuple_38), NULL); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 79; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-    __Pyx_GOTREF(__pyx_t_3);
-    __Pyx_Raise(__pyx_t_3, 0, 0, 0);
-    __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
-    {__pyx_filename = __pyx_f[5]; __pyx_lineno = 79; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_t_3 = PyObject_Length(__pyx_v_inp); if (unlikely(__pyx_t_3 == -1)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 8; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_v_self->lattice = new Lattice(__pyx_t_3);
+
+    /* "/Users/vchahun/Sandbox/cdec/python/src/lattice.pxi":9
+ *         if isinstance(inp, tuple):
+ *             self.lattice = new lattice.Lattice(len(inp))
+ *             for i, arcs in enumerate(inp):             # <<<<<<<<<<<<<<
+ *                 self[i] = arcs
+ *         else:
+ */
+    __Pyx_INCREF(__pyx_int_0);
+    __pyx_t_1 = __pyx_int_0;
+    if (PyList_CheckExact(__pyx_v_inp) || PyTuple_CheckExact(__pyx_v_inp)) {
+      __pyx_t_4 = __pyx_v_inp; __Pyx_INCREF(__pyx_t_4); __pyx_t_3 = 0;
+      __pyx_t_5 = NULL;
+    } else {
+      __pyx_t_3 = -1; __pyx_t_4 = PyObject_GetIter(__pyx_v_inp); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 9; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __Pyx_GOTREF(__pyx_t_4);
+      __pyx_t_5 = Py_TYPE(__pyx_t_4)->tp_iternext;
+    }
+    for (;;) {
+      if (!__pyx_t_5 && PyList_CheckExact(__pyx_t_4)) {
+        if (__pyx_t_3 >= PyList_GET_SIZE(__pyx_t_4)) break;
+        __pyx_t_6 = PyList_GET_ITEM(__pyx_t_4, __pyx_t_3); __Pyx_INCREF(__pyx_t_6); __pyx_t_3++;
+      } else if (!__pyx_t_5 && PyTuple_CheckExact(__pyx_t_4)) {
+        if (__pyx_t_3 >= PyTuple_GET_SIZE(__pyx_t_4)) break;
+        __pyx_t_6 = PyTuple_GET_ITEM(__pyx_t_4, __pyx_t_3); __Pyx_INCREF(__pyx_t_6); __pyx_t_3++;
+      } else {
+        __pyx_t_6 = __pyx_t_5(__pyx_t_4);
+        if (unlikely(!__pyx_t_6)) {
+          if (PyErr_Occurred()) {
+            if (likely(PyErr_ExceptionMatches(PyExc_StopIteration))) PyErr_Clear();
+            else {__pyx_filename = __pyx_f[4]; __pyx_lineno = 9; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+          }
+          break;
+        }
+        __Pyx_GOTREF(__pyx_t_6);
+      }
+      __Pyx_XDECREF(__pyx_v_arcs);
+      __pyx_v_arcs = __pyx_t_6;
+      __pyx_t_6 = 0;
+      __Pyx_INCREF(__pyx_t_1);
+      __Pyx_XDECREF(__pyx_v_i);
+      __pyx_v_i = __pyx_t_1;
+      __pyx_t_6 = PyNumber_Add(__pyx_t_1, __pyx_int_1); if (unlikely(!__pyx_t_6)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 9; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __Pyx_GOTREF(__pyx_t_6);
+      __Pyx_DECREF(__pyx_t_1);
+      __pyx_t_1 = __pyx_t_6;
+      __pyx_t_6 = 0;
+
+      /* "/Users/vchahun/Sandbox/cdec/python/src/lattice.pxi":10
+ *             self.lattice = new lattice.Lattice(len(inp))
+ *             for i, arcs in enumerate(inp):
+ *                 self[i] = arcs             # <<<<<<<<<<<<<<
+ *         else:
+ *             if isinstance(inp, unicode):
+ */
+      if (PyObject_SetItem(((PyObject *)__pyx_v_self), __pyx_v_i, __pyx_v_arcs) < 0) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 10; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    }
+    __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
+    __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
     goto __pyx_L3;
   }
-  __pyx_L3:;
+  /*else*/ {
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":80
- *         if not 0 <= k < self.cs.size():
- *             raise IndexError('candidate set index out of range')
- *         cdef Candidate candidate = Candidate()             # <<<<<<<<<<<<<<
- *         candidate.candidate = &self.cs[0][k]
- *         candidate.score = self.metric.ComputeScore(self.cs[0][k].eval_feats)
+    /* "/Users/vchahun/Sandbox/cdec/python/src/lattice.pxi":12
+ *                 self[i] = arcs
+ *         else:
+ *             if isinstance(inp, unicode):             # <<<<<<<<<<<<<<
+ *                 inp = inp.encode('utf8')
+ *             if not isinstance(inp, str):
  */
-  __pyx_t_3 = PyObject_Call(((PyObject *)((PyObject*)__pyx_ptype_5_cdec_Candidate)), ((PyObject *)__pyx_empty_tuple), NULL); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 80; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __Pyx_GOTREF(__pyx_t_3);
-  __pyx_v_candidate = ((struct __pyx_obj_5_cdec_Candidate *)__pyx_t_3);
-  __pyx_t_3 = 0;
+    __pyx_t_1 = ((PyObject *)((PyObject*)(&PyUnicode_Type)));
+    __Pyx_INCREF(__pyx_t_1);
+    __pyx_t_2 = __Pyx_TypeCheck(__pyx_v_inp, __pyx_t_1); 
+    __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+    if (__pyx_t_2) {
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":81
- *             raise IndexError('candidate set index out of range')
- *         cdef Candidate candidate = Candidate()
- *         candidate.candidate = &self.cs[0][k]             # <<<<<<<<<<<<<<
- *         candidate.score = self.metric.ComputeScore(self.cs[0][k].eval_feats)
- *         return candidate
+      /* "/Users/vchahun/Sandbox/cdec/python/src/lattice.pxi":13
+ *         else:
+ *             if isinstance(inp, unicode):
+ *                 inp = inp.encode('utf8')             # <<<<<<<<<<<<<<
+ *             if not isinstance(inp, str):
+ *                 raise TypeError('Cannot create lattice from %s' % type(inp))
  */
-  __pyx_v_candidate->candidate = (&((__pyx_v_self->cs[0])[__pyx_v_k]));
+      __pyx_t_1 = PyObject_GetAttr(__pyx_v_inp, __pyx_n_s__encode); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 13; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __Pyx_GOTREF(__pyx_t_1);
+      __pyx_t_4 = PyObject_Call(__pyx_t_1, ((PyObject *)__pyx_k_tuple_21), NULL); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 13; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __Pyx_GOTREF(__pyx_t_4);
+      __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+      __Pyx_DECREF(__pyx_v_inp);
+      __pyx_v_inp = __pyx_t_4;
+      __pyx_t_4 = 0;
+      goto __pyx_L6;
+    }
+    __pyx_L6:;
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":82
- *         cdef Candidate candidate = Candidate()
- *         candidate.candidate = &self.cs[0][k]
- *         candidate.score = self.metric.ComputeScore(self.cs[0][k].eval_feats)             # <<<<<<<<<<<<<<
- *         return candidate
+    /* "/Users/vchahun/Sandbox/cdec/python/src/lattice.pxi":14
+ *             if isinstance(inp, unicode):
+ *                 inp = inp.encode('utf8')
+ *             if not isinstance(inp, str):             # <<<<<<<<<<<<<<
+ *                 raise TypeError('Cannot create lattice from %s' % type(inp))
+ *             self.lattice = new lattice.Lattice()
+ */
+    __pyx_t_4 = ((PyObject *)((PyObject*)(&PyString_Type)));
+    __Pyx_INCREF(__pyx_t_4);
+    __pyx_t_2 = __Pyx_TypeCheck(__pyx_v_inp, __pyx_t_4); 
+    __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
+    __pyx_t_7 = (!__pyx_t_2);
+    if (__pyx_t_7) {
+
+      /* "/Users/vchahun/Sandbox/cdec/python/src/lattice.pxi":15
+ *                 inp = inp.encode('utf8')
+ *             if not isinstance(inp, str):
+ *                 raise TypeError('Cannot create lattice from %s' % type(inp))             # <<<<<<<<<<<<<<
+ *             self.lattice = new lattice.Lattice()
+ *             lattice.ConvertTextToLattice(string(<char *>inp), self.lattice)
+ */
+      __pyx_t_4 = PyNumber_Remainder(((PyObject *)__pyx_kp_s_22), ((PyObject *)Py_TYPE(__pyx_v_inp))); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 15; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __Pyx_GOTREF(((PyObject *)__pyx_t_4));
+      __pyx_t_1 = PyTuple_New(1); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 15; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __Pyx_GOTREF(__pyx_t_1);
+      PyTuple_SET_ITEM(__pyx_t_1, 0, ((PyObject *)__pyx_t_4));
+      __Pyx_GIVEREF(((PyObject *)__pyx_t_4));
+      __pyx_t_4 = 0;
+      __pyx_t_4 = PyObject_Call(__pyx_builtin_TypeError, ((PyObject *)__pyx_t_1), NULL); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 15; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __Pyx_GOTREF(__pyx_t_4);
+      __Pyx_DECREF(((PyObject *)__pyx_t_1)); __pyx_t_1 = 0;
+      __Pyx_Raise(__pyx_t_4, 0, 0, 0);
+      __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
+      {__pyx_filename = __pyx_f[4]; __pyx_lineno = 15; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      goto __pyx_L7;
+    }
+    __pyx_L7:;
+
+    /* "/Users/vchahun/Sandbox/cdec/python/src/lattice.pxi":16
+ *             if not isinstance(inp, str):
+ *                 raise TypeError('Cannot create lattice from %s' % type(inp))
+ *             self.lattice = new lattice.Lattice()             # <<<<<<<<<<<<<<
+ *             lattice.ConvertTextToLattice(string(<char *>inp), self.lattice)
  * 
  */
-  __pyx_v_candidate->score = __pyx_v_self->metric->ComputeScore(((__pyx_v_self->cs[0])[__pyx_v_k]).eval_feats);
+    __pyx_v_self->lattice = new Lattice();
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":83
- *         candidate.candidate = &self.cs[0][k]
- *         candidate.score = self.metric.ComputeScore(self.cs[0][k].eval_feats)
- *         return candidate             # <<<<<<<<<<<<<<
+    /* "/Users/vchahun/Sandbox/cdec/python/src/lattice.pxi":17
+ *                 raise TypeError('Cannot create lattice from %s' % type(inp))
+ *             self.lattice = new lattice.Lattice()
+ *             lattice.ConvertTextToLattice(string(<char *>inp), self.lattice)             # <<<<<<<<<<<<<<
  * 
- *     def __iter__(self):
+ *     def __getitem__(self, int index):
  */
-  __Pyx_XDECREF(__pyx_r);
-  __Pyx_INCREF(((PyObject *)__pyx_v_candidate));
-  __pyx_r = ((PyObject *)__pyx_v_candidate);
-  goto __pyx_L0;
+    __pyx_t_8 = PyBytes_AsString(__pyx_v_inp); if (unlikely((!__pyx_t_8) && PyErr_Occurred())) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 17; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    LatticeTools::ConvertTextToLattice(std::string(((char *)__pyx_t_8)), __pyx_v_self->lattice);
+  }
+  __pyx_L3:;
 
-  __pyx_r = Py_None; __Pyx_INCREF(Py_None);
+  __pyx_r = 0;
   goto __pyx_L0;
   __pyx_L1_error:;
-  __Pyx_XDECREF(__pyx_t_3);
-  __Pyx_AddTraceback("_cdec.CandidateSet.__getitem__", __pyx_clineno, __pyx_lineno, __pyx_filename);
-  __pyx_r = NULL;
+  __Pyx_XDECREF(__pyx_t_1);
+  __Pyx_XDECREF(__pyx_t_4);
+  __Pyx_XDECREF(__pyx_t_6);
+  __Pyx_AddTraceback("_cdec.Lattice.__cinit__", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __pyx_r = -1;
   __pyx_L0:;
-  __Pyx_XDECREF((PyObject *)__pyx_v_candidate);
-  __Pyx_XGIVEREF(__pyx_r);
+  __Pyx_XDECREF(__pyx_v_i);
+  __Pyx_XDECREF(__pyx_v_arcs);
+  __Pyx_XDECREF(__pyx_v_inp);
   __Pyx_RefNannyFinishContext();
   return __pyx_r;
 }
-static PyObject *__pyx_gb_5_cdec_12CandidateSet_10generator13(__pyx_GeneratorObject *__pyx_generator, PyObject *__pyx_sent_value); /* proto */
 
 /* Python wrapper */
-static PyObject *__pyx_pw_5_cdec_12CandidateSet_9__iter__(PyObject *__pyx_v_self); /*proto*/
-static PyObject *__pyx_pw_5_cdec_12CandidateSet_9__iter__(PyObject *__pyx_v_self) {
+static PyObject *__pyx_pw_5_cdec_7Lattice_3__getitem__(PyObject *__pyx_v_self, PyObject *__pyx_arg_index); /*proto*/
+static PyObject *__pyx_pw_5_cdec_7Lattice_3__getitem__(PyObject *__pyx_v_self, PyObject *__pyx_arg_index) {
+  int __pyx_v_index;
   PyObject *__pyx_r = 0;
   __Pyx_RefNannyDeclarations
-  __Pyx_RefNannySetupContext("__iter__ (wrapper)", 0);
-  __pyx_r = __pyx_pf_5_cdec_12CandidateSet_8__iter__(((struct __pyx_obj_5_cdec_CandidateSet *)__pyx_v_self));
+  __Pyx_RefNannySetupContext("__getitem__ (wrapper)", 0);
+  assert(__pyx_arg_index); {
+    __pyx_v_index = __Pyx_PyInt_AsInt(__pyx_arg_index); if (unlikely((__pyx_v_index == (int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 19; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+  }
+  goto __pyx_L4_argument_unpacking_done;
+  __pyx_L3_error:;
+  __Pyx_AddTraceback("_cdec.Lattice.__getitem__", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __Pyx_RefNannyFinishContext();
+  return NULL;
+  __pyx_L4_argument_unpacking_done:;
+  __pyx_r = __pyx_pf_5_cdec_7Lattice_2__getitem__(((struct __pyx_obj_5_cdec_Lattice *)__pyx_v_self), ((int)__pyx_v_index));
   __Pyx_RefNannyFinishContext();
   return __pyx_r;
 }
 
-/* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":85
- *         return candidate
+/* "/Users/vchahun/Sandbox/cdec/python/src/lattice.pxi":19
+ *             lattice.ConvertTextToLattice(string(<char *>inp), self.lattice)
  * 
- *     def __iter__(self):             # <<<<<<<<<<<<<<
- *         cdef unsigned i
- *         for i in range(len(self)):
+ *     def __getitem__(self, int index):             # <<<<<<<<<<<<<<
+ *         if not 0 <= index < len(self):
+ *             raise IndexError('lattice index out of range')
  */
 
-static PyObject *__pyx_pf_5_cdec_12CandidateSet_8__iter__(struct __pyx_obj_5_cdec_CandidateSet *__pyx_v_self) {
-  struct __pyx_obj_5_cdec___pyx_scope_struct_19___iter__ *__pyx_cur_scope;
-  PyObject *__pyx_r = NULL;
-  __Pyx_RefNannyDeclarations
+static PyObject *__pyx_pf_5_cdec_7Lattice_2__getitem__(struct __pyx_obj_5_cdec_Lattice *__pyx_v_self, int __pyx_v_index) {
+  PyObject *__pyx_v_arcs = NULL;
+  std::vector<LatticeArc> __pyx_v_arc_vector;
+  LatticeArc *__pyx_v_arc;
+  unsigned int __pyx_v_i;
+  PyObject *__pyx_v_label = NULL;
+  PyObject *__pyx_r = NULL;
+  __Pyx_RefNannyDeclarations
+  int __pyx_t_1;
+  Py_ssize_t __pyx_t_2;
+  int __pyx_t_3;
+  PyObject *__pyx_t_4 = NULL;
+  size_t __pyx_t_5;
+  unsigned int __pyx_t_6;
+  PyObject *__pyx_t_7 = NULL;
+  PyObject *__pyx_t_8 = NULL;
+  int __pyx_t_9;
   int __pyx_lineno = 0;
   const char *__pyx_filename = NULL;
   int __pyx_clineno = 0;
-  __Pyx_RefNannySetupContext("__iter__", 0);
-  __pyx_cur_scope = (struct __pyx_obj_5_cdec___pyx_scope_struct_19___iter__ *)__pyx_ptype_5_cdec___pyx_scope_struct_19___iter__->tp_new(__pyx_ptype_5_cdec___pyx_scope_struct_19___iter__, __pyx_empty_tuple, NULL);
-  if (unlikely(!__pyx_cur_scope)) {
-    __Pyx_RefNannyFinishContext();
-    return NULL;
+  __Pyx_RefNannySetupContext("__getitem__", 0);
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/lattice.pxi":20
+ * 
+ *     def __getitem__(self, int index):
+ *         if not 0 <= index < len(self):             # <<<<<<<<<<<<<<
+ *             raise IndexError('lattice index out of range')
+ *         arcs = []
+ */
+  __pyx_t_1 = (0 <= __pyx_v_index);
+  if (__pyx_t_1) {
+    __pyx_t_2 = PyObject_Length(((PyObject *)__pyx_v_self)); if (unlikely(__pyx_t_2 == -1)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 20; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_t_1 = (__pyx_v_index < __pyx_t_2);
   }
-  __Pyx_GOTREF(__pyx_cur_scope);
-  __pyx_cur_scope->__pyx_v_self = __pyx_v_self;
-  __Pyx_INCREF((PyObject *)__pyx_cur_scope->__pyx_v_self);
-  __Pyx_GIVEREF((PyObject *)__pyx_cur_scope->__pyx_v_self);
-  {
-    __pyx_GeneratorObject *gen = __Pyx_Generator_New((__pyx_generator_body_t) __pyx_gb_5_cdec_12CandidateSet_10generator13, (PyObject *) __pyx_cur_scope); if (unlikely(!gen)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 85; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-    __Pyx_DECREF(__pyx_cur_scope);
-    __Pyx_RefNannyFinishContext();
-    return (PyObject *) gen;
+  __pyx_t_3 = (!__pyx_t_1);
+  if (__pyx_t_3) {
+
+    /* "/Users/vchahun/Sandbox/cdec/python/src/lattice.pxi":21
+ *     def __getitem__(self, int index):
+ *         if not 0 <= index < len(self):
+ *             raise IndexError('lattice index out of range')             # <<<<<<<<<<<<<<
+ *         arcs = []
+ *         cdef vector[lattice.LatticeArc] arc_vector = self.lattice[0][index]
+ */
+    __pyx_t_4 = PyObject_Call(__pyx_builtin_IndexError, ((PyObject *)__pyx_k_tuple_24), NULL); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 21; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_4);
+    __Pyx_Raise(__pyx_t_4, 0, 0, 0);
+    __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
+    {__pyx_filename = __pyx_f[4]; __pyx_lineno = 21; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    goto __pyx_L3;
+  }
+  __pyx_L3:;
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/lattice.pxi":22
+ *         if not 0 <= index < len(self):
+ *             raise IndexError('lattice index out of range')
+ *         arcs = []             # <<<<<<<<<<<<<<
+ *         cdef vector[lattice.LatticeArc] arc_vector = self.lattice[0][index]
+ *         cdef lattice.LatticeArc* arc
+ */
+  __pyx_t_4 = PyList_New(0); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 22; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_4);
+  __pyx_v_arcs = __pyx_t_4;
+  __pyx_t_4 = 0;
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/lattice.pxi":23
+ *             raise IndexError('lattice index out of range')
+ *         arcs = []
+ *         cdef vector[lattice.LatticeArc] arc_vector = self.lattice[0][index]             # <<<<<<<<<<<<<<
+ *         cdef lattice.LatticeArc* arc
+ *         cdef unsigned i
+ */
+  __pyx_v_arc_vector = ((__pyx_v_self->lattice[0])[__pyx_v_index]);
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/lattice.pxi":26
+ *         cdef lattice.LatticeArc* arc
+ *         cdef unsigned i
+ *         for i in range(arc_vector.size()):             # <<<<<<<<<<<<<<
+ *             arc = &arc_vector[i]
+ *             label = unicode(TDConvert(arc.label), 'utf8')
+ */
+  __pyx_t_5 = __pyx_v_arc_vector.size();
+  for (__pyx_t_6 = 0; __pyx_t_6 < __pyx_t_5; __pyx_t_6+=1) {
+    __pyx_v_i = __pyx_t_6;
+
+    /* "/Users/vchahun/Sandbox/cdec/python/src/lattice.pxi":27
+ *         cdef unsigned i
+ *         for i in range(arc_vector.size()):
+ *             arc = &arc_vector[i]             # <<<<<<<<<<<<<<
+ *             label = unicode(TDConvert(arc.label), 'utf8')
+ *             arcs.append((label, arc.cost, arc.dist2next))
+ */
+    __pyx_v_arc = (&(__pyx_v_arc_vector[__pyx_v_i]));
+
+    /* "/Users/vchahun/Sandbox/cdec/python/src/lattice.pxi":28
+ *         for i in range(arc_vector.size()):
+ *             arc = &arc_vector[i]
+ *             label = unicode(TDConvert(arc.label), 'utf8')             # <<<<<<<<<<<<<<
+ *             arcs.append((label, arc.cost, arc.dist2next))
+ *         return tuple(arcs)
+ */
+    __pyx_t_4 = PyBytes_FromString(TD::Convert(__pyx_v_arc->label)); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 28; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(((PyObject *)__pyx_t_4));
+    __pyx_t_7 = PyTuple_New(2); if (unlikely(!__pyx_t_7)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 28; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_7);
+    PyTuple_SET_ITEM(__pyx_t_7, 0, ((PyObject *)__pyx_t_4));
+    __Pyx_GIVEREF(((PyObject *)__pyx_t_4));
+    __Pyx_INCREF(((PyObject *)__pyx_n_s__utf8));
+    PyTuple_SET_ITEM(__pyx_t_7, 1, ((PyObject *)__pyx_n_s__utf8));
+    __Pyx_GIVEREF(((PyObject *)__pyx_n_s__utf8));
+    __pyx_t_4 = 0;
+    __pyx_t_4 = PyObject_Call(((PyObject *)((PyObject*)(&PyUnicode_Type))), ((PyObject *)__pyx_t_7), NULL); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 28; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_4);
+    __Pyx_DECREF(((PyObject *)__pyx_t_7)); __pyx_t_7 = 0;
+    __Pyx_XDECREF(((PyObject *)__pyx_v_label));
+    __pyx_v_label = ((PyObject*)__pyx_t_4);
+    __pyx_t_4 = 0;
+
+    /* "/Users/vchahun/Sandbox/cdec/python/src/lattice.pxi":29
+ *             arc = &arc_vector[i]
+ *             label = unicode(TDConvert(arc.label), 'utf8')
+ *             arcs.append((label, arc.cost, arc.dist2next))             # <<<<<<<<<<<<<<
+ *         return tuple(arcs)
+ * 
+ */
+    __pyx_t_4 = PyFloat_FromDouble(__pyx_v_arc->cost); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 29; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_4);
+    __pyx_t_7 = PyInt_FromLong(__pyx_v_arc->dist2next); if (unlikely(!__pyx_t_7)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 29; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_7);
+    __pyx_t_8 = PyTuple_New(3); if (unlikely(!__pyx_t_8)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 29; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_8);
+    __Pyx_INCREF(((PyObject *)__pyx_v_label));
+    PyTuple_SET_ITEM(__pyx_t_8, 0, ((PyObject *)__pyx_v_label));
+    __Pyx_GIVEREF(((PyObject *)__pyx_v_label));
+    PyTuple_SET_ITEM(__pyx_t_8, 1, __pyx_t_4);
+    __Pyx_GIVEREF(__pyx_t_4);
+    PyTuple_SET_ITEM(__pyx_t_8, 2, __pyx_t_7);
+    __Pyx_GIVEREF(__pyx_t_7);
+    __pyx_t_4 = 0;
+    __pyx_t_7 = 0;
+    __pyx_t_9 = PyList_Append(__pyx_v_arcs, ((PyObject *)__pyx_t_8)); if (unlikely(__pyx_t_9 == -1)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 29; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_DECREF(((PyObject *)__pyx_t_8)); __pyx_t_8 = 0;
   }
 
+  /* "/Users/vchahun/Sandbox/cdec/python/src/lattice.pxi":30
+ *             label = unicode(TDConvert(arc.label), 'utf8')
+ *             arcs.append((label, arc.cost, arc.dist2next))
+ *         return tuple(arcs)             # <<<<<<<<<<<<<<
+ * 
+ *     def __setitem__(self, int index, tuple arcs):
+ */
+  __Pyx_XDECREF(__pyx_r);
+  __pyx_t_8 = ((PyObject *)PyList_AsTuple(__pyx_v_arcs)); if (unlikely(!__pyx_t_8)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 30; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(((PyObject *)__pyx_t_8));
+  __pyx_r = ((PyObject *)__pyx_t_8);
+  __pyx_t_8 = 0;
+  goto __pyx_L0;
+
   __pyx_r = Py_None; __Pyx_INCREF(Py_None);
   goto __pyx_L0;
   __pyx_L1_error:;
-  __Pyx_AddTraceback("_cdec.CandidateSet.__iter__", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __Pyx_XDECREF(__pyx_t_4);
+  __Pyx_XDECREF(__pyx_t_7);
+  __Pyx_XDECREF(__pyx_t_8);
+  __Pyx_AddTraceback("_cdec.Lattice.__getitem__", __pyx_clineno, __pyx_lineno, __pyx_filename);
   __pyx_r = NULL;
   __pyx_L0:;
-  __Pyx_DECREF(((PyObject *)__pyx_cur_scope));
+  __Pyx_XDECREF(__pyx_v_arcs);
+  __Pyx_XDECREF(__pyx_v_label);
   __Pyx_XGIVEREF(__pyx_r);
   __Pyx_RefNannyFinishContext();
   return __pyx_r;
 }
 
-static PyObject *__pyx_gb_5_cdec_12CandidateSet_10generator13(__pyx_GeneratorObject *__pyx_generator, PyObject *__pyx_sent_value) /* generator body */
-{
-  struct __pyx_obj_5_cdec___pyx_scope_struct_19___iter__ *__pyx_cur_scope = ((struct __pyx_obj_5_cdec___pyx_scope_struct_19___iter__ *)__pyx_generator->closure);
-  PyObject *__pyx_r = NULL;
-  Py_ssize_t __pyx_t_1;
-  unsigned int __pyx_t_2;
-  PyObject *__pyx_t_3 = NULL;
+/* Python wrapper */
+static int __pyx_pw_5_cdec_7Lattice_5__setitem__(PyObject *__pyx_v_self, PyObject *__pyx_arg_index, PyObject *__pyx_v_arcs); /*proto*/
+static int __pyx_pw_5_cdec_7Lattice_5__setitem__(PyObject *__pyx_v_self, PyObject *__pyx_arg_index, PyObject *__pyx_v_arcs) {
+  int __pyx_v_index;
+  int __pyx_r;
   __Pyx_RefNannyDeclarations
-  __Pyx_RefNannySetupContext("None", 0);
-  switch (__pyx_generator->resume_label) {
-    case 0: goto __pyx_L3_first_run;
-    case 1: goto __pyx_L6_resume_from_yield;
-    default: /* CPython raises the right error here */
-    __Pyx_RefNannyFinishContext();
-    return NULL;
-  }
-  __pyx_L3_first_run:;
-  if (unlikely(!__pyx_sent_value)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 85; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-
-  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":87
- *     def __iter__(self):
- *         cdef unsigned i
- *         for i in range(len(self)):             # <<<<<<<<<<<<<<
- *             yield self[i]
- * 
- */
-  __pyx_t_1 = PyObject_Length(((PyObject *)__pyx_cur_scope->__pyx_v_self)); if (unlikely(__pyx_t_1 == -1)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 87; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  for (__pyx_t_2 = 0; __pyx_t_2 < __pyx_t_1; __pyx_t_2+=1) {
-    __pyx_cur_scope->__pyx_v_i = __pyx_t_2;
-
-    /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":88
- *         cdef unsigned i
- *         for i in range(len(self)):
- *             yield self[i]             # <<<<<<<<<<<<<<
- * 
- *     def add_kbest(self, Hypergraph hypergraph, unsigned k):
- */
-    __pyx_t_3 = __Pyx_GetItemInt(((PyObject *)__pyx_cur_scope->__pyx_v_self), __pyx_cur_scope->__pyx_v_i, sizeof(unsigned int)+1, PyLong_FromUnsignedLong); if (!__pyx_t_3) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 88; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-    __Pyx_GOTREF(__pyx_t_3);
-    __pyx_r = __pyx_t_3;
-    __pyx_t_3 = 0;
-    __pyx_cur_scope->__pyx_t_0 = __pyx_t_1;
-    __pyx_cur_scope->__pyx_t_1 = __pyx_t_2;
-    __Pyx_XGIVEREF(__pyx_r);
-    __Pyx_RefNannyFinishContext();
-    /* return from generator, yielding value */
-    __pyx_generator->resume_label = 1;
-    return __pyx_r;
-    __pyx_L6_resume_from_yield:;
-    __pyx_t_1 = __pyx_cur_scope->__pyx_t_0;
-    __pyx_t_2 = __pyx_cur_scope->__pyx_t_1;
-    if (unlikely(!__pyx_sent_value)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 88; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_RefNannySetupContext("__setitem__ (wrapper)", 0);
+  assert(__pyx_arg_index); {
+    __pyx_v_index = __Pyx_PyInt_AsInt(__pyx_arg_index); if (unlikely((__pyx_v_index == (int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 32; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
   }
-  PyErr_SetNone(PyExc_StopIteration);
+  goto __pyx_L4_argument_unpacking_done;
+  __pyx_L3_error:;
+  __Pyx_AddTraceback("_cdec.Lattice.__setitem__", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __Pyx_RefNannyFinishContext();
+  return -1;
+  __pyx_L4_argument_unpacking_done:;
+  if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_arcs), (&PyTuple_Type), 1, "arcs", 1))) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 32; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_r = __pyx_pf_5_cdec_7Lattice_4__setitem__(((struct __pyx_obj_5_cdec_Lattice *)__pyx_v_self), ((int)__pyx_v_index), ((PyObject*)__pyx_v_arcs));
   goto __pyx_L0;
   __pyx_L1_error:;
-  __Pyx_XDECREF(__pyx_t_3);
-  __Pyx_AddTraceback("__iter__", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __pyx_r = -1;
   __pyx_L0:;
-  __Pyx_XDECREF(__pyx_r);
-  __pyx_generator->resume_label = -1;
   __Pyx_RefNannyFinishContext();
-  return NULL;
+  return __pyx_r;
 }
 
-/* Python wrapper */
-static PyObject *__pyx_pw_5_cdec_12CandidateSet_12add_kbest(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/
-static PyObject *__pyx_pw_5_cdec_12CandidateSet_12add_kbest(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) {
-  struct __pyx_obj_5_cdec_Hypergraph *__pyx_v_hypergraph = 0;
-  unsigned int __pyx_v_k;
-  static PyObject **__pyx_pyargnames[] = {&__pyx_n_s__hypergraph,&__pyx_n_s__k,0};
-  PyObject *__pyx_r = 0;
+/* "/Users/vchahun/Sandbox/cdec/python/src/lattice.pxi":32
+ *         return tuple(arcs)
+ * 
+ *     def __setitem__(self, int index, tuple arcs):             # <<<<<<<<<<<<<<
+ *         if not 0 <= index < len(self):
+ *             raise IndexError('lattice index out of range')
+ */
+
+static int __pyx_pf_5_cdec_7Lattice_4__setitem__(struct __pyx_obj_5_cdec_Lattice *__pyx_v_self, int __pyx_v_index, PyObject *__pyx_v_arcs) {
+  LatticeArc *__pyx_v_arc;
+  PyObject *__pyx_v_label = NULL;
+  PyObject *__pyx_v_cost = NULL;
+  PyObject *__pyx_v_dist2next = NULL;
+  int __pyx_r;
   __Pyx_RefNannyDeclarations
-  __Pyx_RefNannySetupContext("add_kbest (wrapper)", 0);
-  {
-    PyObject* values[2] = {0,0};
-    if (unlikely(__pyx_kwds)) {
-      Py_ssize_t kw_args;
-      const Py_ssize_t pos_args = PyTuple_GET_SIZE(__pyx_args);
-      switch (pos_args) {
-        case  2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1);
-        case  1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0);
-        case  0: break;
-        default: goto __pyx_L5_argtuple_error;
-      }
-      kw_args = PyDict_Size(__pyx_kwds);
-      switch (pos_args) {
-        case  0:
-        values[0] = PyDict_GetItem(__pyx_kwds, __pyx_n_s__hypergraph);
-        if (likely(values[0])) kw_args--;
-        else goto __pyx_L5_argtuple_error;
-        case  1:
-        values[1] = PyDict_GetItem(__pyx_kwds, __pyx_n_s__k);
-        if (likely(values[1])) kw_args--;
-        else {
-          __Pyx_RaiseArgtupleInvalid("add_kbest", 1, 2, 2, 1); {__pyx_filename = __pyx_f[5]; __pyx_lineno = 90; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+  int __pyx_t_1;
+  Py_ssize_t __pyx_t_2;
+  int __pyx_t_3;
+  PyObject *__pyx_t_4 = NULL;
+  PyObject *__pyx_t_5 = NULL;
+  PyObject *__pyx_t_6 = NULL;
+  PyObject *__pyx_t_7 = NULL;
+  PyObject *__pyx_t_8 = NULL;
+  PyObject *__pyx_t_9 = NULL;
+  PyObject *(*__pyx_t_10)(PyObject *);
+  char *__pyx_t_11;
+  double __pyx_t_12;
+  int __pyx_t_13;
+  int __pyx_lineno = 0;
+  const char *__pyx_filename = NULL;
+  int __pyx_clineno = 0;
+  __Pyx_RefNannySetupContext("__setitem__", 0);
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/lattice.pxi":33
+ * 
+ *     def __setitem__(self, int index, tuple arcs):
+ *         if not 0 <= index < len(self):             # <<<<<<<<<<<<<<
+ *             raise IndexError('lattice index out of range')
+ *         cdef lattice.LatticeArc* arc
+ */
+  __pyx_t_1 = (0 <= __pyx_v_index);
+  if (__pyx_t_1) {
+    __pyx_t_2 = PyObject_Length(((PyObject *)__pyx_v_self)); if (unlikely(__pyx_t_2 == -1)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 33; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_t_1 = (__pyx_v_index < __pyx_t_2);
+  }
+  __pyx_t_3 = (!__pyx_t_1);
+  if (__pyx_t_3) {
+
+    /* "/Users/vchahun/Sandbox/cdec/python/src/lattice.pxi":34
+ *     def __setitem__(self, int index, tuple arcs):
+ *         if not 0 <= index < len(self):
+ *             raise IndexError('lattice index out of range')             # <<<<<<<<<<<<<<
+ *         cdef lattice.LatticeArc* arc
+ *         for (label, cost, dist2next) in arcs:
+ */
+    __pyx_t_4 = PyObject_Call(__pyx_builtin_IndexError, ((PyObject *)__pyx_k_tuple_25), NULL); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 34; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_4);
+    __Pyx_Raise(__pyx_t_4, 0, 0, 0);
+    __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
+    {__pyx_filename = __pyx_f[4]; __pyx_lineno = 34; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    goto __pyx_L3;
+  }
+  __pyx_L3:;
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/lattice.pxi":36
+ *             raise IndexError('lattice index out of range')
+ *         cdef lattice.LatticeArc* arc
+ *         for (label, cost, dist2next) in arcs:             # <<<<<<<<<<<<<<
+ *             if isinstance(label, unicode):
+ *                 label = label.encode('utf8')
+ */
+  if (unlikely(((PyObject *)__pyx_v_arcs) == Py_None)) {
+    PyErr_SetString(PyExc_TypeError, "'NoneType' object is not iterable"); {__pyx_filename = __pyx_f[4]; __pyx_lineno = 36; __pyx_clineno = __LINE__; goto __pyx_L1_error;} 
+  }
+  __pyx_t_4 = ((PyObject *)__pyx_v_arcs); __Pyx_INCREF(__pyx_t_4); __pyx_t_2 = 0;
+  for (;;) {
+    if (__pyx_t_2 >= PyTuple_GET_SIZE(__pyx_t_4)) break;
+    __pyx_t_5 = PyTuple_GET_ITEM(__pyx_t_4, __pyx_t_2); __Pyx_INCREF(__pyx_t_5); __pyx_t_2++;
+    if ((likely(PyTuple_CheckExact(__pyx_t_5))) || (PyList_CheckExact(__pyx_t_5))) {
+      PyObject* sequence = __pyx_t_5;
+      if (likely(PyTuple_CheckExact(sequence))) {
+        if (unlikely(PyTuple_GET_SIZE(sequence) != 3)) {
+          if (PyTuple_GET_SIZE(sequence) > 3) __Pyx_RaiseTooManyValuesError(3);
+          else __Pyx_RaiseNeedMoreValuesError(PyTuple_GET_SIZE(sequence));
+          {__pyx_filename = __pyx_f[4]; __pyx_lineno = 36; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
         }
+        __pyx_t_6 = PyTuple_GET_ITEM(sequence, 0); 
+        __pyx_t_7 = PyTuple_GET_ITEM(sequence, 1); 
+        __pyx_t_8 = PyTuple_GET_ITEM(sequence, 2); 
+      } else {
+        if (unlikely(PyList_GET_SIZE(sequence) != 3)) {
+          if (PyList_GET_SIZE(sequence) > 3) __Pyx_RaiseTooManyValuesError(3);
+          else __Pyx_RaiseNeedMoreValuesError(PyList_GET_SIZE(sequence));
+          {__pyx_filename = __pyx_f[4]; __pyx_lineno = 36; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+        }
+        __pyx_t_6 = PyList_GET_ITEM(sequence, 0); 
+        __pyx_t_7 = PyList_GET_ITEM(sequence, 1); 
+        __pyx_t_8 = PyList_GET_ITEM(sequence, 2); 
       }
-      if (unlikely(kw_args > 0)) {
-        if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "add_kbest") < 0)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 90; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
-      }
-    } else if (PyTuple_GET_SIZE(__pyx_args) != 2) {
-      goto __pyx_L5_argtuple_error;
+      __Pyx_INCREF(__pyx_t_6);
+      __Pyx_INCREF(__pyx_t_7);
+      __Pyx_INCREF(__pyx_t_8);
+      __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
     } else {
-      values[0] = PyTuple_GET_ITEM(__pyx_args, 0);
-      values[1] = PyTuple_GET_ITEM(__pyx_args, 1);
+      Py_ssize_t index = -1;
+      __pyx_t_9 = PyObject_GetIter(__pyx_t_5); if (unlikely(!__pyx_t_9)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 36; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __Pyx_GOTREF(__pyx_t_9);
+      __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
+      __pyx_t_10 = Py_TYPE(__pyx_t_9)->tp_iternext;
+      index = 0; __pyx_t_6 = __pyx_t_10(__pyx_t_9); if (unlikely(!__pyx_t_6)) goto __pyx_L6_unpacking_failed;
+      __Pyx_GOTREF(__pyx_t_6);
+      index = 1; __pyx_t_7 = __pyx_t_10(__pyx_t_9); if (unlikely(!__pyx_t_7)) goto __pyx_L6_unpacking_failed;
+      __Pyx_GOTREF(__pyx_t_7);
+      index = 2; __pyx_t_8 = __pyx_t_10(__pyx_t_9); if (unlikely(!__pyx_t_8)) goto __pyx_L6_unpacking_failed;
+      __Pyx_GOTREF(__pyx_t_8);
+      if (__Pyx_IternextUnpackEndCheck(__pyx_t_10(__pyx_t_9), 3) < 0) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 36; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0;
+      goto __pyx_L7_unpacking_done;
+      __pyx_L6_unpacking_failed:;
+      __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0;
+      if (PyErr_Occurred() && PyErr_ExceptionMatches(PyExc_StopIteration)) PyErr_Clear();
+      if (!PyErr_Occurred()) __Pyx_RaiseNeedMoreValuesError(index);
+      {__pyx_filename = __pyx_f[4]; __pyx_lineno = 36; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __pyx_L7_unpacking_done:;
     }
-    __pyx_v_hypergraph = ((struct __pyx_obj_5_cdec_Hypergraph *)values[0]);
-    __pyx_v_k = __Pyx_PyInt_AsUnsignedInt(values[1]); if (unlikely((__pyx_v_k == (unsigned int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 90; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+    __Pyx_XDECREF(__pyx_v_label);
+    __pyx_v_label = __pyx_t_6;
+    __pyx_t_6 = 0;
+    __Pyx_XDECREF(__pyx_v_cost);
+    __pyx_v_cost = __pyx_t_7;
+    __pyx_t_7 = 0;
+    __Pyx_XDECREF(__pyx_v_dist2next);
+    __pyx_v_dist2next = __pyx_t_8;
+    __pyx_t_8 = 0;
+
+    /* "/Users/vchahun/Sandbox/cdec/python/src/lattice.pxi":37
+ *         cdef lattice.LatticeArc* arc
+ *         for (label, cost, dist2next) in arcs:
+ *             if isinstance(label, unicode):             # <<<<<<<<<<<<<<
+ *                 label = label.encode('utf8')
+ *             arc = new lattice.LatticeArc(TDConvert(<char *>label), cost, dist2next)
+ */
+    __pyx_t_5 = ((PyObject *)((PyObject*)(&PyUnicode_Type)));
+    __Pyx_INCREF(__pyx_t_5);
+    __pyx_t_3 = __Pyx_TypeCheck(__pyx_v_label, __pyx_t_5); 
+    __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
+    if (__pyx_t_3) {
+
+      /* "/Users/vchahun/Sandbox/cdec/python/src/lattice.pxi":38
+ *         for (label, cost, dist2next) in arcs:
+ *             if isinstance(label, unicode):
+ *                 label = label.encode('utf8')             # <<<<<<<<<<<<<<
+ *             arc = new lattice.LatticeArc(TDConvert(<char *>label), cost, dist2next)
+ *             self.lattice[0][index].push_back(arc[0])
+ */
+      __pyx_t_5 = PyObject_GetAttr(__pyx_v_label, __pyx_n_s__encode); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 38; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __Pyx_GOTREF(__pyx_t_5);
+      __pyx_t_8 = PyObject_Call(__pyx_t_5, ((PyObject *)__pyx_k_tuple_26), NULL); if (unlikely(!__pyx_t_8)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 38; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __Pyx_GOTREF(__pyx_t_8);
+      __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
+      __Pyx_DECREF(__pyx_v_label);
+      __pyx_v_label = __pyx_t_8;
+      __pyx_t_8 = 0;
+      goto __pyx_L8;
+    }
+    __pyx_L8:;
+
+    /* "/Users/vchahun/Sandbox/cdec/python/src/lattice.pxi":39
+ *             if isinstance(label, unicode):
+ *                 label = label.encode('utf8')
+ *             arc = new lattice.LatticeArc(TDConvert(<char *>label), cost, dist2next)             # <<<<<<<<<<<<<<
+ *             self.lattice[0][index].push_back(arc[0])
+ *             del arc
+ */
+    __pyx_t_11 = PyBytes_AsString(__pyx_v_label); if (unlikely((!__pyx_t_11) && PyErr_Occurred())) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 39; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_t_12 = __pyx_PyFloat_AsDouble(__pyx_v_cost); if (unlikely((__pyx_t_12 == (double)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 39; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_t_13 = __Pyx_PyInt_AsInt(__pyx_v_dist2next); if (unlikely((__pyx_t_13 == (int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 39; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_v_arc = new LatticeArc(TD::Convert(((char *)__pyx_t_11)), __pyx_t_12, __pyx_t_13);
+
+    /* "/Users/vchahun/Sandbox/cdec/python/src/lattice.pxi":40
+ *                 label = label.encode('utf8')
+ *             arc = new lattice.LatticeArc(TDConvert(<char *>label), cost, dist2next)
+ *             self.lattice[0][index].push_back(arc[0])             # <<<<<<<<<<<<<<
+ *             del arc
+ * 
+ */
+    ((__pyx_v_self->lattice[0])[__pyx_v_index]).push_back((__pyx_v_arc[0]));
+
+    /* "/Users/vchahun/Sandbox/cdec/python/src/lattice.pxi":41
+ *             arc = new lattice.LatticeArc(TDConvert(<char *>label), cost, dist2next)
+ *             self.lattice[0][index].push_back(arc[0])
+ *             del arc             # <<<<<<<<<<<<<<
+ * 
+ *     def __len__(self):
+ */
+    delete __pyx_v_arc;
   }
-  goto __pyx_L4_argument_unpacking_done;
-  __pyx_L5_argtuple_error:;
-  __Pyx_RaiseArgtupleInvalid("add_kbest", 1, 2, 2, PyTuple_GET_SIZE(__pyx_args)); {__pyx_filename = __pyx_f[5]; __pyx_lineno = 90; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
-  __pyx_L3_error:;
-  __Pyx_AddTraceback("_cdec.CandidateSet.add_kbest", __pyx_clineno, __pyx_lineno, __pyx_filename);
-  __Pyx_RefNannyFinishContext();
-  return NULL;
-  __pyx_L4_argument_unpacking_done:;
-  if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_hypergraph), __pyx_ptype_5_cdec_Hypergraph, 1, "hypergraph", 0))) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 90; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __pyx_r = __pyx_pf_5_cdec_12CandidateSet_11add_kbest(((struct __pyx_obj_5_cdec_CandidateSet *)__pyx_v_self), __pyx_v_hypergraph, __pyx_v_k);
+  __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
+
+  __pyx_r = 0;
   goto __pyx_L0;
   __pyx_L1_error:;
-  __pyx_r = NULL;
+  __Pyx_XDECREF(__pyx_t_4);
+  __Pyx_XDECREF(__pyx_t_5);
+  __Pyx_XDECREF(__pyx_t_6);
+  __Pyx_XDECREF(__pyx_t_7);
+  __Pyx_XDECREF(__pyx_t_8);
+  __Pyx_XDECREF(__pyx_t_9);
+  __Pyx_AddTraceback("_cdec.Lattice.__setitem__", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __pyx_r = -1;
   __pyx_L0:;
+  __Pyx_XDECREF(__pyx_v_label);
+  __Pyx_XDECREF(__pyx_v_cost);
+  __Pyx_XDECREF(__pyx_v_dist2next);
   __Pyx_RefNannyFinishContext();
   return __pyx_r;
 }
 
-/* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":90
- *             yield self[i]
+/* Python wrapper */
+static Py_ssize_t __pyx_pw_5_cdec_7Lattice_7__len__(PyObject *__pyx_v_self); /*proto*/
+static Py_ssize_t __pyx_pw_5_cdec_7Lattice_7__len__(PyObject *__pyx_v_self) {
+  Py_ssize_t __pyx_r;
+  __Pyx_RefNannyDeclarations
+  __Pyx_RefNannySetupContext("__len__ (wrapper)", 0);
+  __pyx_r = __pyx_pf_5_cdec_7Lattice_6__len__(((struct __pyx_obj_5_cdec_Lattice *)__pyx_v_self));
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+/* "/Users/vchahun/Sandbox/cdec/python/src/lattice.pxi":43
+ *             del arc
  * 
- *     def add_kbest(self, Hypergraph hypergraph, unsigned k):             # <<<<<<<<<<<<<<
- *         self.cs.AddKBestCandidates(hypergraph.hg[0], k, self.scorer.get())
+ *     def __len__(self):             # <<<<<<<<<<<<<<
+ *         return self.lattice.size()
  * 
  */
 
-static PyObject *__pyx_pf_5_cdec_12CandidateSet_11add_kbest(struct __pyx_obj_5_cdec_CandidateSet *__pyx_v_self, struct __pyx_obj_5_cdec_Hypergraph *__pyx_v_hypergraph, unsigned int __pyx_v_k) {
-  PyObject *__pyx_r = NULL;
+static Py_ssize_t __pyx_pf_5_cdec_7Lattice_6__len__(struct __pyx_obj_5_cdec_Lattice *__pyx_v_self) {
+  Py_ssize_t __pyx_r;
   __Pyx_RefNannyDeclarations
-  __Pyx_RefNannySetupContext("add_kbest", 0);
+  __Pyx_RefNannySetupContext("__len__", 0);
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":91
+  /* "/Users/vchahun/Sandbox/cdec/python/src/lattice.pxi":44
  * 
- *     def add_kbest(self, Hypergraph hypergraph, unsigned k):
- *         self.cs.AddKBestCandidates(hypergraph.hg[0], k, self.scorer.get())             # <<<<<<<<<<<<<<
+ *     def __len__(self):
+ *         return self.lattice.size()             # <<<<<<<<<<<<<<
  * 
- * cdef class SegmentEvaluator:
+ *     def __str__(self):
  */
-  __pyx_v_self->cs->AddKBestCandidates((__pyx_v_hypergraph->hg[0]), __pyx_v_k, __pyx_v_self->scorer->get());
+  __pyx_r = __pyx_v_self->lattice->size();
+  goto __pyx_L0;
 
-  __pyx_r = Py_None; __Pyx_INCREF(Py_None);
-  __Pyx_XGIVEREF(__pyx_r);
+  __pyx_r = 0;
+  __pyx_L0:;
   __Pyx_RefNannyFinishContext();
   return __pyx_r;
 }
 
 /* Python wrapper */
-static void __pyx_pw_5_cdec_16SegmentEvaluator_1__dealloc__(PyObject *__pyx_v_self); /*proto*/
-static void __pyx_pw_5_cdec_16SegmentEvaluator_1__dealloc__(PyObject *__pyx_v_self) {
-  __Pyx_RefNannyDeclarations
-  __Pyx_RefNannySetupContext("__dealloc__ (wrapper)", 0);
-  __pyx_pf_5_cdec_16SegmentEvaluator___dealloc__(((struct __pyx_obj_5_cdec_SegmentEvaluator *)__pyx_v_self));
-  __Pyx_RefNannyFinishContext();
-}
-
-/* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":97
- *     cdef mteval.EvaluationMetric* metric
- * 
- *     def __dealloc__(self):             # <<<<<<<<<<<<<<
- *         del self.scorer
- * 
- */
-
-static void __pyx_pf_5_cdec_16SegmentEvaluator___dealloc__(CYTHON_UNUSED struct __pyx_obj_5_cdec_SegmentEvaluator *__pyx_v_self) {
-  __Pyx_RefNannyDeclarations
-  __Pyx_RefNannySetupContext("__dealloc__", 0);
-
-  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":98
- * 
- *     def __dealloc__(self):
- *         del self.scorer             # <<<<<<<<<<<<<<
- * 
- *     def evaluate(self, sentence):
- */
-  delete __pyx_v_self->scorer;
-
-  __Pyx_RefNannyFinishContext();
-}
-
-/* Python wrapper */
-static PyObject *__pyx_pw_5_cdec_16SegmentEvaluator_3evaluate(PyObject *__pyx_v_self, PyObject *__pyx_v_sentence); /*proto*/
-static PyObject *__pyx_pw_5_cdec_16SegmentEvaluator_3evaluate(PyObject *__pyx_v_self, PyObject *__pyx_v_sentence) {
+static PyObject *__pyx_pw_5_cdec_7Lattice_9__str__(PyObject *__pyx_v_self); /*proto*/
+static PyObject *__pyx_pw_5_cdec_7Lattice_9__str__(PyObject *__pyx_v_self) {
   PyObject *__pyx_r = 0;
   __Pyx_RefNannyDeclarations
-  __Pyx_RefNannySetupContext("evaluate (wrapper)", 0);
-  __pyx_r = __pyx_pf_5_cdec_16SegmentEvaluator_2evaluate(((struct __pyx_obj_5_cdec_SegmentEvaluator *)__pyx_v_self), ((PyObject *)__pyx_v_sentence));
+  __Pyx_RefNannySetupContext("__str__ (wrapper)", 0);
+  __pyx_r = __pyx_pf_5_cdec_7Lattice_8__str__(((struct __pyx_obj_5_cdec_Lattice *)__pyx_v_self));
   __Pyx_RefNannyFinishContext();
   return __pyx_r;
 }
 
-/* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":100
- *         del self.scorer
+/* "/Users/vchahun/Sandbox/cdec/python/src/lattice.pxi":46
+ *         return self.lattice.size()
+ * 
+ *     def __str__(self):             # <<<<<<<<<<<<<<
+ *         return hypergraph.AsPLF(self.lattice[0], True).c_str()
  * 
- *     def evaluate(self, sentence):             # <<<<<<<<<<<<<<
- *         cdef vector[WordID] hyp
- *         cdef SufficientStats sf = SufficientStats()
  */
 
-static PyObject *__pyx_pf_5_cdec_16SegmentEvaluator_2evaluate(struct __pyx_obj_5_cdec_SegmentEvaluator *__pyx_v_self, PyObject *__pyx_v_sentence) {
-  std::vector<WordID> __pyx_v_hyp;
-  struct __pyx_obj_5_cdec_SufficientStats *__pyx_v_sf = 0;
+static PyObject *__pyx_pf_5_cdec_7Lattice_8__str__(struct __pyx_obj_5_cdec_Lattice *__pyx_v_self) {
   PyObject *__pyx_r = NULL;
   __Pyx_RefNannyDeclarations
   PyObject *__pyx_t_1 = NULL;
-  PyObject *__pyx_t_2 = NULL;
   int __pyx_lineno = 0;
   const char *__pyx_filename = NULL;
   int __pyx_clineno = 0;
-  __Pyx_RefNannySetupContext("evaluate", 0);
-
-  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":102
- *     def evaluate(self, sentence):
- *         cdef vector[WordID] hyp
- *         cdef SufficientStats sf = SufficientStats()             # <<<<<<<<<<<<<<
- *         sf.metric = self.metric
- *         sf.stats = new mteval.SufficientStats()
- */
-  __pyx_t_1 = PyObject_Call(((PyObject *)((PyObject*)__pyx_ptype_5_cdec_SufficientStats)), ((PyObject *)__pyx_empty_tuple), NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 102; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __Pyx_GOTREF(__pyx_t_1);
-  __pyx_v_sf = ((struct __pyx_obj_5_cdec_SufficientStats *)__pyx_t_1);
-  __pyx_t_1 = 0;
-
-  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":103
- *         cdef vector[WordID] hyp
- *         cdef SufficientStats sf = SufficientStats()
- *         sf.metric = self.metric             # <<<<<<<<<<<<<<
- *         sf.stats = new mteval.SufficientStats()
- *         ConvertSentence(string(as_str(sentence.strip())), &hyp)
- */
-  __pyx_v_sf->metric = __pyx_v_self->metric;
-
-  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":104
- *         cdef SufficientStats sf = SufficientStats()
- *         sf.metric = self.metric
- *         sf.stats = new mteval.SufficientStats()             # <<<<<<<<<<<<<<
- *         ConvertSentence(string(as_str(sentence.strip())), &hyp)
- *         self.scorer.get().Evaluate(hyp, sf.stats)
- */
-  __pyx_v_sf->stats = new SufficientStats();
-
-  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":105
- *         sf.metric = self.metric
- *         sf.stats = new mteval.SufficientStats()
- *         ConvertSentence(string(as_str(sentence.strip())), &hyp)             # <<<<<<<<<<<<<<
- *         self.scorer.get().Evaluate(hyp, sf.stats)
- *         return sf
- */
-  __pyx_t_1 = PyObject_GetAttr(__pyx_v_sentence, __pyx_n_s__strip); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 105; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __Pyx_GOTREF(__pyx_t_1);
-  __pyx_t_2 = PyObject_Call(__pyx_t_1, ((PyObject *)__pyx_empty_tuple), NULL); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 105; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __Pyx_GOTREF(__pyx_t_2);
-  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
-  TD::ConvertSentence(std::string(__pyx_f_5_cdec_as_str(__pyx_t_2, NULL)), (&__pyx_v_hyp));
-  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+  __Pyx_RefNannySetupContext("__str__", 0);
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":106
- *         sf.stats = new mteval.SufficientStats()
- *         ConvertSentence(string(as_str(sentence.strip())), &hyp)
- *         self.scorer.get().Evaluate(hyp, sf.stats)             # <<<<<<<<<<<<<<
- *         return sf
+  /* "/Users/vchahun/Sandbox/cdec/python/src/lattice.pxi":47
  * 
- */
-  __pyx_v_self->scorer->get()->Evaluate(__pyx_v_hyp, __pyx_v_sf->stats);
-
-  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":107
- *         ConvertSentence(string(as_str(sentence.strip())), &hyp)
- *         self.scorer.get().Evaluate(hyp, sf.stats)
- *         return sf             # <<<<<<<<<<<<<<
+ *     def __str__(self):
+ *         return hypergraph.AsPLF(self.lattice[0], True).c_str()             # <<<<<<<<<<<<<<
  * 
- *     def candidate_set(self):
+ *     def __iter__(self):
  */
   __Pyx_XDECREF(__pyx_r);
-  __Pyx_INCREF(((PyObject *)__pyx_v_sf));
-  __pyx_r = ((PyObject *)__pyx_v_sf);
+  __pyx_t_1 = PyBytes_FromString(HypergraphIO::AsPLF((__pyx_v_self->lattice[0]), 1).c_str()); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 47; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(((PyObject *)__pyx_t_1));
+  __pyx_r = ((PyObject *)__pyx_t_1);
+  __pyx_t_1 = 0;
   goto __pyx_L0;
 
   __pyx_r = Py_None; __Pyx_INCREF(Py_None);
   goto __pyx_L0;
   __pyx_L1_error:;
   __Pyx_XDECREF(__pyx_t_1);
-  __Pyx_XDECREF(__pyx_t_2);
-  __Pyx_AddTraceback("_cdec.SegmentEvaluator.evaluate", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __Pyx_AddTraceback("_cdec.Lattice.__str__", __pyx_clineno, __pyx_lineno, __pyx_filename);
   __pyx_r = NULL;
   __pyx_L0:;
-  __Pyx_XDECREF((PyObject *)__pyx_v_sf);
   __Pyx_XGIVEREF(__pyx_r);
   __Pyx_RefNannyFinishContext();
   return __pyx_r;
 }
+static PyObject *__pyx_gb_5_cdec_7Lattice_12generator13(__pyx_GeneratorObject *__pyx_generator, PyObject *__pyx_sent_value); /* proto */
 
 /* Python wrapper */
-static PyObject *__pyx_pw_5_cdec_16SegmentEvaluator_5candidate_set(PyObject *__pyx_v_self, CYTHON_UNUSED PyObject *unused); /*proto*/
-static PyObject *__pyx_pw_5_cdec_16SegmentEvaluator_5candidate_set(PyObject *__pyx_v_self, CYTHON_UNUSED PyObject *unused) {
+static PyObject *__pyx_pw_5_cdec_7Lattice_11__iter__(PyObject *__pyx_v_self); /*proto*/
+static PyObject *__pyx_pw_5_cdec_7Lattice_11__iter__(PyObject *__pyx_v_self) {
   PyObject *__pyx_r = 0;
   __Pyx_RefNannyDeclarations
-  __Pyx_RefNannySetupContext("candidate_set (wrapper)", 0);
-  __pyx_r = __pyx_pf_5_cdec_16SegmentEvaluator_4candidate_set(((struct __pyx_obj_5_cdec_SegmentEvaluator *)__pyx_v_self));
+  __Pyx_RefNannySetupContext("__iter__ (wrapper)", 0);
+  __pyx_r = __pyx_pf_5_cdec_7Lattice_10__iter__(((struct __pyx_obj_5_cdec_Lattice *)__pyx_v_self));
   __Pyx_RefNannyFinishContext();
   return __pyx_r;
 }
 
-/* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":109
- *         return sf
- * 
- *     def candidate_set(self):             # <<<<<<<<<<<<<<
- *         return CandidateSet(self)
+/* "/Users/vchahun/Sandbox/cdec/python/src/lattice.pxi":49
+ *         return hypergraph.AsPLF(self.lattice[0], True).c_str()
  * 
+ *     def __iter__(self):             # <<<<<<<<<<<<<<
+ *         cdef unsigned i
+ *         for i in range(len(self)):
  */
 
-static PyObject *__pyx_pf_5_cdec_16SegmentEvaluator_4candidate_set(struct __pyx_obj_5_cdec_SegmentEvaluator *__pyx_v_self) {
+static PyObject *__pyx_pf_5_cdec_7Lattice_10__iter__(struct __pyx_obj_5_cdec_Lattice *__pyx_v_self) {
+  struct __pyx_obj_5_cdec___pyx_scope_struct_17___iter__ *__pyx_cur_scope;
   PyObject *__pyx_r = NULL;
   __Pyx_RefNannyDeclarations
-  PyObject *__pyx_t_1 = NULL;
-  PyObject *__pyx_t_2 = NULL;
   int __pyx_lineno = 0;
   const char *__pyx_filename = NULL;
   int __pyx_clineno = 0;
-  __Pyx_RefNannySetupContext("candidate_set", 0);
-
-  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":110
- * 
- *     def candidate_set(self):
- *         return CandidateSet(self)             # <<<<<<<<<<<<<<
- * 
- * cdef class Scorer:
- */
-  __Pyx_XDECREF(__pyx_r);
-  __pyx_t_1 = PyTuple_New(1); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 110; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __Pyx_GOTREF(__pyx_t_1);
-  __Pyx_INCREF(((PyObject *)__pyx_v_self));
-  PyTuple_SET_ITEM(__pyx_t_1, 0, ((PyObject *)__pyx_v_self));
-  __Pyx_GIVEREF(((PyObject *)__pyx_v_self));
-  __pyx_t_2 = PyObject_Call(((PyObject *)((PyObject*)__pyx_ptype_5_cdec_CandidateSet)), ((PyObject *)__pyx_t_1), NULL); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 110; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __Pyx_GOTREF(__pyx_t_2);
-  __Pyx_DECREF(((PyObject *)__pyx_t_1)); __pyx_t_1 = 0;
-  __pyx_r = __pyx_t_2;
-  __pyx_t_2 = 0;
-  goto __pyx_L0;
+  __Pyx_RefNannySetupContext("__iter__", 0);
+  __pyx_cur_scope = (struct __pyx_obj_5_cdec___pyx_scope_struct_17___iter__ *)__pyx_ptype_5_cdec___pyx_scope_struct_17___iter__->tp_new(__pyx_ptype_5_cdec___pyx_scope_struct_17___iter__, __pyx_empty_tuple, NULL);
+  if (unlikely(!__pyx_cur_scope)) {
+    __Pyx_RefNannyFinishContext();
+    return NULL;
+  }
+  __Pyx_GOTREF(__pyx_cur_scope);
+  __pyx_cur_scope->__pyx_v_self = __pyx_v_self;
+  __Pyx_INCREF((PyObject *)__pyx_cur_scope->__pyx_v_self);
+  __Pyx_GIVEREF((PyObject *)__pyx_cur_scope->__pyx_v_self);
+  {
+    __pyx_GeneratorObject *gen = __Pyx_Generator_New((__pyx_generator_body_t) __pyx_gb_5_cdec_7Lattice_12generator13, (PyObject *) __pyx_cur_scope); if (unlikely(!gen)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 49; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_DECREF(__pyx_cur_scope);
+    __Pyx_RefNannyFinishContext();
+    return (PyObject *) gen;
+  }
 
   __pyx_r = Py_None; __Pyx_INCREF(Py_None);
   goto __pyx_L0;
   __pyx_L1_error:;
-  __Pyx_XDECREF(__pyx_t_1);
-  __Pyx_XDECREF(__pyx_t_2);
-  __Pyx_AddTraceback("_cdec.SegmentEvaluator.candidate_set", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __Pyx_AddTraceback("_cdec.Lattice.__iter__", __pyx_clineno, __pyx_lineno, __pyx_filename);
   __pyx_r = NULL;
   __pyx_L0:;
+  __Pyx_DECREF(((PyObject *)__pyx_cur_scope));
   __Pyx_XGIVEREF(__pyx_r);
   __Pyx_RefNannyFinishContext();
   return __pyx_r;
 }
 
-/* Python wrapper */
-static int __pyx_pw_5_cdec_6Scorer_1__cinit__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/
-static int __pyx_pw_5_cdec_6Scorer_1__cinit__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) {
-  char *__pyx_v_name;
-  static PyObject **__pyx_pyargnames[] = {&__pyx_n_s__name,0};
-  int __pyx_r;
+static PyObject *__pyx_gb_5_cdec_7Lattice_12generator13(__pyx_GeneratorObject *__pyx_generator, PyObject *__pyx_sent_value) /* generator body */
+{
+  struct __pyx_obj_5_cdec___pyx_scope_struct_17___iter__ *__pyx_cur_scope = ((struct __pyx_obj_5_cdec___pyx_scope_struct_17___iter__ *)__pyx_generator->closure);
+  PyObject *__pyx_r = NULL;
+  Py_ssize_t __pyx_t_1;
+  unsigned int __pyx_t_2;
+  PyObject *__pyx_t_3 = NULL;
   __Pyx_RefNannyDeclarations
-  __Pyx_RefNannySetupContext("__cinit__ (wrapper)", 0);
-  {
-    PyObject* values[1] = {0};
-    if (unlikely(__pyx_kwds)) {
-      Py_ssize_t kw_args;
-      const Py_ssize_t pos_args = PyTuple_GET_SIZE(__pyx_args);
-      switch (pos_args) {
-        case  1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0);
-        case  0: break;
-        default: goto __pyx_L5_argtuple_error;
-      }
-      kw_args = PyDict_Size(__pyx_kwds);
-      switch (pos_args) {
-        case  0:
-        values[0] = PyDict_GetItem(__pyx_kwds, __pyx_n_s__name);
-        if (likely(values[0])) kw_args--;
-        else goto __pyx_L5_argtuple_error;
-      }
-      if (unlikely(kw_args > 0)) {
-        if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "__cinit__") < 0)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 115; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
-      }
-    } else if (PyTuple_GET_SIZE(__pyx_args) != 1) {
-      goto __pyx_L5_argtuple_error;
-    } else {
-      values[0] = PyTuple_GET_ITEM(__pyx_args, 0);
-    }
-    __pyx_v_name = PyBytes_AsString(values[0]); if (unlikely((!__pyx_v_name) && PyErr_Occurred())) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 115; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+  __Pyx_RefNannySetupContext("None", 0);
+  switch (__pyx_generator->resume_label) {
+    case 0: goto __pyx_L3_first_run;
+    case 1: goto __pyx_L6_resume_from_yield;
+    default: /* CPython raises the right error here */
+    __Pyx_RefNannyFinishContext();
+    return NULL;
   }
-  goto __pyx_L4_argument_unpacking_done;
-  __pyx_L5_argtuple_error:;
-  __Pyx_RaiseArgtupleInvalid("__cinit__", 1, 1, 1, PyTuple_GET_SIZE(__pyx_args)); {__pyx_filename = __pyx_f[5]; __pyx_lineno = 115; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
-  __pyx_L3_error:;
-  __Pyx_AddTraceback("_cdec.Scorer.__cinit__", __pyx_clineno, __pyx_lineno, __pyx_filename);
-  __Pyx_RefNannyFinishContext();
-  return -1;
-  __pyx_L4_argument_unpacking_done:;
-  __pyx_r = __pyx_pf_5_cdec_6Scorer___cinit__(((struct __pyx_obj_5_cdec_Scorer *)__pyx_v_self), __pyx_v_name);
-  __Pyx_RefNannyFinishContext();
-  return __pyx_r;
-}
+  __pyx_L3_first_run:;
+  if (unlikely(!__pyx_sent_value)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 49; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
 
-/* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":115
- *     cdef string* name
- * 
- *     def __cinit__(self, char* name):             # <<<<<<<<<<<<<<
- *         self.name = new string(name)
+  /* "/Users/vchahun/Sandbox/cdec/python/src/lattice.pxi":51
+ *     def __iter__(self):
+ *         cdef unsigned i
+ *         for i in range(len(self)):             # <<<<<<<<<<<<<<
+ *             yield self[i]
  * 
  */
+  __pyx_t_1 = PyObject_Length(((PyObject *)__pyx_cur_scope->__pyx_v_self)); if (unlikely(__pyx_t_1 == -1)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 51; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  for (__pyx_t_2 = 0; __pyx_t_2 < __pyx_t_1; __pyx_t_2+=1) {
+    __pyx_cur_scope->__pyx_v_i = __pyx_t_2;
 
-static int __pyx_pf_5_cdec_6Scorer___cinit__(struct __pyx_obj_5_cdec_Scorer *__pyx_v_self, char *__pyx_v_name) {
-  int __pyx_r;
-  __Pyx_RefNannyDeclarations
-  __Pyx_RefNannySetupContext("__cinit__", 0);
-
-  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":116
- * 
- *     def __cinit__(self, char* name):
- *         self.name = new string(name)             # <<<<<<<<<<<<<<
+    /* "/Users/vchahun/Sandbox/cdec/python/src/lattice.pxi":52
+ *         cdef unsigned i
+ *         for i in range(len(self)):
+ *             yield self[i]             # <<<<<<<<<<<<<<
  * 
  *     def __dealloc__(self):
  */
-  __pyx_v_self->name = new std::string(__pyx_v_name);
-
-  __pyx_r = 0;
+    __pyx_t_3 = __Pyx_GetItemInt(((PyObject *)__pyx_cur_scope->__pyx_v_self), __pyx_cur_scope->__pyx_v_i, sizeof(unsigned int)+1, PyLong_FromUnsignedLong); if (!__pyx_t_3) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 52; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_3);
+    __pyx_r = __pyx_t_3;
+    __pyx_t_3 = 0;
+    __pyx_cur_scope->__pyx_t_0 = __pyx_t_1;
+    __pyx_cur_scope->__pyx_t_1 = __pyx_t_2;
+    __Pyx_XGIVEREF(__pyx_r);
+    __Pyx_RefNannyFinishContext();
+    /* return from generator, yielding value */
+    __pyx_generator->resume_label = 1;
+    return __pyx_r;
+    __pyx_L6_resume_from_yield:;
+    __pyx_t_1 = __pyx_cur_scope->__pyx_t_0;
+    __pyx_t_2 = __pyx_cur_scope->__pyx_t_1;
+    if (unlikely(!__pyx_sent_value)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 52; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  }
+  PyErr_SetNone(PyExc_StopIteration);
+  goto __pyx_L0;
+  __pyx_L1_error:;
+  __Pyx_XDECREF(__pyx_t_3);
+  __Pyx_AddTraceback("__iter__", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __pyx_L0:;
+  __Pyx_XDECREF(__pyx_r);
+  __pyx_generator->resume_label = -1;
   __Pyx_RefNannyFinishContext();
-  return __pyx_r;
+  return NULL;
 }
 
 /* Python wrapper */
-static void __pyx_pw_5_cdec_6Scorer_3__dealloc__(PyObject *__pyx_v_self); /*proto*/
-static void __pyx_pw_5_cdec_6Scorer_3__dealloc__(PyObject *__pyx_v_self) {
+static void __pyx_pw_5_cdec_7Lattice_14__dealloc__(PyObject *__pyx_v_self); /*proto*/
+static void __pyx_pw_5_cdec_7Lattice_14__dealloc__(PyObject *__pyx_v_self) {
   __Pyx_RefNannyDeclarations
   __Pyx_RefNannySetupContext("__dealloc__ (wrapper)", 0);
-  __pyx_pf_5_cdec_6Scorer_2__dealloc__(((struct __pyx_obj_5_cdec_Scorer *)__pyx_v_self));
+  __pyx_pf_5_cdec_7Lattice_13__dealloc__(((struct __pyx_obj_5_cdec_Lattice *)__pyx_v_self));
   __Pyx_RefNannyFinishContext();
 }
 
-/* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":118
- *         self.name = new string(name)
+/* "/Users/vchahun/Sandbox/cdec/python/src/lattice.pxi":54
+ *             yield self[i]
  * 
  *     def __dealloc__(self):             # <<<<<<<<<<<<<<
- *         del self.name
+ *         del self.lattice
  * 
  */
 
-static void __pyx_pf_5_cdec_6Scorer_2__dealloc__(CYTHON_UNUSED struct __pyx_obj_5_cdec_Scorer *__pyx_v_self) {
+static void __pyx_pf_5_cdec_7Lattice_13__dealloc__(CYTHON_UNUSED struct __pyx_obj_5_cdec_Lattice *__pyx_v_self) {
   __Pyx_RefNannyDeclarations
   __Pyx_RefNannySetupContext("__dealloc__", 0);
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":119
+  /* "/Users/vchahun/Sandbox/cdec/python/src/lattice.pxi":55
  * 
  *     def __dealloc__(self):
- *         del self.name             # <<<<<<<<<<<<<<
+ *         del self.lattice             # <<<<<<<<<<<<<<
  * 
- *     def __call__(self, refs):
+ *     def todot(self):
  */
-  delete __pyx_v_self->name;
+  delete __pyx_v_self->lattice;
 
   __Pyx_RefNannyFinishContext();
 }
 
 /* Python wrapper */
-static PyObject *__pyx_pw_5_cdec_6Scorer_5__call__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/
-static PyObject *__pyx_pw_5_cdec_6Scorer_5__call__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) {
-  PyObject *__pyx_v_refs = 0;
-  static PyObject **__pyx_pyargnames[] = {&__pyx_n_s__refs,0};
+static PyObject *__pyx_pw_5_cdec_7Lattice_16todot(PyObject *__pyx_v_self, CYTHON_UNUSED PyObject *unused); /*proto*/
+static PyObject *__pyx_pw_5_cdec_7Lattice_16todot(PyObject *__pyx_v_self, CYTHON_UNUSED PyObject *unused) {
   PyObject *__pyx_r = 0;
   __Pyx_RefNannyDeclarations
-  __Pyx_RefNannySetupContext("__call__ (wrapper)", 0);
-  {
-    PyObject* values[1] = {0};
-    if (unlikely(__pyx_kwds)) {
-      Py_ssize_t kw_args;
-      const Py_ssize_t pos_args = PyTuple_GET_SIZE(__pyx_args);
-      switch (pos_args) {
-        case  1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0);
-        case  0: break;
-        default: goto __pyx_L5_argtuple_error;
-      }
-      kw_args = PyDict_Size(__pyx_kwds);
-      switch (pos_args) {
-        case  0:
-        values[0] = PyDict_GetItem(__pyx_kwds, __pyx_n_s__refs);
-        if (likely(values[0])) kw_args--;
-        else goto __pyx_L5_argtuple_error;
-      }
-      if (unlikely(kw_args > 0)) {
-        if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "__call__") < 0)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 121; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
-      }
-    } else if (PyTuple_GET_SIZE(__pyx_args) != 1) {
-      goto __pyx_L5_argtuple_error;
-    } else {
-      values[0] = PyTuple_GET_ITEM(__pyx_args, 0);
-    }
-    __pyx_v_refs = values[0];
-  }
-  goto __pyx_L4_argument_unpacking_done;
-  __pyx_L5_argtuple_error:;
-  __Pyx_RaiseArgtupleInvalid("__call__", 1, 1, 1, PyTuple_GET_SIZE(__pyx_args)); {__pyx_filename = __pyx_f[5]; __pyx_lineno = 121; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
-  __pyx_L3_error:;
-  __Pyx_AddTraceback("_cdec.Scorer.__call__", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __Pyx_RefNannySetupContext("todot (wrapper)", 0);
+  __pyx_r = __pyx_pf_5_cdec_7Lattice_15todot(((struct __pyx_obj_5_cdec_Lattice *)__pyx_v_self));
   __Pyx_RefNannyFinishContext();
-  return NULL;
-  __pyx_L4_argument_unpacking_done:;
-  __pyx_r = __pyx_pf_5_cdec_6Scorer_4__call__(((struct __pyx_obj_5_cdec_Scorer *)__pyx_v_self), __pyx_v_refs);
+  return __pyx_r;
+}
+static PyObject *__pyx_gb_5_cdec_7Lattice_5todot_2generator19(__pyx_GeneratorObject *__pyx_generator, PyObject *__pyx_sent_value); /* proto */
+
+/* Python wrapper */
+static PyObject *__pyx_pw_5_cdec_7Lattice_5todot_1lines(PyObject *__pyx_self, CYTHON_UNUSED PyObject *unused); /*proto*/
+static PyMethodDef __pyx_mdef_5_cdec_7Lattice_5todot_1lines = {__Pyx_NAMESTR("lines"), (PyCFunction)__pyx_pw_5_cdec_7Lattice_5todot_1lines, METH_NOARGS, __Pyx_DOCSTR(0)};
+static PyObject *__pyx_pw_5_cdec_7Lattice_5todot_1lines(PyObject *__pyx_self, CYTHON_UNUSED PyObject *unused) {
+  PyObject *__pyx_r = 0;
+  __Pyx_RefNannyDeclarations
+  __Pyx_RefNannySetupContext("lines (wrapper)", 0);
+  __pyx_self = __pyx_self;
+  __pyx_r = __pyx_pf_5_cdec_7Lattice_5todot_lines(__pyx_self);
   __Pyx_RefNannyFinishContext();
   return __pyx_r;
 }
 
-/* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":121
- *         del self.name
+/* "/Users/vchahun/Sandbox/cdec/python/src/lattice.pxi":58
  * 
- *     def __call__(self, refs):             # <<<<<<<<<<<<<<
- *         cdef mteval.EvaluationMetric* metric = mteval.Instance(self.name[0])
- *         if isinstance(refs, unicode) or isinstance(refs, str):
+ *     def todot(self):
+ *         def lines():             # <<<<<<<<<<<<<<
+ *             yield 'digraph lattice {'
+ *             yield 'rankdir = LR;'
  */
 
-static PyObject *__pyx_pf_5_cdec_6Scorer_4__call__(struct __pyx_obj_5_cdec_Scorer *__pyx_v_self, PyObject *__pyx_v_refs) {
-  EvaluationMetric *__pyx_v_metric;
-  std::vector<std::vector<WordID> > *__pyx_v_refsv;
-  std::vector<WordID> *__pyx_v_refv;
-  PyObject *__pyx_v_ref = NULL;
-  struct __pyx_obj_5_cdec_SegmentEvaluator *__pyx_v_evaluator = 0;
+static PyObject *__pyx_pf_5_cdec_7Lattice_5todot_lines(PyObject *__pyx_self) {
+  struct __pyx_obj_5_cdec___pyx_scope_struct_19_lines *__pyx_cur_scope;
   PyObject *__pyx_r = NULL;
   __Pyx_RefNannyDeclarations
-  PyObject *__pyx_t_1 = NULL;
-  int __pyx_t_2;
-  int __pyx_t_3;
-  int __pyx_t_4;
-  Py_ssize_t __pyx_t_5;
-  PyObject *(*__pyx_t_6)(PyObject *);
-  PyObject *__pyx_t_7 = NULL;
-  PyObject *__pyx_t_8 = NULL;
   int __pyx_lineno = 0;
   const char *__pyx_filename = NULL;
   int __pyx_clineno = 0;
-  __Pyx_RefNannySetupContext("__call__", 0);
-  __Pyx_INCREF(__pyx_v_refs);
+  __Pyx_RefNannySetupContext("lines", 0);
+  __pyx_cur_scope = (struct __pyx_obj_5_cdec___pyx_scope_struct_19_lines *)__pyx_ptype_5_cdec___pyx_scope_struct_19_lines->tp_new(__pyx_ptype_5_cdec___pyx_scope_struct_19_lines, __pyx_empty_tuple, NULL);
+  if (unlikely(!__pyx_cur_scope)) {
+    __Pyx_RefNannyFinishContext();
+    return NULL;
+  }
+  __Pyx_GOTREF(__pyx_cur_scope);
+  __pyx_cur_scope->__pyx_outer_scope = (struct __pyx_obj_5_cdec___pyx_scope_struct_18_todot *) __Pyx_CyFunction_GetClosure(__pyx_self);
+  __Pyx_INCREF(((PyObject *)__pyx_cur_scope->__pyx_outer_scope));
+  __Pyx_GIVEREF(__pyx_cur_scope->__pyx_outer_scope);
+  {
+    __pyx_GeneratorObject *gen = __Pyx_Generator_New((__pyx_generator_body_t) __pyx_gb_5_cdec_7Lattice_5todot_2generator19, (PyObject *) __pyx_cur_scope); if (unlikely(!gen)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 58; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_DECREF(__pyx_cur_scope);
+    __Pyx_RefNannyFinishContext();
+    return (PyObject *) gen;
+  }
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":122
- * 
- *     def __call__(self, refs):
- *         cdef mteval.EvaluationMetric* metric = mteval.Instance(self.name[0])             # <<<<<<<<<<<<<<
- *         if isinstance(refs, unicode) or isinstance(refs, str):
- *             refs = [refs]
- */
-  __pyx_v_metric = EvaluationMetric::Instance((__pyx_v_self->name[0]));
+  __pyx_r = Py_None; __Pyx_INCREF(Py_None);
+  goto __pyx_L0;
+  __pyx_L1_error:;
+  __Pyx_AddTraceback("_cdec.Lattice.todot.lines", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __pyx_r = NULL;
+  __pyx_L0:;
+  __Pyx_DECREF(((PyObject *)__pyx_cur_scope));
+  __Pyx_XGIVEREF(__pyx_r);
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":123
- *     def __call__(self, refs):
- *         cdef mteval.EvaluationMetric* metric = mteval.Instance(self.name[0])
- *         if isinstance(refs, unicode) or isinstance(refs, str):             # <<<<<<<<<<<<<<
- *             refs = [refs]
- *         cdef vector[vector[WordID]]* refsv = new vector[vector[WordID]]()
- */
-  __pyx_t_1 = ((PyObject *)((PyObject*)(&PyUnicode_Type)));
-  __Pyx_INCREF(__pyx_t_1);
-  __pyx_t_2 = __Pyx_TypeCheck(__pyx_v_refs, __pyx_t_1); 
-  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
-  if (!__pyx_t_2) {
-    __pyx_t_1 = ((PyObject *)((PyObject*)(&PyString_Type)));
-    __Pyx_INCREF(__pyx_t_1);
-    __pyx_t_3 = __Pyx_TypeCheck(__pyx_v_refs, __pyx_t_1); 
-    __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
-    __pyx_t_4 = __pyx_t_3;
-  } else {
-    __pyx_t_4 = __pyx_t_2;
+static PyObject *__pyx_gb_5_cdec_7Lattice_5todot_2generator19(__pyx_GeneratorObject *__pyx_generator, PyObject *__pyx_sent_value) /* generator body */
+{
+  struct __pyx_obj_5_cdec___pyx_scope_struct_19_lines *__pyx_cur_scope = ((struct __pyx_obj_5_cdec___pyx_scope_struct_19_lines *)__pyx_generator->closure);
+  PyObject *__pyx_r = NULL;
+  PyObject *__pyx_t_1 = NULL;
+  Py_ssize_t __pyx_t_2;
+  PyObject *__pyx_t_3 = NULL;
+  PyObject *(*__pyx_t_4)(PyObject *);
+  PyObject *__pyx_t_5 = NULL;
+  Py_ssize_t __pyx_t_6;
+  PyObject *(*__pyx_t_7)(PyObject *);
+  PyObject *__pyx_t_8 = NULL;
+  PyObject *__pyx_t_9 = NULL;
+  PyObject *__pyx_t_10 = NULL;
+  PyObject *__pyx_t_11 = NULL;
+  PyObject *(*__pyx_t_12)(PyObject *);
+  __Pyx_RefNannyDeclarations
+  __Pyx_RefNannySetupContext("None", 0);
+  switch (__pyx_generator->resume_label) {
+    case 0: goto __pyx_L3_first_run;
+    case 1: goto __pyx_L4_resume_from_yield;
+    case 2: goto __pyx_L5_resume_from_yield;
+    case 3: goto __pyx_L6_resume_from_yield;
+    case 4: goto __pyx_L13_resume_from_yield;
+    case 5: goto __pyx_L14_resume_from_yield;
+    case 6: goto __pyx_L15_resume_from_yield;
+    default: /* CPython raises the right error here */
+    __Pyx_RefNannyFinishContext();
+    return NULL;
   }
-  if (__pyx_t_4) {
+  __pyx_L3_first_run:;
+  if (unlikely(!__pyx_sent_value)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 58; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
 
-    /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":124
- *         cdef mteval.EvaluationMetric* metric = mteval.Instance(self.name[0])
- *         if isinstance(refs, unicode) or isinstance(refs, str):
- *             refs = [refs]             # <<<<<<<<<<<<<<
- *         cdef vector[vector[WordID]]* refsv = new vector[vector[WordID]]()
- *         cdef vector[WordID]* refv
+  /* "/Users/vchahun/Sandbox/cdec/python/src/lattice.pxi":59
+ *     def todot(self):
+ *         def lines():
+ *             yield 'digraph lattice {'             # <<<<<<<<<<<<<<
+ *             yield 'rankdir = LR;'
+ *             yield 'node [shape=circle];'
  */
-    __pyx_t_1 = PyList_New(1); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 124; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-    __Pyx_GOTREF(__pyx_t_1);
-    __Pyx_INCREF(__pyx_v_refs);
-    PyList_SET_ITEM(__pyx_t_1, 0, __pyx_v_refs);
-    __Pyx_GIVEREF(__pyx_v_refs);
-    __Pyx_DECREF(__pyx_v_refs);
-    __pyx_v_refs = ((PyObject *)__pyx_t_1);
-    __pyx_t_1 = 0;
-    goto __pyx_L3;
-  }
-  __pyx_L3:;
-
-  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":125
- *         if isinstance(refs, unicode) or isinstance(refs, str):
- *             refs = [refs]
- *         cdef vector[vector[WordID]]* refsv = new vector[vector[WordID]]()             # <<<<<<<<<<<<<<
- *         cdef vector[WordID]* refv
- *         cdef bytes ref_str
+  __Pyx_INCREF(((PyObject *)__pyx_kp_s_27));
+  __pyx_r = ((PyObject *)__pyx_kp_s_27);
+  __Pyx_XGIVEREF(__pyx_r);
+  __Pyx_RefNannyFinishContext();
+  /* return from generator, yielding value */
+  __pyx_generator->resume_label = 1;
+  return __pyx_r;
+  __pyx_L4_resume_from_yield:;
+  if (unlikely(!__pyx_sent_value)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 59; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/lattice.pxi":60
+ *         def lines():
+ *             yield 'digraph lattice {'
+ *             yield 'rankdir = LR;'             # <<<<<<<<<<<<<<
+ *             yield 'node [shape=circle];'
+ *             for i in range(len(self)):
  */
-  __pyx_v_refsv = new std::vector<std::vector<WordID> >();
+  __Pyx_INCREF(((PyObject *)__pyx_kp_s_28));
+  __pyx_r = ((PyObject *)__pyx_kp_s_28);
+  __Pyx_XGIVEREF(__pyx_r);
+  __Pyx_RefNannyFinishContext();
+  /* return from generator, yielding value */
+  __pyx_generator->resume_label = 2;
+  return __pyx_r;
+  __pyx_L5_resume_from_yield:;
+  if (unlikely(!__pyx_sent_value)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 60; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":128
- *         cdef vector[WordID]* refv
- *         cdef bytes ref_str
- *         for ref in refs:             # <<<<<<<<<<<<<<
- *             refv = new vector[WordID]()
- *             ConvertSentence(string(as_str(ref.strip())), refv)
+  /* "/Users/vchahun/Sandbox/cdec/python/src/lattice.pxi":61
+ *             yield 'digraph lattice {'
+ *             yield 'rankdir = LR;'
+ *             yield 'node [shape=circle];'             # <<<<<<<<<<<<<<
+ *             for i in range(len(self)):
+ *                 for label, weight, delta in self[i]:
  */
-  if (PyList_CheckExact(__pyx_v_refs) || PyTuple_CheckExact(__pyx_v_refs)) {
-    __pyx_t_1 = __pyx_v_refs; __Pyx_INCREF(__pyx_t_1); __pyx_t_5 = 0;
-    __pyx_t_6 = NULL;
+  __Pyx_INCREF(((PyObject *)__pyx_kp_s_29));
+  __pyx_r = ((PyObject *)__pyx_kp_s_29);
+  __Pyx_XGIVEREF(__pyx_r);
+  __Pyx_RefNannyFinishContext();
+  /* return from generator, yielding value */
+  __pyx_generator->resume_label = 3;
+  return __pyx_r;
+  __pyx_L6_resume_from_yield:;
+  if (unlikely(!__pyx_sent_value)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 61; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/lattice.pxi":62
+ *             yield 'rankdir = LR;'
+ *             yield 'node [shape=circle];'
+ *             for i in range(len(self)):             # <<<<<<<<<<<<<<
+ *                 for label, weight, delta in self[i]:
+ *                     yield '%d -> %d [label="%s"];' % (i, i+delta, label.replace('"', '\\"'))
+ */
+  if (unlikely(!__pyx_cur_scope->__pyx_outer_scope->__pyx_v_self)) { __Pyx_RaiseClosureNameError("self"); {__pyx_filename = __pyx_f[4]; __pyx_lineno = 62; __pyx_clineno = __LINE__; goto __pyx_L1_error;} }
+  __pyx_t_1 = ((PyObject *)__pyx_cur_scope->__pyx_outer_scope->__pyx_v_self);
+  __Pyx_INCREF(__pyx_t_1);
+  __pyx_t_2 = PyObject_Length(__pyx_t_1); if (unlikely(__pyx_t_2 == -1)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 62; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+  __pyx_t_1 = PyInt_FromSsize_t(__pyx_t_2); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 62; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_1);
+  __pyx_t_3 = PyTuple_New(1); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 62; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_3);
+  PyTuple_SET_ITEM(__pyx_t_3, 0, __pyx_t_1);
+  __Pyx_GIVEREF(__pyx_t_1);
+  __pyx_t_1 = 0;
+  __pyx_t_1 = PyObject_Call(__pyx_builtin_range, ((PyObject *)__pyx_t_3), NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 62; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_1);
+  __Pyx_DECREF(((PyObject *)__pyx_t_3)); __pyx_t_3 = 0;
+  if (PyList_CheckExact(__pyx_t_1) || PyTuple_CheckExact(__pyx_t_1)) {
+    __pyx_t_3 = __pyx_t_1; __Pyx_INCREF(__pyx_t_3); __pyx_t_2 = 0;
+    __pyx_t_4 = NULL;
   } else {
-    __pyx_t_5 = -1; __pyx_t_1 = PyObject_GetIter(__pyx_v_refs); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 128; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-    __Pyx_GOTREF(__pyx_t_1);
-    __pyx_t_6 = Py_TYPE(__pyx_t_1)->tp_iternext;
+    __pyx_t_2 = -1; __pyx_t_3 = PyObject_GetIter(__pyx_t_1); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 62; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_3);
+    __pyx_t_4 = Py_TYPE(__pyx_t_3)->tp_iternext;
   }
+  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
   for (;;) {
-    if (!__pyx_t_6 && PyList_CheckExact(__pyx_t_1)) {
-      if (__pyx_t_5 >= PyList_GET_SIZE(__pyx_t_1)) break;
-      __pyx_t_7 = PyList_GET_ITEM(__pyx_t_1, __pyx_t_5); __Pyx_INCREF(__pyx_t_7); __pyx_t_5++;
-    } else if (!__pyx_t_6 && PyTuple_CheckExact(__pyx_t_1)) {
-      if (__pyx_t_5 >= PyTuple_GET_SIZE(__pyx_t_1)) break;
-      __pyx_t_7 = PyTuple_GET_ITEM(__pyx_t_1, __pyx_t_5); __Pyx_INCREF(__pyx_t_7); __pyx_t_5++;
+    if (!__pyx_t_4 && PyList_CheckExact(__pyx_t_3)) {
+      if (__pyx_t_2 >= PyList_GET_SIZE(__pyx_t_3)) break;
+      __pyx_t_1 = PyList_GET_ITEM(__pyx_t_3, __pyx_t_2); __Pyx_INCREF(__pyx_t_1); __pyx_t_2++;
+    } else if (!__pyx_t_4 && PyTuple_CheckExact(__pyx_t_3)) {
+      if (__pyx_t_2 >= PyTuple_GET_SIZE(__pyx_t_3)) break;
+      __pyx_t_1 = PyTuple_GET_ITEM(__pyx_t_3, __pyx_t_2); __Pyx_INCREF(__pyx_t_1); __pyx_t_2++;
     } else {
-      __pyx_t_7 = __pyx_t_6(__pyx_t_1);
-      if (unlikely(!__pyx_t_7)) {
+      __pyx_t_1 = __pyx_t_4(__pyx_t_3);
+      if (unlikely(!__pyx_t_1)) {
         if (PyErr_Occurred()) {
           if (likely(PyErr_ExceptionMatches(PyExc_StopIteration))) PyErr_Clear();
-          else {__pyx_filename = __pyx_f[5]; __pyx_lineno = 128; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+          else {__pyx_filename = __pyx_f[4]; __pyx_lineno = 62; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
         }
         break;
       }
-      __Pyx_GOTREF(__pyx_t_7);
+      __Pyx_GOTREF(__pyx_t_1);
     }
-    __Pyx_XDECREF(__pyx_v_ref);
-    __pyx_v_ref = __pyx_t_7;
-    __pyx_t_7 = 0;
-
-    /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":129
- *         cdef bytes ref_str
- *         for ref in refs:
- *             refv = new vector[WordID]()             # <<<<<<<<<<<<<<
- *             ConvertSentence(string(as_str(ref.strip())), refv)
- *             refsv.push_back(refv[0])
- */
-    __pyx_v_refv = new std::vector<WordID>();
-
-    /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":130
- *         for ref in refs:
- *             refv = new vector[WordID]()
- *             ConvertSentence(string(as_str(ref.strip())), refv)             # <<<<<<<<<<<<<<
- *             refsv.push_back(refv[0])
- *             del refv
- */
-    __pyx_t_7 = PyObject_GetAttr(__pyx_v_ref, __pyx_n_s__strip); if (unlikely(!__pyx_t_7)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 130; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-    __Pyx_GOTREF(__pyx_t_7);
-    __pyx_t_8 = PyObject_Call(__pyx_t_7, ((PyObject *)__pyx_empty_tuple), NULL); if (unlikely(!__pyx_t_8)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 130; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-    __Pyx_GOTREF(__pyx_t_8);
-    __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;
-    TD::ConvertSentence(std::string(__pyx_f_5_cdec_as_str(__pyx_t_8, NULL)), __pyx_v_refv);
-    __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0;
-
-    /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":131
- *             refv = new vector[WordID]()
- *             ConvertSentence(string(as_str(ref.strip())), refv)
- *             refsv.push_back(refv[0])             # <<<<<<<<<<<<<<
- *             del refv
- *         cdef unsigned i
- */
-    __pyx_v_refsv->push_back((__pyx_v_refv[0]));
-
-    /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":132
- *             ConvertSentence(string(as_str(ref.strip())), refv)
- *             refsv.push_back(refv[0])
- *             del refv             # <<<<<<<<<<<<<<
- *         cdef unsigned i
- *         cdef SegmentEvaluator evaluator = SegmentEvaluator()
- */
-    delete __pyx_v_refv;
-  }
-  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+    __Pyx_XGOTREF(__pyx_cur_scope->__pyx_v_i);
+    __Pyx_XDECREF(__pyx_cur_scope->__pyx_v_i);
+    __Pyx_GIVEREF(__pyx_t_1);
+    __pyx_cur_scope->__pyx_v_i = __pyx_t_1;
+    __pyx_t_1 = 0;
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":134
- *             del refv
- *         cdef unsigned i
- *         cdef SegmentEvaluator evaluator = SegmentEvaluator()             # <<<<<<<<<<<<<<
- *         evaluator.metric = metric
- *         evaluator.scorer = new shared_ptr[mteval.SegmentEvaluator](metric.CreateSegmentEvaluator(refsv[0]))
+    /* "/Users/vchahun/Sandbox/cdec/python/src/lattice.pxi":63
+ *             yield 'node [shape=circle];'
+ *             for i in range(len(self)):
+ *                 for label, weight, delta in self[i]:             # <<<<<<<<<<<<<<
+ *                     yield '%d -> %d [label="%s"];' % (i, i+delta, label.replace('"', '\\"'))
+ *             yield '%d [shape=doublecircle]' % len(self)
  */
-  __pyx_t_1 = PyObject_Call(((PyObject *)((PyObject*)__pyx_ptype_5_cdec_SegmentEvaluator)), ((PyObject *)__pyx_empty_tuple), NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 134; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __Pyx_GOTREF(__pyx_t_1);
-  __pyx_v_evaluator = ((struct __pyx_obj_5_cdec_SegmentEvaluator *)__pyx_t_1);
-  __pyx_t_1 = 0;
+    __pyx_t_1 = PyObject_GetItem(((PyObject *)__pyx_cur_scope->__pyx_outer_scope->__pyx_v_self), __pyx_cur_scope->__pyx_v_i); if (!__pyx_t_1) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 63; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_1);
+    if (PyList_CheckExact(__pyx_t_1) || PyTuple_CheckExact(__pyx_t_1)) {
+      __pyx_t_5 = __pyx_t_1; __Pyx_INCREF(__pyx_t_5); __pyx_t_6 = 0;
+      __pyx_t_7 = NULL;
+    } else {
+      __pyx_t_6 = -1; __pyx_t_5 = PyObject_GetIter(__pyx_t_1); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 63; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __Pyx_GOTREF(__pyx_t_5);
+      __pyx_t_7 = Py_TYPE(__pyx_t_5)->tp_iternext;
+    }
+    __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+    for (;;) {
+      if (!__pyx_t_7 && PyList_CheckExact(__pyx_t_5)) {
+        if (__pyx_t_6 >= PyList_GET_SIZE(__pyx_t_5)) break;
+        __pyx_t_1 = PyList_GET_ITEM(__pyx_t_5, __pyx_t_6); __Pyx_INCREF(__pyx_t_1); __pyx_t_6++;
+      } else if (!__pyx_t_7 && PyTuple_CheckExact(__pyx_t_5)) {
+        if (__pyx_t_6 >= PyTuple_GET_SIZE(__pyx_t_5)) break;
+        __pyx_t_1 = PyTuple_GET_ITEM(__pyx_t_5, __pyx_t_6); __Pyx_INCREF(__pyx_t_1); __pyx_t_6++;
+      } else {
+        __pyx_t_1 = __pyx_t_7(__pyx_t_5);
+        if (unlikely(!__pyx_t_1)) {
+          if (PyErr_Occurred()) {
+            if (likely(PyErr_ExceptionMatches(PyExc_StopIteration))) PyErr_Clear();
+            else {__pyx_filename = __pyx_f[4]; __pyx_lineno = 63; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+          }
+          break;
+        }
+        __Pyx_GOTREF(__pyx_t_1);
+      }
+      if ((likely(PyTuple_CheckExact(__pyx_t_1))) || (PyList_CheckExact(__pyx_t_1))) {
+        PyObject* sequence = __pyx_t_1;
+        if (likely(PyTuple_CheckExact(sequence))) {
+          if (unlikely(PyTuple_GET_SIZE(sequence) != 3)) {
+            if (PyTuple_GET_SIZE(sequence) > 3) __Pyx_RaiseTooManyValuesError(3);
+            else __Pyx_RaiseNeedMoreValuesError(PyTuple_GET_SIZE(sequence));
+            {__pyx_filename = __pyx_f[4]; __pyx_lineno = 63; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+          }
+          __pyx_t_8 = PyTuple_GET_ITEM(sequence, 0); 
+          __pyx_t_9 = PyTuple_GET_ITEM(sequence, 1); 
+          __pyx_t_10 = PyTuple_GET_ITEM(sequence, 2); 
+        } else {
+          if (unlikely(PyList_GET_SIZE(sequence) != 3)) {
+            if (PyList_GET_SIZE(sequence) > 3) __Pyx_RaiseTooManyValuesError(3);
+            else __Pyx_RaiseNeedMoreValuesError(PyList_GET_SIZE(sequence));
+            {__pyx_filename = __pyx_f[4]; __pyx_lineno = 63; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+          }
+          __pyx_t_8 = PyList_GET_ITEM(sequence, 0); 
+          __pyx_t_9 = PyList_GET_ITEM(sequence, 1); 
+          __pyx_t_10 = PyList_GET_ITEM(sequence, 2); 
+        }
+        __Pyx_INCREF(__pyx_t_8);
+        __Pyx_INCREF(__pyx_t_9);
+        __Pyx_INCREF(__pyx_t_10);
+        __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+      } else {
+        Py_ssize_t index = -1;
+        __pyx_t_11 = PyObject_GetIter(__pyx_t_1); if (unlikely(!__pyx_t_11)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 63; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+        __Pyx_GOTREF(__pyx_t_11);
+        __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+        __pyx_t_12 = Py_TYPE(__pyx_t_11)->tp_iternext;
+        index = 0; __pyx_t_8 = __pyx_t_12(__pyx_t_11); if (unlikely(!__pyx_t_8)) goto __pyx_L11_unpacking_failed;
+        __Pyx_GOTREF(__pyx_t_8);
+        index = 1; __pyx_t_9 = __pyx_t_12(__pyx_t_11); if (unlikely(!__pyx_t_9)) goto __pyx_L11_unpacking_failed;
+        __Pyx_GOTREF(__pyx_t_9);
+        index = 2; __pyx_t_10 = __pyx_t_12(__pyx_t_11); if (unlikely(!__pyx_t_10)) goto __pyx_L11_unpacking_failed;
+        __Pyx_GOTREF(__pyx_t_10);
+        if (__Pyx_IternextUnpackEndCheck(__pyx_t_12(__pyx_t_11), 3) < 0) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 63; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+        __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0;
+        goto __pyx_L12_unpacking_done;
+        __pyx_L11_unpacking_failed:;
+        __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0;
+        if (PyErr_Occurred() && PyErr_ExceptionMatches(PyExc_StopIteration)) PyErr_Clear();
+        if (!PyErr_Occurred()) __Pyx_RaiseNeedMoreValuesError(index);
+        {__pyx_filename = __pyx_f[4]; __pyx_lineno = 63; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+        __pyx_L12_unpacking_done:;
+      }
+      __Pyx_XGOTREF(__pyx_cur_scope->__pyx_v_label);
+      __Pyx_XDECREF(__pyx_cur_scope->__pyx_v_label);
+      __Pyx_GIVEREF(__pyx_t_8);
+      __pyx_cur_scope->__pyx_v_label = __pyx_t_8;
+      __pyx_t_8 = 0;
+      __Pyx_XGOTREF(__pyx_cur_scope->__pyx_v_weight);
+      __Pyx_XDECREF(__pyx_cur_scope->__pyx_v_weight);
+      __Pyx_GIVEREF(__pyx_t_9);
+      __pyx_cur_scope->__pyx_v_weight = __pyx_t_9;
+      __pyx_t_9 = 0;
+      __Pyx_XGOTREF(__pyx_cur_scope->__pyx_v_delta);
+      __Pyx_XDECREF(__pyx_cur_scope->__pyx_v_delta);
+      __Pyx_GIVEREF(__pyx_t_10);
+      __pyx_cur_scope->__pyx_v_delta = __pyx_t_10;
+      __pyx_t_10 = 0;
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":135
- *         cdef unsigned i
- *         cdef SegmentEvaluator evaluator = SegmentEvaluator()
- *         evaluator.metric = metric             # <<<<<<<<<<<<<<
- *         evaluator.scorer = new shared_ptr[mteval.SegmentEvaluator](metric.CreateSegmentEvaluator(refsv[0]))
- *         del refsv # in theory should not delete but store in SegmentEvaluator
+      /* "/Users/vchahun/Sandbox/cdec/python/src/lattice.pxi":64
+ *             for i in range(len(self)):
+ *                 for label, weight, delta in self[i]:
+ *                     yield '%d -> %d [label="%s"];' % (i, i+delta, label.replace('"', '\\"'))             # <<<<<<<<<<<<<<
+ *             yield '%d [shape=doublecircle]' % len(self)
+ *             yield '}'
  */
-  __pyx_v_evaluator->metric = __pyx_v_metric;
-
-  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":136
- *         cdef SegmentEvaluator evaluator = SegmentEvaluator()
- *         evaluator.metric = metric
- *         evaluator.scorer = new shared_ptr[mteval.SegmentEvaluator](metric.CreateSegmentEvaluator(refsv[0]))             # <<<<<<<<<<<<<<
- *         del refsv # in theory should not delete but store in SegmentEvaluator
- *         return evaluator
- */
-  __pyx_v_evaluator->scorer = new boost::shared_ptr<SegmentEvaluator>(__pyx_v_metric->CreateSegmentEvaluator((__pyx_v_refsv[0])));
+      __pyx_t_1 = PyNumber_Add(__pyx_cur_scope->__pyx_v_i, __pyx_cur_scope->__pyx_v_delta); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 64; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __Pyx_GOTREF(__pyx_t_1);
+      __pyx_t_10 = PyObject_GetAttr(__pyx_cur_scope->__pyx_v_label, __pyx_n_s__replace); if (unlikely(!__pyx_t_10)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 64; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __Pyx_GOTREF(__pyx_t_10);
+      __pyx_t_9 = PyObject_Call(__pyx_t_10, ((PyObject *)__pyx_k_tuple_33), NULL); if (unlikely(!__pyx_t_9)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 64; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __Pyx_GOTREF(__pyx_t_9);
+      __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0;
+      __pyx_t_10 = PyTuple_New(3); if (unlikely(!__pyx_t_10)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 64; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __Pyx_GOTREF(__pyx_t_10);
+      __Pyx_INCREF(__pyx_cur_scope->__pyx_v_i);
+      PyTuple_SET_ITEM(__pyx_t_10, 0, __pyx_cur_scope->__pyx_v_i);
+      __Pyx_GIVEREF(__pyx_cur_scope->__pyx_v_i);
+      PyTuple_SET_ITEM(__pyx_t_10, 1, __pyx_t_1);
+      __Pyx_GIVEREF(__pyx_t_1);
+      PyTuple_SET_ITEM(__pyx_t_10, 2, __pyx_t_9);
+      __Pyx_GIVEREF(__pyx_t_9);
+      __pyx_t_1 = 0;
+      __pyx_t_9 = 0;
+      __pyx_t_9 = PyNumber_Remainder(((PyObject *)__pyx_kp_s_30), ((PyObject *)__pyx_t_10)); if (unlikely(!__pyx_t_9)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 64; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __Pyx_GOTREF(((PyObject *)__pyx_t_9));
+      __Pyx_DECREF(((PyObject *)__pyx_t_10)); __pyx_t_10 = 0;
+      __pyx_r = ((PyObject *)__pyx_t_9);
+      __pyx_t_9 = 0;
+      __pyx_cur_scope->__pyx_t_0 = __pyx_t_2;
+      __Pyx_XGIVEREF(__pyx_t_3);
+      __pyx_cur_scope->__pyx_t_1 = __pyx_t_3;
+      __pyx_cur_scope->__pyx_t_2 = __pyx_t_4;
+      __Pyx_XGIVEREF(__pyx_t_5);
+      __pyx_cur_scope->__pyx_t_3 = __pyx_t_5;
+      __pyx_cur_scope->__pyx_t_4 = __pyx_t_6;
+      __pyx_cur_scope->__pyx_t_5 = __pyx_t_7;
+      __Pyx_XGIVEREF(__pyx_r);
+      __Pyx_RefNannyFinishContext();
+      /* return from generator, yielding value */
+      __pyx_generator->resume_label = 4;
+      return __pyx_r;
+      __pyx_L13_resume_from_yield:;
+      __pyx_t_2 = __pyx_cur_scope->__pyx_t_0;
+      __pyx_t_3 = __pyx_cur_scope->__pyx_t_1;
+      __pyx_cur_scope->__pyx_t_1 = 0;
+      __Pyx_XGOTREF(__pyx_t_3);
+      __pyx_t_4 = __pyx_cur_scope->__pyx_t_2;
+      __pyx_t_5 = __pyx_cur_scope->__pyx_t_3;
+      __pyx_cur_scope->__pyx_t_3 = 0;
+      __Pyx_XGOTREF(__pyx_t_5);
+      __pyx_t_6 = __pyx_cur_scope->__pyx_t_4;
+      __pyx_t_7 = __pyx_cur_scope->__pyx_t_5;
+      if (unlikely(!__pyx_sent_value)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 64; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    }
+    __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
+  }
+  __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":137
- *         evaluator.metric = metric
- *         evaluator.scorer = new shared_ptr[mteval.SegmentEvaluator](metric.CreateSegmentEvaluator(refsv[0]))
- *         del refsv # in theory should not delete but store in SegmentEvaluator             # <<<<<<<<<<<<<<
- *         return evaluator
- * 
+  /* "/Users/vchahun/Sandbox/cdec/python/src/lattice.pxi":65
+ *                 for label, weight, delta in self[i]:
+ *                     yield '%d -> %d [label="%s"];' % (i, i+delta, label.replace('"', '\\"'))
+ *             yield '%d [shape=doublecircle]' % len(self)             # <<<<<<<<<<<<<<
+ *             yield '}'
+ *         return '\n'.join(lines()).encode('utf8')
  */
-  delete __pyx_v_refsv;
+  __pyx_t_3 = ((PyObject *)__pyx_cur_scope->__pyx_outer_scope->__pyx_v_self);
+  __Pyx_INCREF(__pyx_t_3);
+  __pyx_t_2 = PyObject_Length(__pyx_t_3); if (unlikely(__pyx_t_2 == -1)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 65; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
+  __pyx_t_3 = PyInt_FromSsize_t(__pyx_t_2); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 65; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_3);
+  __pyx_t_5 = PyNumber_Remainder(((PyObject *)__pyx_kp_s_34), __pyx_t_3); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 65; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(((PyObject *)__pyx_t_5));
+  __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
+  __pyx_r = ((PyObject *)__pyx_t_5);
+  __pyx_t_5 = 0;
+  __Pyx_XGIVEREF(__pyx_r);
+  __Pyx_RefNannyFinishContext();
+  /* return from generator, yielding value */
+  __pyx_generator->resume_label = 5;
+  return __pyx_r;
+  __pyx_L14_resume_from_yield:;
+  if (unlikely(!__pyx_sent_value)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 65; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":138
- *         evaluator.scorer = new shared_ptr[mteval.SegmentEvaluator](metric.CreateSegmentEvaluator(refsv[0]))
- *         del refsv # in theory should not delete but store in SegmentEvaluator
- *         return evaluator             # <<<<<<<<<<<<<<
- * 
- *     def __str__(self):
+  /* "/Users/vchahun/Sandbox/cdec/python/src/lattice.pxi":66
+ *                     yield '%d -> %d [label="%s"];' % (i, i+delta, label.replace('"', '\\"'))
+ *             yield '%d [shape=doublecircle]' % len(self)
+ *             yield '}'             # <<<<<<<<<<<<<<
+ *         return '\n'.join(lines()).encode('utf8')
  */
-  __Pyx_XDECREF(__pyx_r);
-  __Pyx_INCREF(((PyObject *)__pyx_v_evaluator));
-  __pyx_r = ((PyObject *)__pyx_v_evaluator);
-  goto __pyx_L0;
-
-  __pyx_r = Py_None; __Pyx_INCREF(Py_None);
+  __Pyx_INCREF(((PyObject *)__pyx_kp_s_35));
+  __pyx_r = ((PyObject *)__pyx_kp_s_35);
+  __Pyx_XGIVEREF(__pyx_r);
+  __Pyx_RefNannyFinishContext();
+  /* return from generator, yielding value */
+  __pyx_generator->resume_label = 6;
+  return __pyx_r;
+  __pyx_L15_resume_from_yield:;
+  if (unlikely(!__pyx_sent_value)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 66; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  PyErr_SetNone(PyExc_StopIteration);
   goto __pyx_L0;
   __pyx_L1_error:;
   __Pyx_XDECREF(__pyx_t_1);
-  __Pyx_XDECREF(__pyx_t_7);
+  __Pyx_XDECREF(__pyx_t_3);
+  __Pyx_XDECREF(__pyx_t_5);
   __Pyx_XDECREF(__pyx_t_8);
-  __Pyx_AddTraceback("_cdec.Scorer.__call__", __pyx_clineno, __pyx_lineno, __pyx_filename);
-  __pyx_r = NULL;
+  __Pyx_XDECREF(__pyx_t_9);
+  __Pyx_XDECREF(__pyx_t_10);
+  __Pyx_XDECREF(__pyx_t_11);
+  __Pyx_AddTraceback("lines", __pyx_clineno, __pyx_lineno, __pyx_filename);
   __pyx_L0:;
-  __Pyx_XDECREF(__pyx_v_ref);
-  __Pyx_XDECREF((PyObject *)__pyx_v_evaluator);
-  __Pyx_XDECREF(__pyx_v_refs);
-  __Pyx_XGIVEREF(__pyx_r);
-  __Pyx_RefNannyFinishContext();
-  return __pyx_r;
-}
-
-/* Python wrapper */
-static PyObject *__pyx_pw_5_cdec_6Scorer_7__str__(PyObject *__pyx_v_self); /*proto*/
-static PyObject *__pyx_pw_5_cdec_6Scorer_7__str__(PyObject *__pyx_v_self) {
-  PyObject *__pyx_r = 0;
-  __Pyx_RefNannyDeclarations
-  __Pyx_RefNannySetupContext("__str__ (wrapper)", 0);
-  __pyx_r = __pyx_pf_5_cdec_6Scorer_6__str__(((struct __pyx_obj_5_cdec_Scorer *)__pyx_v_self));
+  __Pyx_XDECREF(__pyx_r);
+  __pyx_generator->resume_label = -1;
   __Pyx_RefNannyFinishContext();
-  return __pyx_r;
+  return NULL;
 }
 
-/* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":140
- *         return evaluator
- * 
- *     def __str__(self):             # <<<<<<<<<<<<<<
- *         return self.name.c_str()
+/* "/Users/vchahun/Sandbox/cdec/python/src/lattice.pxi":57
+ *         del self.lattice
  * 
+ *     def todot(self):             # <<<<<<<<<<<<<<
+ *         def lines():
+ *             yield 'digraph lattice {'
  */
 
-static PyObject *__pyx_pf_5_cdec_6Scorer_6__str__(struct __pyx_obj_5_cdec_Scorer *__pyx_v_self) {
+static PyObject *__pyx_pf_5_cdec_7Lattice_15todot(struct __pyx_obj_5_cdec_Lattice *__pyx_v_self) {
+  struct __pyx_obj_5_cdec___pyx_scope_struct_18_todot *__pyx_cur_scope;
+  PyObject *__pyx_v_lines = 0;
   PyObject *__pyx_r = NULL;
   __Pyx_RefNannyDeclarations
   PyObject *__pyx_t_1 = NULL;
+  PyObject *__pyx_t_2 = NULL;
+  PyObject *__pyx_t_3 = NULL;
   int __pyx_lineno = 0;
   const char *__pyx_filename = NULL;
   int __pyx_clineno = 0;
-  __Pyx_RefNannySetupContext("__str__", 0);
+  __Pyx_RefNannySetupContext("todot", 0);
+  __pyx_cur_scope = (struct __pyx_obj_5_cdec___pyx_scope_struct_18_todot *)__pyx_ptype_5_cdec___pyx_scope_struct_18_todot->tp_new(__pyx_ptype_5_cdec___pyx_scope_struct_18_todot, __pyx_empty_tuple, NULL);
+  if (unlikely(!__pyx_cur_scope)) {
+    __Pyx_RefNannyFinishContext();
+    return NULL;
+  }
+  __Pyx_GOTREF(__pyx_cur_scope);
+  __pyx_cur_scope->__pyx_v_self = __pyx_v_self;
+  __Pyx_INCREF((PyObject *)__pyx_cur_scope->__pyx_v_self);
+  __Pyx_GIVEREF((PyObject *)__pyx_cur_scope->__pyx_v_self);
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":141
- * 
- *     def __str__(self):
- *         return self.name.c_str()             # <<<<<<<<<<<<<<
+  /* "/Users/vchahun/Sandbox/cdec/python/src/lattice.pxi":58
  * 
- * BLEU = Scorer('IBM_BLEU')
+ *     def todot(self):
+ *         def lines():             # <<<<<<<<<<<<<<
+ *             yield 'digraph lattice {'
+ *             yield 'rankdir = LR;'
  */
-  __Pyx_XDECREF(__pyx_r);
-  __pyx_t_1 = PyBytes_FromString(__pyx_v_self->name->c_str()); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 141; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __Pyx_GOTREF(((PyObject *)__pyx_t_1));
-  __pyx_r = ((PyObject *)__pyx_t_1);
+  __pyx_t_1 = __Pyx_CyFunction_NewEx(&__pyx_mdef_5_cdec_7Lattice_5todot_1lines, 0, ((PyObject*)__pyx_cur_scope), __pyx_n_s___cdec, ((PyObject *)__pyx_k_codeobj_37)); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 58; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_1);
+  __pyx_v_lines = __pyx_t_1;
   __pyx_t_1 = 0;
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/lattice.pxi":67
+ *             yield '%d [shape=doublecircle]' % len(self)
+ *             yield '}'
+ *         return '\n'.join(lines()).encode('utf8')             # <<<<<<<<<<<<<<
+ */
+  __Pyx_XDECREF(__pyx_r);
+  __pyx_t_1 = PyObject_GetAttr(((PyObject *)__pyx_kp_s_39), __pyx_n_s__join); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 67; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_1);
+  __pyx_t_2 = PyObject_Call(__pyx_v_lines, ((PyObject *)__pyx_empty_tuple), NULL); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 67; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_2);
+  __pyx_t_3 = PyTuple_New(1); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 67; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_3);
+  PyTuple_SET_ITEM(__pyx_t_3, 0, __pyx_t_2);
+  __Pyx_GIVEREF(__pyx_t_2);
+  __pyx_t_2 = 0;
+  __pyx_t_2 = PyObject_Call(__pyx_t_1, ((PyObject *)__pyx_t_3), NULL); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 67; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_2);
+  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+  __Pyx_DECREF(((PyObject *)__pyx_t_3)); __pyx_t_3 = 0;
+  __pyx_t_3 = PyObject_GetAttr(__pyx_t_2, __pyx_n_s__encode); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 67; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_3);
+  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+  __pyx_t_2 = PyObject_Call(__pyx_t_3, ((PyObject *)__pyx_k_tuple_40), NULL); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 67; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_2);
+  __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
+  __pyx_r = __pyx_t_2;
+  __pyx_t_2 = 0;
   goto __pyx_L0;
 
   __pyx_r = Py_None; __Pyx_INCREF(Py_None);
   goto __pyx_L0;
   __pyx_L1_error:;
   __Pyx_XDECREF(__pyx_t_1);
-  __Pyx_AddTraceback("_cdec.Scorer.__str__", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __Pyx_XDECREF(__pyx_t_2);
+  __Pyx_XDECREF(__pyx_t_3);
+  __Pyx_AddTraceback("_cdec.Lattice.todot", __pyx_clineno, __pyx_lineno, __pyx_filename);
   __pyx_r = NULL;
   __pyx_L0:;
+  __Pyx_XDECREF(__pyx_v_lines);
+  __Pyx_DECREF(((PyObject *)__pyx_cur_scope));
   __Pyx_XGIVEREF(__pyx_r);
   __Pyx_RefNannyFinishContext();
   return __pyx_r;
 }
-static PyObject *__pyx_gb_5_cdec_4generator14(__pyx_GeneratorObject *__pyx_generator, PyObject *__pyx_sent_value); /* proto */
-
-/* Python wrapper */
-static PyObject *__pyx_pw_5_cdec_3_make_config(PyObject *__pyx_self, PyObject *__pyx_v_config); /*proto*/
-static PyMethodDef __pyx_mdef_5_cdec_3_make_config = {__Pyx_NAMESTR("_make_config"), (PyCFunction)__pyx_pw_5_cdec_3_make_config, METH_O, __Pyx_DOCSTR(0)};
-static PyObject *__pyx_pw_5_cdec_3_make_config(PyObject *__pyx_self, PyObject *__pyx_v_config) {
-  PyObject *__pyx_r = 0;
-  __Pyx_RefNannyDeclarations
-  __Pyx_RefNannySetupContext("_make_config (wrapper)", 0);
-  __pyx_self = __pyx_self;
-  __pyx_r = __pyx_pf_5_cdec_2_make_config(__pyx_self, ((PyObject *)__pyx_v_config));
-  __Pyx_RefNannyFinishContext();
-  return __pyx_r;
-}
 
-/* "_cdec.pyx":27
- * class ParseFailed(Exception): pass
+/* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":3
+ * cimport mteval
  * 
- * def _make_config(config):             # <<<<<<<<<<<<<<
- *     for key, value in config.items():
- *         if isinstance(value, dict):
+ * cdef SufficientStats as_stats(x, y):             # <<<<<<<<<<<<<<
+ *     if isinstance(x, SufficientStats):
+ *         return x
  */
 
-static PyObject *__pyx_pf_5_cdec_2_make_config(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_config) {
-  struct __pyx_obj_5_cdec___pyx_scope_struct_20__make_config *__pyx_cur_scope;
-  PyObject *__pyx_r = NULL;
+static struct __pyx_obj_5_cdec_SufficientStats *__pyx_f_5_cdec_as_stats(PyObject *__pyx_v_x, PyObject *__pyx_v_y) {
+  struct __pyx_obj_5_cdec_SufficientStats *__pyx_v_stats = NULL;
+  struct __pyx_obj_5_cdec_SufficientStats *__pyx_r = NULL;
   __Pyx_RefNannyDeclarations
+  PyObject *__pyx_t_1 = NULL;
+  int __pyx_t_2;
+  int __pyx_t_3;
+  int __pyx_t_4;
   int __pyx_lineno = 0;
   const char *__pyx_filename = NULL;
   int __pyx_clineno = 0;
-  __Pyx_RefNannySetupContext("_make_config", 0);
-  __pyx_cur_scope = (struct __pyx_obj_5_cdec___pyx_scope_struct_20__make_config *)__pyx_ptype_5_cdec___pyx_scope_struct_20__make_config->tp_new(__pyx_ptype_5_cdec___pyx_scope_struct_20__make_config, __pyx_empty_tuple, NULL);
-  if (unlikely(!__pyx_cur_scope)) {
-    __Pyx_RefNannyFinishContext();
-    return NULL;
-  }
-  __Pyx_GOTREF(__pyx_cur_scope);
-  __pyx_cur_scope->__pyx_v_config = __pyx_v_config;
-  __Pyx_INCREF(__pyx_cur_scope->__pyx_v_config);
-  __Pyx_GIVEREF(__pyx_cur_scope->__pyx_v_config);
-  {
-    __pyx_GeneratorObject *gen = __Pyx_Generator_New((__pyx_generator_body_t) __pyx_gb_5_cdec_4generator14, (PyObject *) __pyx_cur_scope); if (unlikely(!gen)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 27; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-    __Pyx_DECREF(__pyx_cur_scope);
-    __Pyx_RefNannyFinishContext();
-    return (PyObject *) gen;
-  }
+  __Pyx_RefNannySetupContext("as_stats", 0);
 
-  __pyx_r = Py_None; __Pyx_INCREF(Py_None);
-  goto __pyx_L0;
-  __pyx_L1_error:;
-  __Pyx_AddTraceback("_cdec._make_config", __pyx_clineno, __pyx_lineno, __pyx_filename);
-  __pyx_r = NULL;
-  __pyx_L0:;
-  __Pyx_DECREF(((PyObject *)__pyx_cur_scope));
-  __Pyx_XGIVEREF(__pyx_r);
-  __Pyx_RefNannyFinishContext();
-  return __pyx_r;
-}
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":4
+ * 
+ * cdef SufficientStats as_stats(x, y):
+ *     if isinstance(x, SufficientStats):             # <<<<<<<<<<<<<<
+ *         return x
+ *     elif x == 0 and isinstance(y, SufficientStats):
+ */
+  __pyx_t_1 = ((PyObject *)((PyObject*)__pyx_ptype_5_cdec_SufficientStats));
+  __Pyx_INCREF(__pyx_t_1);
+  __pyx_t_2 = __Pyx_TypeCheck(__pyx_v_x, __pyx_t_1); 
+  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+  if (__pyx_t_2) {
 
-static PyObject *__pyx_gb_5_cdec_4generator14(__pyx_GeneratorObject *__pyx_generator, PyObject *__pyx_sent_value) /* generator body */
-{
-  struct __pyx_obj_5_cdec___pyx_scope_struct_20__make_config *__pyx_cur_scope = ((struct __pyx_obj_5_cdec___pyx_scope_struct_20__make_config *)__pyx_generator->closure);
-  PyObject *__pyx_r = NULL;
-  PyObject *__pyx_t_1 = NULL;
-  PyObject *__pyx_t_2 = NULL;
-  Py_ssize_t __pyx_t_3;
-  PyObject *(*__pyx_t_4)(PyObject *);
-  PyObject *__pyx_t_5 = NULL;
-  PyObject *__pyx_t_6 = NULL;
-  PyObject *__pyx_t_7 = NULL;
-  PyObject *(*__pyx_t_8)(PyObject *);
-  int __pyx_t_9;
-  Py_ssize_t __pyx_t_10;
-  PyObject *(*__pyx_t_11)(PyObject *);
-  PyObject *__pyx_t_12 = NULL;
-  __Pyx_RefNannyDeclarations
-  __Pyx_RefNannySetupContext("None", 0);
-  switch (__pyx_generator->resume_label) {
-    case 0: goto __pyx_L3_first_run;
-    case 1: goto __pyx_L13_resume_from_yield;
-    case 2: goto __pyx_L16_resume_from_yield;
-    case 3: goto __pyx_L17_resume_from_yield;
-    default: /* CPython raises the right error here */
-    __Pyx_RefNannyFinishContext();
-    return NULL;
+    /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":5
+ * cdef SufficientStats as_stats(x, y):
+ *     if isinstance(x, SufficientStats):
+ *         return x             # <<<<<<<<<<<<<<
+ *     elif x == 0 and isinstance(y, SufficientStats):
+ *         stats = SufficientStats()
+ */
+    __Pyx_XDECREF(((PyObject *)__pyx_r));
+    if (!(likely(((__pyx_v_x) == Py_None) || likely(__Pyx_TypeTest(__pyx_v_x, __pyx_ptype_5_cdec_SufficientStats))))) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 5; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_INCREF(__pyx_v_x);
+    __pyx_r = ((struct __pyx_obj_5_cdec_SufficientStats *)__pyx_v_x);
+    goto __pyx_L0;
+    goto __pyx_L3;
   }
-  __pyx_L3_first_run:;
-  if (unlikely(!__pyx_sent_value)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 27; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
 
-  /* "_cdec.pyx":28
- * 
- * def _make_config(config):
- *     for key, value in config.items():             # <<<<<<<<<<<<<<
- *         if isinstance(value, dict):
- *             for name, info in value.items():
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":6
+ *     if isinstance(x, SufficientStats):
+ *         return x
+ *     elif x == 0 and isinstance(y, SufficientStats):             # <<<<<<<<<<<<<<
+ *         stats = SufficientStats()
+ *         stats.stats = new mteval.SufficientStats()
  */
-  __pyx_t_1 = PyObject_GetAttr(__pyx_cur_scope->__pyx_v_config, __pyx_n_s__items); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 28; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_1 = PyObject_RichCompare(__pyx_v_x, __pyx_int_0, Py_EQ); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 6; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __Pyx_GOTREF(__pyx_t_1);
-  __pyx_t_2 = PyObject_Call(__pyx_t_1, ((PyObject *)__pyx_empty_tuple), NULL); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 28; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __Pyx_GOTREF(__pyx_t_2);
+  __pyx_t_2 = __Pyx_PyObject_IsTrue(__pyx_t_1); if (unlikely(__pyx_t_2 < 0)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 6; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
-  if (PyList_CheckExact(__pyx_t_2) || PyTuple_CheckExact(__pyx_t_2)) {
-    __pyx_t_1 = __pyx_t_2; __Pyx_INCREF(__pyx_t_1); __pyx_t_3 = 0;
-    __pyx_t_4 = NULL;
+  if (__pyx_t_2) {
+    __pyx_t_1 = ((PyObject *)((PyObject*)__pyx_ptype_5_cdec_SufficientStats));
+    __Pyx_INCREF(__pyx_t_1);
+    __pyx_t_3 = __Pyx_TypeCheck(__pyx_v_y, __pyx_t_1); 
+    __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+    __pyx_t_4 = __pyx_t_3;
   } else {
-    __pyx_t_3 = -1; __pyx_t_1 = PyObject_GetIter(__pyx_t_2); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 28; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-    __Pyx_GOTREF(__pyx_t_1);
-    __pyx_t_4 = Py_TYPE(__pyx_t_1)->tp_iternext;
+    __pyx_t_4 = __pyx_t_2;
   }
-  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
-  for (;;) {
-    if (!__pyx_t_4 && PyList_CheckExact(__pyx_t_1)) {
-      if (__pyx_t_3 >= PyList_GET_SIZE(__pyx_t_1)) break;
-      __pyx_t_2 = PyList_GET_ITEM(__pyx_t_1, __pyx_t_3); __Pyx_INCREF(__pyx_t_2); __pyx_t_3++;
-    } else if (!__pyx_t_4 && PyTuple_CheckExact(__pyx_t_1)) {
-      if (__pyx_t_3 >= PyTuple_GET_SIZE(__pyx_t_1)) break;
-      __pyx_t_2 = PyTuple_GET_ITEM(__pyx_t_1, __pyx_t_3); __Pyx_INCREF(__pyx_t_2); __pyx_t_3++;
-    } else {
-      __pyx_t_2 = __pyx_t_4(__pyx_t_1);
-      if (unlikely(!__pyx_t_2)) {
-        if (PyErr_Occurred()) {
-          if (likely(PyErr_ExceptionMatches(PyExc_StopIteration))) PyErr_Clear();
-          else {__pyx_filename = __pyx_f[0]; __pyx_lineno = 28; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-        }
-        break;
-      }
-      __Pyx_GOTREF(__pyx_t_2);
-    }
-    if ((likely(PyTuple_CheckExact(__pyx_t_2))) || (PyList_CheckExact(__pyx_t_2))) {
-      PyObject* sequence = __pyx_t_2;
-      if (likely(PyTuple_CheckExact(sequence))) {
-        if (unlikely(PyTuple_GET_SIZE(sequence) != 2)) {
-          if (PyTuple_GET_SIZE(sequence) > 2) __Pyx_RaiseTooManyValuesError(2);
-          else __Pyx_RaiseNeedMoreValuesError(PyTuple_GET_SIZE(sequence));
-          {__pyx_filename = __pyx_f[0]; __pyx_lineno = 28; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-        }
-        __pyx_t_5 = PyTuple_GET_ITEM(sequence, 0); 
-        __pyx_t_6 = PyTuple_GET_ITEM(sequence, 1); 
-      } else {
-        if (unlikely(PyList_GET_SIZE(sequence) != 2)) {
-          if (PyList_GET_SIZE(sequence) > 2) __Pyx_RaiseTooManyValuesError(2);
-          else __Pyx_RaiseNeedMoreValuesError(PyList_GET_SIZE(sequence));
-          {__pyx_filename = __pyx_f[0]; __pyx_lineno = 28; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-        }
-        __pyx_t_5 = PyList_GET_ITEM(sequence, 0); 
-        __pyx_t_6 = PyList_GET_ITEM(sequence, 1); 
-      }
-      __Pyx_INCREF(__pyx_t_5);
-      __Pyx_INCREF(__pyx_t_6);
-      __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
-    } else {
-      Py_ssize_t index = -1;
-      __pyx_t_7 = PyObject_GetIter(__pyx_t_2); if (unlikely(!__pyx_t_7)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 28; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-      __Pyx_GOTREF(__pyx_t_7);
-      __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
-      __pyx_t_8 = Py_TYPE(__pyx_t_7)->tp_iternext;
-      index = 0; __pyx_t_5 = __pyx_t_8(__pyx_t_7); if (unlikely(!__pyx_t_5)) goto __pyx_L6_unpacking_failed;
-      __Pyx_GOTREF(__pyx_t_5);
-      index = 1; __pyx_t_6 = __pyx_t_8(__pyx_t_7); if (unlikely(!__pyx_t_6)) goto __pyx_L6_unpacking_failed;
-      __Pyx_GOTREF(__pyx_t_6);
-      if (__Pyx_IternextUnpackEndCheck(__pyx_t_8(__pyx_t_7), 2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 28; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-      __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;
-      goto __pyx_L7_unpacking_done;
-      __pyx_L6_unpacking_failed:;
-      __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;
-      if (PyErr_Occurred() && PyErr_ExceptionMatches(PyExc_StopIteration)) PyErr_Clear();
-      if (!PyErr_Occurred()) __Pyx_RaiseNeedMoreValuesError(index);
-      {__pyx_filename = __pyx_f[0]; __pyx_lineno = 28; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-      __pyx_L7_unpacking_done:;
-    }
-    __Pyx_XGOTREF(__pyx_cur_scope->__pyx_v_key);
-    __Pyx_XDECREF(__pyx_cur_scope->__pyx_v_key);
-    __Pyx_GIVEREF(__pyx_t_5);
-    __pyx_cur_scope->__pyx_v_key = __pyx_t_5;
-    __pyx_t_5 = 0;
-    __Pyx_XGOTREF(__pyx_cur_scope->__pyx_v_value);
-    __Pyx_XDECREF(__pyx_cur_scope->__pyx_v_value);
-    __Pyx_GIVEREF(__pyx_t_6);
-    __pyx_cur_scope->__pyx_v_value = __pyx_t_6;
-    __pyx_t_6 = 0;
+  if (__pyx_t_4) {
 
-    /* "_cdec.pyx":29
- * def _make_config(config):
- *     for key, value in config.items():
- *         if isinstance(value, dict):             # <<<<<<<<<<<<<<
- *             for name, info in value.items():
- *                 yield key, '%s %s' % (name, info)
+    /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":7
+ *         return x
+ *     elif x == 0 and isinstance(y, SufficientStats):
+ *         stats = SufficientStats()             # <<<<<<<<<<<<<<
+ *         stats.stats = new mteval.SufficientStats()
+ *         stats.metric = (<SufficientStats> y).metric
  */
-    __pyx_t_2 = ((PyObject *)((PyObject*)(&PyDict_Type)));
-    __Pyx_INCREF(__pyx_t_2);
-    __pyx_t_9 = __Pyx_TypeCheck(__pyx_cur_scope->__pyx_v_value, __pyx_t_2); 
-    __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
-    if (__pyx_t_9) {
+    __pyx_t_1 = PyObject_Call(((PyObject *)((PyObject*)__pyx_ptype_5_cdec_SufficientStats)), ((PyObject *)__pyx_empty_tuple), NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 7; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_1);
+    __pyx_v_stats = ((struct __pyx_obj_5_cdec_SufficientStats *)__pyx_t_1);
+    __pyx_t_1 = 0;
 
-      /* "_cdec.pyx":30
- *     for key, value in config.items():
- *         if isinstance(value, dict):
- *             for name, info in value.items():             # <<<<<<<<<<<<<<
- *                 yield key, '%s %s' % (name, info)
- *         elif isinstance(value, list):
+    /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":8
+ *     elif x == 0 and isinstance(y, SufficientStats):
+ *         stats = SufficientStats()
+ *         stats.stats = new mteval.SufficientStats()             # <<<<<<<<<<<<<<
+ *         stats.metric = (<SufficientStats> y).metric
+ *         return stats
  */
-      __pyx_t_2 = PyObject_GetAttr(__pyx_cur_scope->__pyx_v_value, __pyx_n_s__items); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 30; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-      __Pyx_GOTREF(__pyx_t_2);
-      __pyx_t_6 = PyObject_Call(__pyx_t_2, ((PyObject *)__pyx_empty_tuple), NULL); if (unlikely(!__pyx_t_6)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 30; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-      __Pyx_GOTREF(__pyx_t_6);
-      __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
-      if (PyList_CheckExact(__pyx_t_6) || PyTuple_CheckExact(__pyx_t_6)) {
-        __pyx_t_2 = __pyx_t_6; __Pyx_INCREF(__pyx_t_2); __pyx_t_10 = 0;
-        __pyx_t_11 = NULL;
-      } else {
-        __pyx_t_10 = -1; __pyx_t_2 = PyObject_GetIter(__pyx_t_6); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 30; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-        __Pyx_GOTREF(__pyx_t_2);
-        __pyx_t_11 = Py_TYPE(__pyx_t_2)->tp_iternext;
-      }
-      __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0;
-      for (;;) {
-        if (!__pyx_t_11 && PyList_CheckExact(__pyx_t_2)) {
-          if (__pyx_t_10 >= PyList_GET_SIZE(__pyx_t_2)) break;
-          __pyx_t_6 = PyList_GET_ITEM(__pyx_t_2, __pyx_t_10); __Pyx_INCREF(__pyx_t_6); __pyx_t_10++;
-        } else if (!__pyx_t_11 && PyTuple_CheckExact(__pyx_t_2)) {
-          if (__pyx_t_10 >= PyTuple_GET_SIZE(__pyx_t_2)) break;
-          __pyx_t_6 = PyTuple_GET_ITEM(__pyx_t_2, __pyx_t_10); __Pyx_INCREF(__pyx_t_6); __pyx_t_10++;
-        } else {
-          __pyx_t_6 = __pyx_t_11(__pyx_t_2);
-          if (unlikely(!__pyx_t_6)) {
-            if (PyErr_Occurred()) {
-              if (likely(PyErr_ExceptionMatches(PyExc_StopIteration))) PyErr_Clear();
-              else {__pyx_filename = __pyx_f[0]; __pyx_lineno = 30; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-            }
-            break;
-          }
-          __Pyx_GOTREF(__pyx_t_6);
-        }
-        if ((likely(PyTuple_CheckExact(__pyx_t_6))) || (PyList_CheckExact(__pyx_t_6))) {
-          PyObject* sequence = __pyx_t_6;
-          if (likely(PyTuple_CheckExact(sequence))) {
-            if (unlikely(PyTuple_GET_SIZE(sequence) != 2)) {
-              if (PyTuple_GET_SIZE(sequence) > 2) __Pyx_RaiseTooManyValuesError(2);
-              else __Pyx_RaiseNeedMoreValuesError(PyTuple_GET_SIZE(sequence));
-              {__pyx_filename = __pyx_f[0]; __pyx_lineno = 30; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-            }
-            __pyx_t_5 = PyTuple_GET_ITEM(sequence, 0); 
-            __pyx_t_7 = PyTuple_GET_ITEM(sequence, 1); 
-          } else {
-            if (unlikely(PyList_GET_SIZE(sequence) != 2)) {
-              if (PyList_GET_SIZE(sequence) > 2) __Pyx_RaiseTooManyValuesError(2);
-              else __Pyx_RaiseNeedMoreValuesError(PyList_GET_SIZE(sequence));
-              {__pyx_filename = __pyx_f[0]; __pyx_lineno = 30; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-            }
-            __pyx_t_5 = PyList_GET_ITEM(sequence, 0); 
-            __pyx_t_7 = PyList_GET_ITEM(sequence, 1); 
-          }
-          __Pyx_INCREF(__pyx_t_5);
-          __Pyx_INCREF(__pyx_t_7);
-          __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0;
-        } else {
-          Py_ssize_t index = -1;
-          __pyx_t_12 = PyObject_GetIter(__pyx_t_6); if (unlikely(!__pyx_t_12)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 30; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-          __Pyx_GOTREF(__pyx_t_12);
-          __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0;
-          __pyx_t_8 = Py_TYPE(__pyx_t_12)->tp_iternext;
-          index = 0; __pyx_t_5 = __pyx_t_8(__pyx_t_12); if (unlikely(!__pyx_t_5)) goto __pyx_L11_unpacking_failed;
-          __Pyx_GOTREF(__pyx_t_5);
-          index = 1; __pyx_t_7 = __pyx_t_8(__pyx_t_12); if (unlikely(!__pyx_t_7)) goto __pyx_L11_unpacking_failed;
-          __Pyx_GOTREF(__pyx_t_7);
-          if (__Pyx_IternextUnpackEndCheck(__pyx_t_8(__pyx_t_12), 2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 30; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-          __Pyx_DECREF(__pyx_t_12); __pyx_t_12 = 0;
-          goto __pyx_L12_unpacking_done;
-          __pyx_L11_unpacking_failed:;
-          __Pyx_DECREF(__pyx_t_12); __pyx_t_12 = 0;
-          if (PyErr_Occurred() && PyErr_ExceptionMatches(PyExc_StopIteration)) PyErr_Clear();
-          if (!PyErr_Occurred()) __Pyx_RaiseNeedMoreValuesError(index);
-          {__pyx_filename = __pyx_f[0]; __pyx_lineno = 30; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-          __pyx_L12_unpacking_done:;
-        }
-        __Pyx_XGOTREF(__pyx_cur_scope->__pyx_v_name);
-        __Pyx_XDECREF(__pyx_cur_scope->__pyx_v_name);
-        __Pyx_GIVEREF(__pyx_t_5);
-        __pyx_cur_scope->__pyx_v_name = __pyx_t_5;
-        __pyx_t_5 = 0;
-        __Pyx_XGOTREF(__pyx_cur_scope->__pyx_v_info);
-        __Pyx_XDECREF(__pyx_cur_scope->__pyx_v_info);
-        __Pyx_GIVEREF(__pyx_t_7);
-        __pyx_cur_scope->__pyx_v_info = __pyx_t_7;
-        __pyx_t_7 = 0;
+    __pyx_v_stats->stats = new SufficientStats();
 
-        /* "_cdec.pyx":31
- *         if isinstance(value, dict):
- *             for name, info in value.items():
- *                 yield key, '%s %s' % (name, info)             # <<<<<<<<<<<<<<
- *         elif isinstance(value, list):
- *             for name in value:
- */
-        __pyx_t_6 = PyTuple_New(2); if (unlikely(!__pyx_t_6)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 31; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-        __Pyx_GOTREF(__pyx_t_6);
-        __Pyx_INCREF(__pyx_cur_scope->__pyx_v_name);
-        PyTuple_SET_ITEM(__pyx_t_6, 0, __pyx_cur_scope->__pyx_v_name);
-        __Pyx_GIVEREF(__pyx_cur_scope->__pyx_v_name);
-        __Pyx_INCREF(__pyx_cur_scope->__pyx_v_info);
-        PyTuple_SET_ITEM(__pyx_t_6, 1, __pyx_cur_scope->__pyx_v_info);
-        __Pyx_GIVEREF(__pyx_cur_scope->__pyx_v_info);
-        __pyx_t_7 = PyNumber_Remainder(((PyObject *)__pyx_kp_s_39), ((PyObject *)__pyx_t_6)); if (unlikely(!__pyx_t_7)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 31; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-        __Pyx_GOTREF(((PyObject *)__pyx_t_7));
-        __Pyx_DECREF(((PyObject *)__pyx_t_6)); __pyx_t_6 = 0;
-        __pyx_t_6 = PyTuple_New(2); if (unlikely(!__pyx_t_6)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 31; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-        __Pyx_GOTREF(__pyx_t_6);
-        __Pyx_INCREF(__pyx_cur_scope->__pyx_v_key);
-        PyTuple_SET_ITEM(__pyx_t_6, 0, __pyx_cur_scope->__pyx_v_key);
-        __Pyx_GIVEREF(__pyx_cur_scope->__pyx_v_key);
-        PyTuple_SET_ITEM(__pyx_t_6, 1, ((PyObject *)__pyx_t_7));
-        __Pyx_GIVEREF(((PyObject *)__pyx_t_7));
-        __pyx_t_7 = 0;
-        __pyx_r = ((PyObject *)__pyx_t_6);
-        __pyx_t_6 = 0;
-        __Pyx_XGIVEREF(__pyx_t_1);
-        __pyx_cur_scope->__pyx_t_0 = __pyx_t_1;
-        __Pyx_XGIVEREF(__pyx_t_2);
-        __pyx_cur_scope->__pyx_t_1 = __pyx_t_2;
-        __pyx_cur_scope->__pyx_t_2 = __pyx_t_3;
-        __pyx_cur_scope->__pyx_t_3 = __pyx_t_4;
-        __pyx_cur_scope->__pyx_t_4 = __pyx_t_10;
-        __pyx_cur_scope->__pyx_t_5 = __pyx_t_11;
-        __Pyx_XGIVEREF(__pyx_r);
-        __Pyx_RefNannyFinishContext();
-        /* return from generator, yielding value */
-        __pyx_generator->resume_label = 1;
-        return __pyx_r;
-        __pyx_L13_resume_from_yield:;
-        __pyx_t_1 = __pyx_cur_scope->__pyx_t_0;
-        __pyx_cur_scope->__pyx_t_0 = 0;
-        __Pyx_XGOTREF(__pyx_t_1);
-        __pyx_t_2 = __pyx_cur_scope->__pyx_t_1;
-        __pyx_cur_scope->__pyx_t_1 = 0;
-        __Pyx_XGOTREF(__pyx_t_2);
-        __pyx_t_3 = __pyx_cur_scope->__pyx_t_2;
-        __pyx_t_4 = __pyx_cur_scope->__pyx_t_3;
-        __pyx_t_10 = __pyx_cur_scope->__pyx_t_4;
-        __pyx_t_11 = __pyx_cur_scope->__pyx_t_5;
-        if (unlikely(!__pyx_sent_value)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 31; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-      }
-      __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
-      goto __pyx_L8;
-    }
-
-    /* "_cdec.pyx":32
- *             for name, info in value.items():
- *                 yield key, '%s %s' % (name, info)
- *         elif isinstance(value, list):             # <<<<<<<<<<<<<<
- *             for name in value:
- *                 yield key, name
- */
-    __pyx_t_2 = ((PyObject *)((PyObject*)(&PyList_Type)));
-    __Pyx_INCREF(__pyx_t_2);
-    __pyx_t_9 = __Pyx_TypeCheck(__pyx_cur_scope->__pyx_v_value, __pyx_t_2); 
-    __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
-    if (__pyx_t_9) {
-
-      /* "_cdec.pyx":33
- *                 yield key, '%s %s' % (name, info)
- *         elif isinstance(value, list):
- *             for name in value:             # <<<<<<<<<<<<<<
- *                 yield key, name
- *         else:
- */
-      if (PyList_CheckExact(__pyx_cur_scope->__pyx_v_value) || PyTuple_CheckExact(__pyx_cur_scope->__pyx_v_value)) {
-        __pyx_t_2 = __pyx_cur_scope->__pyx_v_value; __Pyx_INCREF(__pyx_t_2); __pyx_t_10 = 0;
-        __pyx_t_11 = NULL;
-      } else {
-        __pyx_t_10 = -1; __pyx_t_2 = PyObject_GetIter(__pyx_cur_scope->__pyx_v_value); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 33; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-        __Pyx_GOTREF(__pyx_t_2);
-        __pyx_t_11 = Py_TYPE(__pyx_t_2)->tp_iternext;
-      }
-      for (;;) {
-        if (!__pyx_t_11 && PyList_CheckExact(__pyx_t_2)) {
-          if (__pyx_t_10 >= PyList_GET_SIZE(__pyx_t_2)) break;
-          __pyx_t_6 = PyList_GET_ITEM(__pyx_t_2, __pyx_t_10); __Pyx_INCREF(__pyx_t_6); __pyx_t_10++;
-        } else if (!__pyx_t_11 && PyTuple_CheckExact(__pyx_t_2)) {
-          if (__pyx_t_10 >= PyTuple_GET_SIZE(__pyx_t_2)) break;
-          __pyx_t_6 = PyTuple_GET_ITEM(__pyx_t_2, __pyx_t_10); __Pyx_INCREF(__pyx_t_6); __pyx_t_10++;
-        } else {
-          __pyx_t_6 = __pyx_t_11(__pyx_t_2);
-          if (unlikely(!__pyx_t_6)) {
-            if (PyErr_Occurred()) {
-              if (likely(PyErr_ExceptionMatches(PyExc_StopIteration))) PyErr_Clear();
-              else {__pyx_filename = __pyx_f[0]; __pyx_lineno = 33; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-            }
-            break;
-          }
-          __Pyx_GOTREF(__pyx_t_6);
-        }
-        __Pyx_XGOTREF(__pyx_cur_scope->__pyx_v_name);
-        __Pyx_XDECREF(__pyx_cur_scope->__pyx_v_name);
-        __Pyx_GIVEREF(__pyx_t_6);
-        __pyx_cur_scope->__pyx_v_name = __pyx_t_6;
-        __pyx_t_6 = 0;
-
-        /* "_cdec.pyx":34
- *         elif isinstance(value, list):
- *             for name in value:
- *                 yield key, name             # <<<<<<<<<<<<<<
- *         else:
- *             yield key, bytes(value)
+    /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":9
+ *         stats = SufficientStats()
+ *         stats.stats = new mteval.SufficientStats()
+ *         stats.metric = (<SufficientStats> y).metric             # <<<<<<<<<<<<<<
+ *         return stats
+ * 
  */
-        __pyx_t_6 = PyTuple_New(2); if (unlikely(!__pyx_t_6)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 34; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-        __Pyx_GOTREF(__pyx_t_6);
-        __Pyx_INCREF(__pyx_cur_scope->__pyx_v_key);
-        PyTuple_SET_ITEM(__pyx_t_6, 0, __pyx_cur_scope->__pyx_v_key);
-        __Pyx_GIVEREF(__pyx_cur_scope->__pyx_v_key);
-        __Pyx_INCREF(__pyx_cur_scope->__pyx_v_name);
-        PyTuple_SET_ITEM(__pyx_t_6, 1, __pyx_cur_scope->__pyx_v_name);
-        __Pyx_GIVEREF(__pyx_cur_scope->__pyx_v_name);
-        __pyx_r = ((PyObject *)__pyx_t_6);
-        __pyx_t_6 = 0;
-        __Pyx_XGIVEREF(__pyx_t_1);
-        __pyx_cur_scope->__pyx_t_0 = __pyx_t_1;
-        __Pyx_XGIVEREF(__pyx_t_2);
-        __pyx_cur_scope->__pyx_t_1 = __pyx_t_2;
-        __pyx_cur_scope->__pyx_t_2 = __pyx_t_3;
-        __pyx_cur_scope->__pyx_t_3 = __pyx_t_4;
-        __pyx_cur_scope->__pyx_t_4 = __pyx_t_10;
-        __pyx_cur_scope->__pyx_t_5 = __pyx_t_11;
-        __Pyx_XGIVEREF(__pyx_r);
-        __Pyx_RefNannyFinishContext();
-        /* return from generator, yielding value */
-        __pyx_generator->resume_label = 2;
-        return __pyx_r;
-        __pyx_L16_resume_from_yield:;
-        __pyx_t_1 = __pyx_cur_scope->__pyx_t_0;
-        __pyx_cur_scope->__pyx_t_0 = 0;
-        __Pyx_XGOTREF(__pyx_t_1);
-        __pyx_t_2 = __pyx_cur_scope->__pyx_t_1;
-        __pyx_cur_scope->__pyx_t_1 = 0;
-        __Pyx_XGOTREF(__pyx_t_2);
-        __pyx_t_3 = __pyx_cur_scope->__pyx_t_2;
-        __pyx_t_4 = __pyx_cur_scope->__pyx_t_3;
-        __pyx_t_10 = __pyx_cur_scope->__pyx_t_4;
-        __pyx_t_11 = __pyx_cur_scope->__pyx_t_5;
-        if (unlikely(!__pyx_sent_value)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 34; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-      }
-      __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
-      goto __pyx_L8;
-    }
-    /*else*/ {
+    __pyx_v_stats->metric = ((struct __pyx_obj_5_cdec_SufficientStats *)__pyx_v_y)->metric;
 
-      /* "_cdec.pyx":36
- *                 yield key, name
- *         else:
- *             yield key, bytes(value)             # <<<<<<<<<<<<<<
+    /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":10
+ *         stats.stats = new mteval.SufficientStats()
+ *         stats.metric = (<SufficientStats> y).metric
+ *         return stats             # <<<<<<<<<<<<<<
  * 
- * cdef class Decoder:
+ * cdef class Candidate:
  */
-      __pyx_t_2 = PyTuple_New(1); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 36; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-      __Pyx_GOTREF(__pyx_t_2);
-      __Pyx_INCREF(__pyx_cur_scope->__pyx_v_value);
-      PyTuple_SET_ITEM(__pyx_t_2, 0, __pyx_cur_scope->__pyx_v_value);
-      __Pyx_GIVEREF(__pyx_cur_scope->__pyx_v_value);
-      __pyx_t_6 = PyObject_Call(((PyObject *)((PyObject*)(&PyBytes_Type))), ((PyObject *)__pyx_t_2), NULL); if (unlikely(!__pyx_t_6)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 36; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-      __Pyx_GOTREF(__pyx_t_6);
-      __Pyx_DECREF(((PyObject *)__pyx_t_2)); __pyx_t_2 = 0;
-      __pyx_t_2 = PyTuple_New(2); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 36; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-      __Pyx_GOTREF(__pyx_t_2);
-      __Pyx_INCREF(__pyx_cur_scope->__pyx_v_key);
-      PyTuple_SET_ITEM(__pyx_t_2, 0, __pyx_cur_scope->__pyx_v_key);
-      __Pyx_GIVEREF(__pyx_cur_scope->__pyx_v_key);
-      PyTuple_SET_ITEM(__pyx_t_2, 1, __pyx_t_6);
-      __Pyx_GIVEREF(__pyx_t_6);
-      __pyx_t_6 = 0;
-      __pyx_r = ((PyObject *)__pyx_t_2);
-      __pyx_t_2 = 0;
-      __Pyx_XGIVEREF(__pyx_t_1);
-      __pyx_cur_scope->__pyx_t_0 = __pyx_t_1;
-      __pyx_cur_scope->__pyx_t_2 = __pyx_t_3;
-      __pyx_cur_scope->__pyx_t_3 = __pyx_t_4;
-      __Pyx_XGIVEREF(__pyx_r);
-      __Pyx_RefNannyFinishContext();
-      /* return from generator, yielding value */
-      __pyx_generator->resume_label = 3;
-      return __pyx_r;
-      __pyx_L17_resume_from_yield:;
-      __pyx_t_1 = __pyx_cur_scope->__pyx_t_0;
-      __pyx_cur_scope->__pyx_t_0 = 0;
-      __Pyx_XGOTREF(__pyx_t_1);
-      __pyx_t_3 = __pyx_cur_scope->__pyx_t_2;
-      __pyx_t_4 = __pyx_cur_scope->__pyx_t_3;
-      if (unlikely(!__pyx_sent_value)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 36; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-    }
-    __pyx_L8:;
+    __Pyx_XDECREF(((PyObject *)__pyx_r));
+    __Pyx_INCREF(((PyObject *)__pyx_v_stats));
+    __pyx_r = __pyx_v_stats;
+    goto __pyx_L0;
+    goto __pyx_L3;
   }
-  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
-  PyErr_SetNone(PyExc_StopIteration);
+  __pyx_L3:;
+
+  __pyx_r = ((struct __pyx_obj_5_cdec_SufficientStats *)Py_None); __Pyx_INCREF(Py_None);
   goto __pyx_L0;
   __pyx_L1_error:;
   __Pyx_XDECREF(__pyx_t_1);
-  __Pyx_XDECREF(__pyx_t_2);
-  __Pyx_XDECREF(__pyx_t_5);
-  __Pyx_XDECREF(__pyx_t_6);
-  __Pyx_XDECREF(__pyx_t_7);
-  __Pyx_XDECREF(__pyx_t_12);
-  __Pyx_AddTraceback("_make_config", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __Pyx_AddTraceback("_cdec.as_stats", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __pyx_r = 0;
   __pyx_L0:;
-  __Pyx_XDECREF(__pyx_r);
-  __pyx_generator->resume_label = -1;
+  __Pyx_XDECREF((PyObject *)__pyx_v_stats);
+  __Pyx_XGIVEREF((PyObject *)__pyx_r);
   __Pyx_RefNannyFinishContext();
-  return NULL;
+  return __pyx_r;
 }
 
 /* Python wrapper */
-static int __pyx_pw_5_cdec_7Decoder_1__cinit__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/
-static int __pyx_pw_5_cdec_7Decoder_1__cinit__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) {
-  PyObject *__pyx_v_config_str = 0;
-  PyObject *__pyx_v_config = 0;
-  static PyObject **__pyx_pyargnames[] = {&__pyx_n_s__config_str,0};
-  int __pyx_r;
+static PyObject *__pyx_pw_5_cdec_9Candidate_5words_1__get__(PyObject *__pyx_v_self); /*proto*/
+static PyObject *__pyx_pw_5_cdec_9Candidate_5words_1__get__(PyObject *__pyx_v_self) {
+  PyObject *__pyx_r = 0;
   __Pyx_RefNannyDeclarations
-  __Pyx_RefNannySetupContext("__cinit__ (wrapper)", 0);
-  __pyx_v_config = PyDict_New(); if (unlikely(!__pyx_v_config)) return -1;
-  __Pyx_GOTREF(__pyx_v_config);
-  {
-    PyObject* values[1] = {0};
+  __Pyx_RefNannySetupContext("__get__ (wrapper)", 0);
+  __pyx_r = __pyx_pf_5_cdec_9Candidate_5words___get__(((struct __pyx_obj_5_cdec_Candidate *)__pyx_v_self));
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
 
-    /* "_cdec.pyx":42
- *     cdef DenseVector weights
+/* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":17
+ * 
+ *     property words:
+ *         def __get__(self):             # <<<<<<<<<<<<<<
+ *             return unicode(GetString(self.candidate.ewords).c_str(), encoding='utf8')
  * 
- *     def __cinit__(self, config_str=None, **config):             # <<<<<<<<<<<<<<
- *         """ Configuration can be given as a string:
- *                 Decoder('formalism = scfg')
- */
-    values[0] = ((PyObject *)Py_None);
-    if (unlikely(__pyx_kwds)) {
-      Py_ssize_t kw_args;
-      const Py_ssize_t pos_args = PyTuple_GET_SIZE(__pyx_args);
-      switch (pos_args) {
-        case  1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0);
-        case  0: break;
-        default: goto __pyx_L5_argtuple_error;
-      }
-      kw_args = PyDict_Size(__pyx_kwds);
-      switch (pos_args) {
-        case  0:
-        if (kw_args > 0) {
-          PyObject* value = PyDict_GetItem(__pyx_kwds, __pyx_n_s__config_str);
-          if (value) { values[0] = value; kw_args--; }
-        }
-      }
-      if (unlikely(kw_args > 0)) {
-        if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, __pyx_v_config, values, pos_args, "__cinit__") < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 42; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
-      }
-    } else {
-      switch (PyTuple_GET_SIZE(__pyx_args)) {
-        case  1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0);
-        case  0: break;
-        default: goto __pyx_L5_argtuple_error;
-      }
-    }
-    __pyx_v_config_str = values[0];
-  }
-  goto __pyx_L4_argument_unpacking_done;
-  __pyx_L5_argtuple_error:;
-  __Pyx_RaiseArgtupleInvalid("__cinit__", 0, 0, 1, PyTuple_GET_SIZE(__pyx_args)); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 42; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
-  __pyx_L3_error:;
-  __Pyx_CLEAR(__pyx_v_config);
-  __Pyx_AddTraceback("_cdec.Decoder.__cinit__", __pyx_clineno, __pyx_lineno, __pyx_filename);
-  __Pyx_RefNannyFinishContext();
-  return -1;
-  __pyx_L4_argument_unpacking_done:;
-  __pyx_r = __pyx_pf_5_cdec_7Decoder___cinit__(((struct __pyx_obj_5_cdec_Decoder *)__pyx_v_self), __pyx_v_config_str, __pyx_v_config);
-  __Pyx_XDECREF(__pyx_v_config);
-  __Pyx_RefNannyFinishContext();
-  return __pyx_r;
-}
-static PyObject *__pyx_gb_5_cdec_7Decoder_9__cinit___2generator18(__pyx_GeneratorObject *__pyx_generator, PyObject *__pyx_sent_value); /* proto */
-
-/* "_cdec.pyx":53
- *                     'csplit', 'tagger', 'lexalign'):
- *                 raise InvalidConfig('formalism "%s" unknown' % formalism)
- *             config_str = '\n'.join('%s = %s' % kv for kv in _make_config(config))             # <<<<<<<<<<<<<<
- *         cdef istringstream* config_stream = new istringstream(config_str)
- *         self.dec = new decoder.Decoder(config_stream)
  */
 
-static PyObject *__pyx_pf_5_cdec_7Decoder_9__cinit___genexpr(PyObject *__pyx_self) {
-  struct __pyx_obj_5_cdec___pyx_scope_struct_22_genexpr *__pyx_cur_scope;
+static PyObject *__pyx_pf_5_cdec_9Candidate_5words___get__(struct __pyx_obj_5_cdec_Candidate *__pyx_v_self) {
   PyObject *__pyx_r = NULL;
   __Pyx_RefNannyDeclarations
+  PyObject *__pyx_t_1 = NULL;
+  PyObject *__pyx_t_2 = NULL;
+  PyObject *__pyx_t_3 = NULL;
   int __pyx_lineno = 0;
   const char *__pyx_filename = NULL;
   int __pyx_clineno = 0;
-  __Pyx_RefNannySetupContext("genexpr", 0);
-  __pyx_cur_scope = (struct __pyx_obj_5_cdec___pyx_scope_struct_22_genexpr *)__pyx_ptype_5_cdec___pyx_scope_struct_22_genexpr->tp_new(__pyx_ptype_5_cdec___pyx_scope_struct_22_genexpr, __pyx_empty_tuple, NULL);
-  if (unlikely(!__pyx_cur_scope)) {
-    __Pyx_RefNannyFinishContext();
-    return NULL;
-  }
-  __Pyx_GOTREF(__pyx_cur_scope);
-  __pyx_cur_scope->__pyx_outer_scope = (struct __pyx_obj_5_cdec___pyx_scope_struct_21___cinit__ *) __pyx_self;
-  __Pyx_INCREF(((PyObject *)__pyx_cur_scope->__pyx_outer_scope));
-  __Pyx_GIVEREF(__pyx_cur_scope->__pyx_outer_scope);
-  {
-    __pyx_GeneratorObject *gen = __Pyx_Generator_New((__pyx_generator_body_t) __pyx_gb_5_cdec_7Decoder_9__cinit___2generator18, (PyObject *) __pyx_cur_scope); if (unlikely(!gen)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 53; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-    __Pyx_DECREF(__pyx_cur_scope);
-    __Pyx_RefNannyFinishContext();
-    return (PyObject *) gen;
-  }
+  __Pyx_RefNannySetupContext("__get__", 0);
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":18
+ *     property words:
+ *         def __get__(self):
+ *             return unicode(GetString(self.candidate.ewords).c_str(), encoding='utf8')             # <<<<<<<<<<<<<<
+ * 
+ *     property fmap:
+ */
+  __Pyx_XDECREF(__pyx_r);
+  __pyx_t_1 = PyBytes_FromString(TD::GetString(__pyx_v_self->candidate->ewords).c_str()); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 18; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(((PyObject *)__pyx_t_1));
+  __pyx_t_2 = PyTuple_New(1); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 18; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_2);
+  PyTuple_SET_ITEM(__pyx_t_2, 0, ((PyObject *)__pyx_t_1));
+  __Pyx_GIVEREF(((PyObject *)__pyx_t_1));
+  __pyx_t_1 = 0;
+  __pyx_t_1 = PyDict_New(); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 18; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(((PyObject *)__pyx_t_1));
+  if (PyDict_SetItem(__pyx_t_1, ((PyObject *)__pyx_n_s__encoding), ((PyObject *)__pyx_n_s__utf8)) < 0) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 18; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_3 = PyObject_Call(((PyObject *)((PyObject*)(&PyUnicode_Type))), ((PyObject *)__pyx_t_2), ((PyObject *)__pyx_t_1)); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 18; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_3);
+  __Pyx_DECREF(((PyObject *)__pyx_t_2)); __pyx_t_2 = 0;
+  __Pyx_DECREF(((PyObject *)__pyx_t_1)); __pyx_t_1 = 0;
+  __pyx_r = __pyx_t_3;
+  __pyx_t_3 = 0;
+  goto __pyx_L0;
 
   __pyx_r = Py_None; __Pyx_INCREF(Py_None);
   goto __pyx_L0;
   __pyx_L1_error:;
-  __Pyx_AddTraceback("_cdec.Decoder.__cinit__.genexpr", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __Pyx_XDECREF(__pyx_t_1);
+  __Pyx_XDECREF(__pyx_t_2);
+  __Pyx_XDECREF(__pyx_t_3);
+  __Pyx_AddTraceback("_cdec.Candidate.words.__get__", __pyx_clineno, __pyx_lineno, __pyx_filename);
   __pyx_r = NULL;
   __pyx_L0:;
-  __Pyx_DECREF(((PyObject *)__pyx_cur_scope));
   __Pyx_XGIVEREF(__pyx_r);
   __Pyx_RefNannyFinishContext();
   return __pyx_r;
 }
 
-static PyObject *__pyx_gb_5_cdec_7Decoder_9__cinit___2generator18(__pyx_GeneratorObject *__pyx_generator, PyObject *__pyx_sent_value) /* generator body */
-{
-  struct __pyx_obj_5_cdec___pyx_scope_struct_22_genexpr *__pyx_cur_scope = ((struct __pyx_obj_5_cdec___pyx_scope_struct_22_genexpr *)__pyx_generator->closure);
-  PyObject *__pyx_r = NULL;
-  PyObject *__pyx_t_1 = NULL;
-  PyObject *__pyx_t_2 = NULL;
-  PyObject *__pyx_t_3 = NULL;
-  Py_ssize_t __pyx_t_4;
-  PyObject *(*__pyx_t_5)(PyObject *);
+/* Python wrapper */
+static PyObject *__pyx_pw_5_cdec_9Candidate_4fmap_1__get__(PyObject *__pyx_v_self); /*proto*/
+static PyObject *__pyx_pw_5_cdec_9Candidate_4fmap_1__get__(PyObject *__pyx_v_self) {
+  PyObject *__pyx_r = 0;
   __Pyx_RefNannyDeclarations
-  __Pyx_RefNannySetupContext("None", 0);
-  switch (__pyx_generator->resume_label) {
-    case 0: goto __pyx_L3_first_run;
-    case 1: goto __pyx_L6_resume_from_yield;
-    default: /* CPython raises the right error here */
-    __Pyx_RefNannyFinishContext();
-    return NULL;
-  }
-  __pyx_L3_first_run:;
-  if (unlikely(!__pyx_sent_value)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 53; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __pyx_t_1 = __Pyx_GetName(__pyx_m, __pyx_n_s___make_config); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 53; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __Pyx_GOTREF(__pyx_t_1);
-  if (unlikely(!__pyx_cur_scope->__pyx_outer_scope->__pyx_v_config)) { __Pyx_RaiseClosureNameError("config"); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 53; __pyx_clineno = __LINE__; goto __pyx_L1_error;} }
-  __pyx_t_2 = PyTuple_New(1); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 53; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __Pyx_GOTREF(__pyx_t_2);
-  __Pyx_INCREF(__pyx_cur_scope->__pyx_outer_scope->__pyx_v_config);
-  PyTuple_SET_ITEM(__pyx_t_2, 0, __pyx_cur_scope->__pyx_outer_scope->__pyx_v_config);
-  __Pyx_GIVEREF(__pyx_cur_scope->__pyx_outer_scope->__pyx_v_config);
-  __pyx_t_3 = PyObject_Call(__pyx_t_1, ((PyObject *)__pyx_t_2), NULL); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 53; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __Pyx_GOTREF(__pyx_t_3);
-  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
-  __Pyx_DECREF(((PyObject *)__pyx_t_2)); __pyx_t_2 = 0;
-  if (PyList_CheckExact(__pyx_t_3) || PyTuple_CheckExact(__pyx_t_3)) {
-    __pyx_t_2 = __pyx_t_3; __Pyx_INCREF(__pyx_t_2); __pyx_t_4 = 0;
-    __pyx_t_5 = NULL;
-  } else {
-    __pyx_t_4 = -1; __pyx_t_2 = PyObject_GetIter(__pyx_t_3); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 53; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-    __Pyx_GOTREF(__pyx_t_2);
-    __pyx_t_5 = Py_TYPE(__pyx_t_2)->tp_iternext;
-  }
-  __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
-  for (;;) {
-    if (!__pyx_t_5 && PyList_CheckExact(__pyx_t_2)) {
-      if (__pyx_t_4 >= PyList_GET_SIZE(__pyx_t_2)) break;
-      __pyx_t_3 = PyList_GET_ITEM(__pyx_t_2, __pyx_t_4); __Pyx_INCREF(__pyx_t_3); __pyx_t_4++;
-    } else if (!__pyx_t_5 && PyTuple_CheckExact(__pyx_t_2)) {
-      if (__pyx_t_4 >= PyTuple_GET_SIZE(__pyx_t_2)) break;
-      __pyx_t_3 = PyTuple_GET_ITEM(__pyx_t_2, __pyx_t_4); __Pyx_INCREF(__pyx_t_3); __pyx_t_4++;
-    } else {
-      __pyx_t_3 = __pyx_t_5(__pyx_t_2);
-      if (unlikely(!__pyx_t_3)) {
-        if (PyErr_Occurred()) {
-          if (likely(PyErr_ExceptionMatches(PyExc_StopIteration))) PyErr_Clear();
-          else {__pyx_filename = __pyx_f[0]; __pyx_lineno = 53; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-        }
-        break;
-      }
-      __Pyx_GOTREF(__pyx_t_3);
-    }
-    __Pyx_XGOTREF(__pyx_cur_scope->__pyx_v_kv);
-    __Pyx_XDECREF(__pyx_cur_scope->__pyx_v_kv);
-    __Pyx_GIVEREF(__pyx_t_3);
-    __pyx_cur_scope->__pyx_v_kv = __pyx_t_3;
-    __pyx_t_3 = 0;
-    __pyx_t_3 = PyNumber_Remainder(((PyObject *)__pyx_kp_s_40), __pyx_cur_scope->__pyx_v_kv); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 53; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-    __Pyx_GOTREF(((PyObject *)__pyx_t_3));
-    __pyx_r = ((PyObject *)__pyx_t_3);
-    __pyx_t_3 = 0;
-    __Pyx_XGIVEREF(__pyx_t_2);
-    __pyx_cur_scope->__pyx_t_0 = __pyx_t_2;
-    __pyx_cur_scope->__pyx_t_1 = __pyx_t_4;
-    __pyx_cur_scope->__pyx_t_2 = __pyx_t_5;
-    __Pyx_XGIVEREF(__pyx_r);
-    __Pyx_RefNannyFinishContext();
-    /* return from generator, yielding value */
-    __pyx_generator->resume_label = 1;
-    return __pyx_r;
-    __pyx_L6_resume_from_yield:;
-    __pyx_t_2 = __pyx_cur_scope->__pyx_t_0;
-    __pyx_cur_scope->__pyx_t_0 = 0;
-    __Pyx_XGOTREF(__pyx_t_2);
-    __pyx_t_4 = __pyx_cur_scope->__pyx_t_1;
-    __pyx_t_5 = __pyx_cur_scope->__pyx_t_2;
-    if (unlikely(!__pyx_sent_value)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 53; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  }
-  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
-  PyErr_SetNone(PyExc_StopIteration);
-  goto __pyx_L0;
-  __pyx_L1_error:;
-  __Pyx_XDECREF(__pyx_t_1);
-  __Pyx_XDECREF(__pyx_t_2);
-  __Pyx_XDECREF(__pyx_t_3);
-  __Pyx_AddTraceback("genexpr", __pyx_clineno, __pyx_lineno, __pyx_filename);
-  __pyx_L0:;
-  __Pyx_XDECREF(__pyx_r);
-  __pyx_generator->resume_label = -1;
+  __Pyx_RefNannySetupContext("__get__ (wrapper)", 0);
+  __pyx_r = __pyx_pf_5_cdec_9Candidate_4fmap___get__(((struct __pyx_obj_5_cdec_Candidate *)__pyx_v_self));
   __Pyx_RefNannyFinishContext();
-  return NULL;
+  return __pyx_r;
 }
 
-/* "_cdec.pyx":42
- *     cdef DenseVector weights
+/* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":21
  * 
- *     def __cinit__(self, config_str=None, **config):             # <<<<<<<<<<<<<<
- *         """ Configuration can be given as a string:
- *                 Decoder('formalism = scfg')
+ *     property fmap:
+ *         def __get__(self):             # <<<<<<<<<<<<<<
+ *             cdef SparseVector fmap = SparseVector()
+ *             fmap.vector = new FastSparseVector[weight_t](self.candidate.fmap)
  */
 
-static int __pyx_pf_5_cdec_7Decoder___cinit__(struct __pyx_obj_5_cdec_Decoder *__pyx_v_self, PyObject *__pyx_v_config_str, PyObject *__pyx_v_config) {
-  struct __pyx_obj_5_cdec___pyx_scope_struct_21___cinit__ *__pyx_cur_scope;
-  PyObject *__pyx_v_formalism = NULL;
-  std::istringstream *__pyx_v_config_stream;
-  int __pyx_r;
+static PyObject *__pyx_pf_5_cdec_9Candidate_4fmap___get__(struct __pyx_obj_5_cdec_Candidate *__pyx_v_self) {
+  struct __pyx_obj_5_cdec_SparseVector *__pyx_v_fmap = 0;
+  PyObject *__pyx_r = NULL;
   __Pyx_RefNannyDeclarations
-  int __pyx_t_1;
-  PyObject *__pyx_t_2 = NULL;
-  PyObject *__pyx_t_3 = NULL;
-  int __pyx_t_4;
-  int __pyx_t_5;
-  PyObject *__pyx_t_6 = NULL;
-  char *__pyx_t_7;
+  PyObject *__pyx_t_1 = NULL;
   int __pyx_lineno = 0;
   const char *__pyx_filename = NULL;
   int __pyx_clineno = 0;
-  __Pyx_RefNannySetupContext("__cinit__", 0);
-  __pyx_cur_scope = (struct __pyx_obj_5_cdec___pyx_scope_struct_21___cinit__ *)__pyx_ptype_5_cdec___pyx_scope_struct_21___cinit__->tp_new(__pyx_ptype_5_cdec___pyx_scope_struct_21___cinit__, __pyx_empty_tuple, NULL);
-  if (unlikely(!__pyx_cur_scope)) {
-    __Pyx_RefNannyFinishContext();
-    return -1;
-  }
-  __Pyx_GOTREF(__pyx_cur_scope);
-  __pyx_cur_scope->__pyx_v_config = __pyx_v_config;
-  __Pyx_INCREF(__pyx_cur_scope->__pyx_v_config);
-  __Pyx_GIVEREF(__pyx_cur_scope->__pyx_v_config);
-  __Pyx_INCREF(__pyx_v_config_str);
+  __Pyx_RefNannySetupContext("__get__", 0);
 
-  /* "_cdec.pyx":48
- *                 Decoder(formalism='scfg')
- *         """
- *         if config_str is None:             # <<<<<<<<<<<<<<
- *             formalism = config.get('formalism', None)
- *             if formalism not in ('scfg', 'fst', 'lextrans', 'pb',
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":22
+ *     property fmap:
+ *         def __get__(self):
+ *             cdef SparseVector fmap = SparseVector()             # <<<<<<<<<<<<<<
+ *             fmap.vector = new FastSparseVector[weight_t](self.candidate.fmap)
+ *             return fmap
  */
-  __pyx_t_1 = (__pyx_v_config_str == Py_None);
-  if (__pyx_t_1) {
+  __pyx_t_1 = PyObject_Call(((PyObject *)((PyObject*)__pyx_ptype_5_cdec_SparseVector)), ((PyObject *)__pyx_empty_tuple), NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 22; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_1);
+  __pyx_v_fmap = ((struct __pyx_obj_5_cdec_SparseVector *)__pyx_t_1);
+  __pyx_t_1 = 0;
 
-    /* "_cdec.pyx":49
- *         """
- *         if config_str is None:
- *             formalism = config.get('formalism', None)             # <<<<<<<<<<<<<<
- *             if formalism not in ('scfg', 'fst', 'lextrans', 'pb',
- *                     'csplit', 'tagger', 'lexalign'):
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":23
+ *         def __get__(self):
+ *             cdef SparseVector fmap = SparseVector()
+ *             fmap.vector = new FastSparseVector[weight_t](self.candidate.fmap)             # <<<<<<<<<<<<<<
+ *             return fmap
+ * 
  */
-    __pyx_t_2 = PyObject_GetAttr(__pyx_cur_scope->__pyx_v_config, __pyx_n_s__get); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 49; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-    __Pyx_GOTREF(__pyx_t_2);
-    __pyx_t_3 = PyObject_Call(__pyx_t_2, ((PyObject *)__pyx_k_tuple_41), NULL); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 49; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-    __Pyx_GOTREF(__pyx_t_3);
-    __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
-    __pyx_v_formalism = __pyx_t_3;
-    __pyx_t_3 = 0;
+  __pyx_v_fmap->vector = new FastSparseVector<weight_t>(__pyx_v_self->candidate->fmap);
 
-    /* "_cdec.pyx":50
- *         if config_str is None:
- *             formalism = config.get('formalism', None)
- *             if formalism not in ('scfg', 'fst', 'lextrans', 'pb',             # <<<<<<<<<<<<<<
- *                     'csplit', 'tagger', 'lexalign'):
- *                 raise InvalidConfig('formalism "%s" unknown' % formalism)
- */
-    __Pyx_INCREF(__pyx_v_formalism);
-    __pyx_t_3 = __pyx_v_formalism;
-    __pyx_t_1 = __Pyx_PyString_Equals(__pyx_t_3, ((PyObject *)__pyx_n_s__scfg), Py_NE); if (unlikely(__pyx_t_1 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 50; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-    if (((int)__pyx_t_1)) {
-      __pyx_t_4 = __Pyx_PyString_Equals(__pyx_t_3, ((PyObject *)__pyx_n_s__fst), Py_NE); if (unlikely(__pyx_t_4 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 50; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-      __pyx_t_5 = ((int)__pyx_t_4);
-    } else {
-      __pyx_t_5 = ((int)__pyx_t_1);
-    }
-    if (__pyx_t_5) {
-      __pyx_t_1 = __Pyx_PyString_Equals(__pyx_t_3, ((PyObject *)__pyx_n_s__lextrans), Py_NE); if (unlikely(__pyx_t_1 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 50; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-      __pyx_t_4 = ((int)__pyx_t_1);
-    } else {
-      __pyx_t_4 = __pyx_t_5;
-    }
-    if (__pyx_t_4) {
-      __pyx_t_5 = __Pyx_PyString_Equals(__pyx_t_3, ((PyObject *)__pyx_n_s__pb), Py_NE); if (unlikely(__pyx_t_5 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 50; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-      __pyx_t_1 = ((int)__pyx_t_5);
-    } else {
-      __pyx_t_1 = __pyx_t_4;
-    }
-    if (__pyx_t_1) {
-      __pyx_t_4 = __Pyx_PyString_Equals(__pyx_t_3, ((PyObject *)__pyx_n_s__csplit), Py_NE); if (unlikely(__pyx_t_4 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 50; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-      __pyx_t_5 = ((int)__pyx_t_4);
-    } else {
-      __pyx_t_5 = __pyx_t_1;
-    }
-    if (__pyx_t_5) {
-      __pyx_t_1 = __Pyx_PyString_Equals(__pyx_t_3, ((PyObject *)__pyx_n_s__tagger), Py_NE); if (unlikely(__pyx_t_1 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 50; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-      __pyx_t_4 = ((int)__pyx_t_1);
-    } else {
-      __pyx_t_4 = __pyx_t_5;
-    }
-    if (__pyx_t_4) {
-      __pyx_t_5 = __Pyx_PyString_Equals(__pyx_t_3, ((PyObject *)__pyx_n_s__lexalign), Py_NE); if (unlikely(__pyx_t_5 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 50; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-      __pyx_t_1 = ((int)__pyx_t_5);
-    } else {
-      __pyx_t_1 = __pyx_t_4;
-    }
-    __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
-    __pyx_t_4 = __pyx_t_1;
-    if (__pyx_t_4) {
-
-      /* "_cdec.pyx":52
- *             if formalism not in ('scfg', 'fst', 'lextrans', 'pb',
- *                     'csplit', 'tagger', 'lexalign'):
- *                 raise InvalidConfig('formalism "%s" unknown' % formalism)             # <<<<<<<<<<<<<<
- *             config_str = '\n'.join('%s = %s' % kv for kv in _make_config(config))
- *         cdef istringstream* config_stream = new istringstream(config_str)
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":24
+ *             cdef SparseVector fmap = SparseVector()
+ *             fmap.vector = new FastSparseVector[weight_t](self.candidate.fmap)
+ *             return fmap             # <<<<<<<<<<<<<<
+ * 
+ * cdef class SufficientStats:
  */
-      __pyx_t_3 = __Pyx_GetName(__pyx_m, __pyx_n_s__InvalidConfig); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 52; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-      __Pyx_GOTREF(__pyx_t_3);
-      __pyx_t_2 = PyNumber_Remainder(((PyObject *)__pyx_kp_s_42), __pyx_v_formalism); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 52; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-      __Pyx_GOTREF(((PyObject *)__pyx_t_2));
-      __pyx_t_6 = PyTuple_New(1); if (unlikely(!__pyx_t_6)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 52; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-      __Pyx_GOTREF(__pyx_t_6);
-      PyTuple_SET_ITEM(__pyx_t_6, 0, ((PyObject *)__pyx_t_2));
-      __Pyx_GIVEREF(((PyObject *)__pyx_t_2));
-      __pyx_t_2 = 0;
-      __pyx_t_2 = PyObject_Call(__pyx_t_3, ((PyObject *)__pyx_t_6), NULL); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 52; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-      __Pyx_GOTREF(__pyx_t_2);
-      __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
-      __Pyx_DECREF(((PyObject *)__pyx_t_6)); __pyx_t_6 = 0;
-      __Pyx_Raise(__pyx_t_2, 0, 0, 0);
-      __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
-      {__pyx_filename = __pyx_f[0]; __pyx_lineno = 52; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-      goto __pyx_L4;
-    }
-    __pyx_L4:;
+  __Pyx_XDECREF(__pyx_r);
+  __Pyx_INCREF(((PyObject *)__pyx_v_fmap));
+  __pyx_r = ((PyObject *)__pyx_v_fmap);
+  goto __pyx_L0;
 
-    /* "_cdec.pyx":53
- *                     'csplit', 'tagger', 'lexalign'):
- *                 raise InvalidConfig('formalism "%s" unknown' % formalism)
- *             config_str = '\n'.join('%s = %s' % kv for kv in _make_config(config))             # <<<<<<<<<<<<<<
- *         cdef istringstream* config_stream = new istringstream(config_str)
- *         self.dec = new decoder.Decoder(config_stream)
- */
-    __pyx_t_2 = PyObject_GetAttr(((PyObject *)__pyx_kp_s_35), __pyx_n_s__join); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 53; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-    __Pyx_GOTREF(__pyx_t_2);
-    __pyx_t_6 = __pyx_pf_5_cdec_7Decoder_9__cinit___genexpr(((PyObject*)__pyx_cur_scope)); if (unlikely(!__pyx_t_6)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 53; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-    __Pyx_GOTREF(__pyx_t_6);
-    __pyx_t_3 = PyTuple_New(1); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 53; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-    __Pyx_GOTREF(__pyx_t_3);
-    PyTuple_SET_ITEM(__pyx_t_3, 0, __pyx_t_6);
-    __Pyx_GIVEREF(__pyx_t_6);
-    __pyx_t_6 = 0;
-    __pyx_t_6 = PyObject_Call(__pyx_t_2, ((PyObject *)__pyx_t_3), NULL); if (unlikely(!__pyx_t_6)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 53; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-    __Pyx_GOTREF(__pyx_t_6);
-    __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
-    __Pyx_DECREF(((PyObject *)__pyx_t_3)); __pyx_t_3 = 0;
-    __Pyx_DECREF(__pyx_v_config_str);
-    __pyx_v_config_str = __pyx_t_6;
-    __pyx_t_6 = 0;
-    goto __pyx_L3;
-  }
-  __pyx_L3:;
+  __pyx_r = Py_None; __Pyx_INCREF(Py_None);
+  goto __pyx_L0;
+  __pyx_L1_error:;
+  __Pyx_XDECREF(__pyx_t_1);
+  __Pyx_AddTraceback("_cdec.Candidate.fmap.__get__", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __pyx_r = NULL;
+  __pyx_L0:;
+  __Pyx_XDECREF((PyObject *)__pyx_v_fmap);
+  __Pyx_XGIVEREF(__pyx_r);
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
 
-  /* "_cdec.pyx":54
- *                 raise InvalidConfig('formalism "%s" unknown' % formalism)
- *             config_str = '\n'.join('%s = %s' % kv for kv in _make_config(config))
- *         cdef istringstream* config_stream = new istringstream(config_str)             # <<<<<<<<<<<<<<
- *         self.dec = new decoder.Decoder(config_stream)
- *         del config_stream
- */
-  __pyx_t_7 = PyBytes_AsString(__pyx_v_config_str); if (unlikely((!__pyx_t_7) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 54; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __pyx_v_config_stream = new std::istringstream(__pyx_t_7);
+/* Python wrapper */
+static PyObject *__pyx_pw_5_cdec_9Candidate_5score_1__get__(PyObject *__pyx_v_self); /*proto*/
+static PyObject *__pyx_pw_5_cdec_9Candidate_5score_1__get__(PyObject *__pyx_v_self) {
+  PyObject *__pyx_r = 0;
+  __Pyx_RefNannyDeclarations
+  __Pyx_RefNannySetupContext("__get__ (wrapper)", 0);
+  __pyx_r = __pyx_pf_5_cdec_9Candidate_5score___get__(((struct __pyx_obj_5_cdec_Candidate *)__pyx_v_self));
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
 
-  /* "_cdec.pyx":55
- *             config_str = '\n'.join('%s = %s' % kv for kv in _make_config(config))
- *         cdef istringstream* config_stream = new istringstream(config_str)
- *         self.dec = new decoder.Decoder(config_stream)             # <<<<<<<<<<<<<<
- *         del config_stream
- *         self.weights = DenseVector()
+/* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":14
+ * cdef class Candidate:
+ *     cdef mteval.Candidate* candidate
+ *     cdef public float score             # <<<<<<<<<<<<<<
+ * 
+ *     property words:
  */
-  __pyx_v_self->dec = new Decoder(__pyx_v_config_stream);
 
-  /* "_cdec.pyx":56
- *         cdef istringstream* config_stream = new istringstream(config_str)
- *         self.dec = new decoder.Decoder(config_stream)
- *         del config_stream             # <<<<<<<<<<<<<<
- *         self.weights = DenseVector()
- *         self.weights.vector = &self.dec.CurrentWeightVector()
- */
-  delete __pyx_v_config_stream;
+static PyObject *__pyx_pf_5_cdec_9Candidate_5score___get__(struct __pyx_obj_5_cdec_Candidate *__pyx_v_self) {
+  PyObject *__pyx_r = NULL;
+  __Pyx_RefNannyDeclarations
+  PyObject *__pyx_t_1 = NULL;
+  int __pyx_lineno = 0;
+  const char *__pyx_filename = NULL;
+  int __pyx_clineno = 0;
+  __Pyx_RefNannySetupContext("__get__", 0);
+  __Pyx_XDECREF(__pyx_r);
+  __pyx_t_1 = PyFloat_FromDouble(__pyx_v_self->score); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 14; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_1);
+  __pyx_r = __pyx_t_1;
+  __pyx_t_1 = 0;
+  goto __pyx_L0;
 
-  /* "_cdec.pyx":57
- *         self.dec = new decoder.Decoder(config_stream)
- *         del config_stream
- *         self.weights = DenseVector()             # <<<<<<<<<<<<<<
- *         self.weights.vector = &self.dec.CurrentWeightVector()
- * 
- */
-  __pyx_t_6 = PyObject_Call(((PyObject *)((PyObject*)__pyx_ptype_5_cdec_DenseVector)), ((PyObject *)__pyx_empty_tuple), NULL); if (unlikely(!__pyx_t_6)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 57; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __Pyx_GOTREF(__pyx_t_6);
-  __Pyx_GIVEREF(__pyx_t_6);
-  __Pyx_GOTREF(__pyx_v_self->weights);
-  __Pyx_DECREF(((PyObject *)__pyx_v_self->weights));
-  __pyx_v_self->weights = ((struct __pyx_obj_5_cdec_DenseVector *)__pyx_t_6);
-  __pyx_t_6 = 0;
+  __pyx_r = Py_None; __Pyx_INCREF(Py_None);
+  goto __pyx_L0;
+  __pyx_L1_error:;
+  __Pyx_XDECREF(__pyx_t_1);
+  __Pyx_AddTraceback("_cdec.Candidate.score.__get__", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __pyx_r = NULL;
+  __pyx_L0:;
+  __Pyx_XGIVEREF(__pyx_r);
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
 
-  /* "_cdec.pyx":58
- *         del config_stream
- *         self.weights = DenseVector()
- *         self.weights.vector = &self.dec.CurrentWeightVector()             # <<<<<<<<<<<<<<
- * 
- *     def __dealloc__(self):
- */
-  __pyx_v_self->weights->vector = (&__pyx_v_self->dec->CurrentWeightVector());
+/* Python wrapper */
+static int __pyx_pw_5_cdec_9Candidate_5score_3__set__(PyObject *__pyx_v_self, PyObject *__pyx_v_value); /*proto*/
+static int __pyx_pw_5_cdec_9Candidate_5score_3__set__(PyObject *__pyx_v_self, PyObject *__pyx_v_value) {
+  int __pyx_r;
+  __Pyx_RefNannyDeclarations
+  __Pyx_RefNannySetupContext("__set__ (wrapper)", 0);
+  __pyx_r = __pyx_pf_5_cdec_9Candidate_5score_2__set__(((struct __pyx_obj_5_cdec_Candidate *)__pyx_v_self), ((PyObject *)__pyx_v_value));
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+static int __pyx_pf_5_cdec_9Candidate_5score_2__set__(struct __pyx_obj_5_cdec_Candidate *__pyx_v_self, PyObject *__pyx_v_value) {
+  int __pyx_r;
+  __Pyx_RefNannyDeclarations
+  float __pyx_t_1;
+  int __pyx_lineno = 0;
+  const char *__pyx_filename = NULL;
+  int __pyx_clineno = 0;
+  __Pyx_RefNannySetupContext("__set__", 0);
+  __pyx_t_1 = __pyx_PyFloat_AsFloat(__pyx_v_value); if (unlikely((__pyx_t_1 == (float)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 14; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_v_self->score = __pyx_t_1;
 
   __pyx_r = 0;
   goto __pyx_L0;
   __pyx_L1_error:;
-  __Pyx_XDECREF(__pyx_t_2);
-  __Pyx_XDECREF(__pyx_t_3);
-  __Pyx_XDECREF(__pyx_t_6);
-  __Pyx_AddTraceback("_cdec.Decoder.__cinit__", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __Pyx_AddTraceback("_cdec.Candidate.score.__set__", __pyx_clineno, __pyx_lineno, __pyx_filename);
   __pyx_r = -1;
   __pyx_L0:;
-  __Pyx_XDECREF(__pyx_v_formalism);
-  __Pyx_XDECREF(__pyx_v_config_str);
-  __Pyx_DECREF(((PyObject *)__pyx_cur_scope));
   __Pyx_RefNannyFinishContext();
   return __pyx_r;
 }
 
 /* Python wrapper */
-static void __pyx_pw_5_cdec_7Decoder_3__dealloc__(PyObject *__pyx_v_self); /*proto*/
-static void __pyx_pw_5_cdec_7Decoder_3__dealloc__(PyObject *__pyx_v_self) {
+static void __pyx_pw_5_cdec_15SufficientStats_1__dealloc__(PyObject *__pyx_v_self); /*proto*/
+static void __pyx_pw_5_cdec_15SufficientStats_1__dealloc__(PyObject *__pyx_v_self) {
   __Pyx_RefNannyDeclarations
   __Pyx_RefNannySetupContext("__dealloc__ (wrapper)", 0);
-  __pyx_pf_5_cdec_7Decoder_2__dealloc__(((struct __pyx_obj_5_cdec_Decoder *)__pyx_v_self));
+  __pyx_pf_5_cdec_15SufficientStats___dealloc__(((struct __pyx_obj_5_cdec_SufficientStats *)__pyx_v_self));
   __Pyx_RefNannyFinishContext();
 }
 
-/* "_cdec.pyx":60
- *         self.weights.vector = &self.dec.CurrentWeightVector()
+/* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":30
+ *     cdef mteval.EvaluationMetric* metric
  * 
  *     def __dealloc__(self):             # <<<<<<<<<<<<<<
- *         del self.dec
+ *         del self.stats
  * 
  */
 
-static void __pyx_pf_5_cdec_7Decoder_2__dealloc__(CYTHON_UNUSED struct __pyx_obj_5_cdec_Decoder *__pyx_v_self) {
+static void __pyx_pf_5_cdec_15SufficientStats___dealloc__(CYTHON_UNUSED struct __pyx_obj_5_cdec_SufficientStats *__pyx_v_self) {
   __Pyx_RefNannyDeclarations
   __Pyx_RefNannySetupContext("__dealloc__", 0);
 
-  /* "_cdec.pyx":61
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":31
  * 
  *     def __dealloc__(self):
- *         del self.dec             # <<<<<<<<<<<<<<
+ *         del self.stats             # <<<<<<<<<<<<<<
  * 
- *     property weights:
+ *     property score:
  */
-  delete __pyx_v_self->dec;
+  delete __pyx_v_self->stats;
 
   __Pyx_RefNannyFinishContext();
 }
 
 /* Python wrapper */
-static PyObject *__pyx_pw_5_cdec_7Decoder_7weights_1__get__(PyObject *__pyx_v_self); /*proto*/
-static PyObject *__pyx_pw_5_cdec_7Decoder_7weights_1__get__(PyObject *__pyx_v_self) {
+static PyObject *__pyx_pw_5_cdec_15SufficientStats_5score_1__get__(PyObject *__pyx_v_self); /*proto*/
+static PyObject *__pyx_pw_5_cdec_15SufficientStats_5score_1__get__(PyObject *__pyx_v_self) {
   PyObject *__pyx_r = 0;
   __Pyx_RefNannyDeclarations
   __Pyx_RefNannySetupContext("__get__ (wrapper)", 0);
-  __pyx_r = __pyx_pf_5_cdec_7Decoder_7weights___get__(((struct __pyx_obj_5_cdec_Decoder *)__pyx_v_self));
+  __pyx_r = __pyx_pf_5_cdec_15SufficientStats_5score___get__(((struct __pyx_obj_5_cdec_SufficientStats *)__pyx_v_self));
   __Pyx_RefNannyFinishContext();
   return __pyx_r;
 }
 
-/* "_cdec.pyx":64
+/* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":34
  * 
- *     property weights:
+ *     property score:
  *         def __get__(self):             # <<<<<<<<<<<<<<
- *             return self.weights
+ *             return self.metric.ComputeScore(self.stats[0])
  * 
  */
 
-static PyObject *__pyx_pf_5_cdec_7Decoder_7weights___get__(struct __pyx_obj_5_cdec_Decoder *__pyx_v_self) {
+static PyObject *__pyx_pf_5_cdec_15SufficientStats_5score___get__(struct __pyx_obj_5_cdec_SufficientStats *__pyx_v_self) {
   PyObject *__pyx_r = NULL;
   __Pyx_RefNannyDeclarations
+  PyObject *__pyx_t_1 = NULL;
+  int __pyx_lineno = 0;
+  const char *__pyx_filename = NULL;
+  int __pyx_clineno = 0;
   __Pyx_RefNannySetupContext("__get__", 0);
 
-  /* "_cdec.pyx":65
- *     property weights:
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":35
+ *     property score:
  *         def __get__(self):
- *             return self.weights             # <<<<<<<<<<<<<<
+ *             return self.metric.ComputeScore(self.stats[0])             # <<<<<<<<<<<<<<
  * 
- *         def __set__(self, weights):
+ *     property detail:
  */
   __Pyx_XDECREF(__pyx_r);
-  __Pyx_INCREF(((PyObject *)__pyx_v_self->weights));
-  __pyx_r = ((PyObject *)__pyx_v_self->weights);
-  goto __pyx_L0;
+  __pyx_t_1 = PyFloat_FromDouble(__pyx_v_self->metric->ComputeScore((__pyx_v_self->stats[0]))); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 35; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_1);
+  __pyx_r = __pyx_t_1;
+  __pyx_t_1 = 0;
+  goto __pyx_L0;
 
   __pyx_r = Py_None; __Pyx_INCREF(Py_None);
+  goto __pyx_L0;
+  __pyx_L1_error:;
+  __Pyx_XDECREF(__pyx_t_1);
+  __Pyx_AddTraceback("_cdec.SufficientStats.score.__get__", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __pyx_r = NULL;
   __pyx_L0:;
   __Pyx_XGIVEREF(__pyx_r);
   __Pyx_RefNannyFinishContext();
@@ -13035,683 +12961,453 @@ static PyObject *__pyx_pf_5_cdec_7Decoder_7weights___get__(struct __pyx_obj_5_cd
 }
 
 /* Python wrapper */
-static int __pyx_pw_5_cdec_7Decoder_7weights_3__set__(PyObject *__pyx_v_self, PyObject *__pyx_v_weights); /*proto*/
-static int __pyx_pw_5_cdec_7Decoder_7weights_3__set__(PyObject *__pyx_v_self, PyObject *__pyx_v_weights) {
-  int __pyx_r;
+static PyObject *__pyx_pw_5_cdec_15SufficientStats_6detail_1__get__(PyObject *__pyx_v_self); /*proto*/
+static PyObject *__pyx_pw_5_cdec_15SufficientStats_6detail_1__get__(PyObject *__pyx_v_self) {
+  PyObject *__pyx_r = 0;
   __Pyx_RefNannyDeclarations
-  __Pyx_RefNannySetupContext("__set__ (wrapper)", 0);
-  __pyx_r = __pyx_pf_5_cdec_7Decoder_7weights_2__set__(((struct __pyx_obj_5_cdec_Decoder *)__pyx_v_self), ((PyObject *)__pyx_v_weights));
+  __Pyx_RefNannySetupContext("__get__ (wrapper)", 0);
+  __pyx_r = __pyx_pf_5_cdec_15SufficientStats_6detail___get__(((struct __pyx_obj_5_cdec_SufficientStats *)__pyx_v_self));
   __Pyx_RefNannyFinishContext();
   return __pyx_r;
 }
 
-/* "_cdec.pyx":67
- *             return self.weights
+/* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":38
+ * 
+ *     property detail:
+ *         def __get__(self):             # <<<<<<<<<<<<<<
+ *             return self.metric.DetailedScore(self.stats[0]).c_str()
  * 
- *         def __set__(self, weights):             # <<<<<<<<<<<<<<
- *             if isinstance(weights, DenseVector):
- *                 self.weights.vector[0] = (<DenseVector> weights).vector[0]
  */
 
-static int __pyx_pf_5_cdec_7Decoder_7weights_2__set__(struct __pyx_obj_5_cdec_Decoder *__pyx_v_self, PyObject *__pyx_v_weights) {
-  PyObject *__pyx_v_fname = NULL;
-  PyObject *__pyx_v_fval = NULL;
-  int __pyx_r;
+static PyObject *__pyx_pf_5_cdec_15SufficientStats_6detail___get__(struct __pyx_obj_5_cdec_SufficientStats *__pyx_v_self) {
+  PyObject *__pyx_r = NULL;
   __Pyx_RefNannyDeclarations
   PyObject *__pyx_t_1 = NULL;
-  int __pyx_t_2;
-  PyObject *__pyx_t_3 = NULL;
-  Py_ssize_t __pyx_t_4;
-  PyObject *(*__pyx_t_5)(PyObject *);
-  PyObject *__pyx_t_6 = NULL;
-  PyObject *__pyx_t_7 = NULL;
-  PyObject *__pyx_t_8 = NULL;
-  PyObject *(*__pyx_t_9)(PyObject *);
   int __pyx_lineno = 0;
   const char *__pyx_filename = NULL;
   int __pyx_clineno = 0;
-  __Pyx_RefNannySetupContext("__set__", 0);
-
-  /* "_cdec.pyx":68
- * 
- *         def __set__(self, weights):
- *             if isinstance(weights, DenseVector):             # <<<<<<<<<<<<<<
- *                 self.weights.vector[0] = (<DenseVector> weights).vector[0]
- *             elif isinstance(weights, SparseVector):
- */
-  __pyx_t_1 = ((PyObject *)((PyObject*)__pyx_ptype_5_cdec_DenseVector));
-  __Pyx_INCREF(__pyx_t_1);
-  __pyx_t_2 = __Pyx_TypeCheck(__pyx_v_weights, __pyx_t_1); 
-  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
-  if (__pyx_t_2) {
-
-    /* "_cdec.pyx":69
- *         def __set__(self, weights):
- *             if isinstance(weights, DenseVector):
- *                 self.weights.vector[0] = (<DenseVector> weights).vector[0]             # <<<<<<<<<<<<<<
- *             elif isinstance(weights, SparseVector):
- *                 self.weights.vector.clear()
- */
-    (__pyx_v_self->weights->vector[0]) = (((struct __pyx_obj_5_cdec_DenseVector *)__pyx_v_weights)->vector[0]);
-    goto __pyx_L3;
-  }
-
-  /* "_cdec.pyx":70
- *             if isinstance(weights, DenseVector):
- *                 self.weights.vector[0] = (<DenseVector> weights).vector[0]
- *             elif isinstance(weights, SparseVector):             # <<<<<<<<<<<<<<
- *                 self.weights.vector.clear()
- *                 ((<SparseVector> weights).vector[0]).init_vector(self.weights.vector)
- */
-  __pyx_t_1 = ((PyObject *)((PyObject*)__pyx_ptype_5_cdec_SparseVector));
-  __Pyx_INCREF(__pyx_t_1);
-  __pyx_t_2 = __Pyx_TypeCheck(__pyx_v_weights, __pyx_t_1); 
-  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
-  if (__pyx_t_2) {
-
-    /* "_cdec.pyx":71
- *                 self.weights.vector[0] = (<DenseVector> weights).vector[0]
- *             elif isinstance(weights, SparseVector):
- *                 self.weights.vector.clear()             # <<<<<<<<<<<<<<
- *                 ((<SparseVector> weights).vector[0]).init_vector(self.weights.vector)
- *             elif isinstance(weights, dict):
- */
-    __pyx_v_self->weights->vector->clear();
-
-    /* "_cdec.pyx":72
- *             elif isinstance(weights, SparseVector):
- *                 self.weights.vector.clear()
- *                 ((<SparseVector> weights).vector[0]).init_vector(self.weights.vector)             # <<<<<<<<<<<<<<
- *             elif isinstance(weights, dict):
- *                 for fname, fval in weights.items():
- */
-    (((struct __pyx_obj_5_cdec_SparseVector *)__pyx_v_weights)->vector[0]).init_vector(__pyx_v_self->weights->vector);
-    goto __pyx_L3;
-  }
-
-  /* "_cdec.pyx":73
- *                 self.weights.vector.clear()
- *                 ((<SparseVector> weights).vector[0]).init_vector(self.weights.vector)
- *             elif isinstance(weights, dict):             # <<<<<<<<<<<<<<
- *                 for fname, fval in weights.items():
- *                     self.weights[fname] = fval
- */
-  __pyx_t_1 = ((PyObject *)((PyObject*)(&PyDict_Type)));
-  __Pyx_INCREF(__pyx_t_1);
-  __pyx_t_2 = __Pyx_TypeCheck(__pyx_v_weights, __pyx_t_1); 
-  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
-  if (__pyx_t_2) {
-
-    /* "_cdec.pyx":74
- *                 ((<SparseVector> weights).vector[0]).init_vector(self.weights.vector)
- *             elif isinstance(weights, dict):
- *                 for fname, fval in weights.items():             # <<<<<<<<<<<<<<
- *                     self.weights[fname] = fval
- *             else:
- */
-    __pyx_t_1 = PyObject_GetAttr(__pyx_v_weights, __pyx_n_s__items); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 74; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-    __Pyx_GOTREF(__pyx_t_1);
-    __pyx_t_3 = PyObject_Call(__pyx_t_1, ((PyObject *)__pyx_empty_tuple), NULL); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 74; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-    __Pyx_GOTREF(__pyx_t_3);
-    __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
-    if (PyList_CheckExact(__pyx_t_3) || PyTuple_CheckExact(__pyx_t_3)) {
-      __pyx_t_1 = __pyx_t_3; __Pyx_INCREF(__pyx_t_1); __pyx_t_4 = 0;
-      __pyx_t_5 = NULL;
-    } else {
-      __pyx_t_4 = -1; __pyx_t_1 = PyObject_GetIter(__pyx_t_3); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 74; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-      __Pyx_GOTREF(__pyx_t_1);
-      __pyx_t_5 = Py_TYPE(__pyx_t_1)->tp_iternext;
-    }
-    __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
-    for (;;) {
-      if (!__pyx_t_5 && PyList_CheckExact(__pyx_t_1)) {
-        if (__pyx_t_4 >= PyList_GET_SIZE(__pyx_t_1)) break;
-        __pyx_t_3 = PyList_GET_ITEM(__pyx_t_1, __pyx_t_4); __Pyx_INCREF(__pyx_t_3); __pyx_t_4++;
-      } else if (!__pyx_t_5 && PyTuple_CheckExact(__pyx_t_1)) {
-        if (__pyx_t_4 >= PyTuple_GET_SIZE(__pyx_t_1)) break;
-        __pyx_t_3 = PyTuple_GET_ITEM(__pyx_t_1, __pyx_t_4); __Pyx_INCREF(__pyx_t_3); __pyx_t_4++;
-      } else {
-        __pyx_t_3 = __pyx_t_5(__pyx_t_1);
-        if (unlikely(!__pyx_t_3)) {
-          if (PyErr_Occurred()) {
-            if (likely(PyErr_ExceptionMatches(PyExc_StopIteration))) PyErr_Clear();
-            else {__pyx_filename = __pyx_f[0]; __pyx_lineno = 74; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-          }
-          break;
-        }
-        __Pyx_GOTREF(__pyx_t_3);
-      }
-      if ((likely(PyTuple_CheckExact(__pyx_t_3))) || (PyList_CheckExact(__pyx_t_3))) {
-        PyObject* sequence = __pyx_t_3;
-        if (likely(PyTuple_CheckExact(sequence))) {
-          if (unlikely(PyTuple_GET_SIZE(sequence) != 2)) {
-            if (PyTuple_GET_SIZE(sequence) > 2) __Pyx_RaiseTooManyValuesError(2);
-            else __Pyx_RaiseNeedMoreValuesError(PyTuple_GET_SIZE(sequence));
-            {__pyx_filename = __pyx_f[0]; __pyx_lineno = 74; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-          }
-          __pyx_t_6 = PyTuple_GET_ITEM(sequence, 0); 
-          __pyx_t_7 = PyTuple_GET_ITEM(sequence, 1); 
-        } else {
-          if (unlikely(PyList_GET_SIZE(sequence) != 2)) {
-            if (PyList_GET_SIZE(sequence) > 2) __Pyx_RaiseTooManyValuesError(2);
-            else __Pyx_RaiseNeedMoreValuesError(PyList_GET_SIZE(sequence));
-            {__pyx_filename = __pyx_f[0]; __pyx_lineno = 74; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-          }
-          __pyx_t_6 = PyList_GET_ITEM(sequence, 0); 
-          __pyx_t_7 = PyList_GET_ITEM(sequence, 1); 
-        }
-        __Pyx_INCREF(__pyx_t_6);
-        __Pyx_INCREF(__pyx_t_7);
-        __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
-      } else {
-        Py_ssize_t index = -1;
-        __pyx_t_8 = PyObject_GetIter(__pyx_t_3); if (unlikely(!__pyx_t_8)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 74; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-        __Pyx_GOTREF(__pyx_t_8);
-        __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
-        __pyx_t_9 = Py_TYPE(__pyx_t_8)->tp_iternext;
-        index = 0; __pyx_t_6 = __pyx_t_9(__pyx_t_8); if (unlikely(!__pyx_t_6)) goto __pyx_L6_unpacking_failed;
-        __Pyx_GOTREF(__pyx_t_6);
-        index = 1; __pyx_t_7 = __pyx_t_9(__pyx_t_8); if (unlikely(!__pyx_t_7)) goto __pyx_L6_unpacking_failed;
-        __Pyx_GOTREF(__pyx_t_7);
-        if (__Pyx_IternextUnpackEndCheck(__pyx_t_9(__pyx_t_8), 2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 74; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-        __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0;
-        goto __pyx_L7_unpacking_done;
-        __pyx_L6_unpacking_failed:;
-        __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0;
-        if (PyErr_Occurred() && PyErr_ExceptionMatches(PyExc_StopIteration)) PyErr_Clear();
-        if (!PyErr_Occurred()) __Pyx_RaiseNeedMoreValuesError(index);
-        {__pyx_filename = __pyx_f[0]; __pyx_lineno = 74; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-        __pyx_L7_unpacking_done:;
-      }
-      __Pyx_XDECREF(__pyx_v_fname);
-      __pyx_v_fname = __pyx_t_6;
-      __pyx_t_6 = 0;
-      __Pyx_XDECREF(__pyx_v_fval);
-      __pyx_v_fval = __pyx_t_7;
-      __pyx_t_7 = 0;
-
-      /* "_cdec.pyx":75
- *             elif isinstance(weights, dict):
- *                 for fname, fval in weights.items():
- *                     self.weights[fname] = fval             # <<<<<<<<<<<<<<
- *             else:
- *                 raise TypeError('cannot initialize weights with %s' % type(weights))
- */
-      if (PyObject_SetItem(((PyObject *)__pyx_v_self->weights), __pyx_v_fname, __pyx_v_fval) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 75; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-    }
-    __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
-    goto __pyx_L3;
-  }
-  /*else*/ {
+  __Pyx_RefNannySetupContext("__get__", 0);
 
-    /* "_cdec.pyx":77
- *                     self.weights[fname] = fval
- *             else:
- *                 raise TypeError('cannot initialize weights with %s' % type(weights))             # <<<<<<<<<<<<<<
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":39
+ *     property detail:
+ *         def __get__(self):
+ *             return self.metric.DetailedScore(self.stats[0]).c_str()             # <<<<<<<<<<<<<<
  * 
- *     property formalism:
+ *     def __len__(self):
  */
-    __pyx_t_1 = PyNumber_Remainder(((PyObject *)__pyx_kp_s_43), ((PyObject *)Py_TYPE(__pyx_v_weights))); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 77; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-    __Pyx_GOTREF(((PyObject *)__pyx_t_1));
-    __pyx_t_3 = PyTuple_New(1); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 77; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-    __Pyx_GOTREF(__pyx_t_3);
-    PyTuple_SET_ITEM(__pyx_t_3, 0, ((PyObject *)__pyx_t_1));
-    __Pyx_GIVEREF(((PyObject *)__pyx_t_1));
-    __pyx_t_1 = 0;
-    __pyx_t_1 = PyObject_Call(__pyx_builtin_TypeError, ((PyObject *)__pyx_t_3), NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 77; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-    __Pyx_GOTREF(__pyx_t_1);
-    __Pyx_DECREF(((PyObject *)__pyx_t_3)); __pyx_t_3 = 0;
-    __Pyx_Raise(__pyx_t_1, 0, 0, 0);
-    __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
-    {__pyx_filename = __pyx_f[0]; __pyx_lineno = 77; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  }
-  __pyx_L3:;
+  __Pyx_XDECREF(__pyx_r);
+  __pyx_t_1 = PyBytes_FromString(__pyx_v_self->metric->DetailedScore((__pyx_v_self->stats[0])).c_str()); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 39; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(((PyObject *)__pyx_t_1));
+  __pyx_r = ((PyObject *)__pyx_t_1);
+  __pyx_t_1 = 0;
+  goto __pyx_L0;
 
-  __pyx_r = 0;
+  __pyx_r = Py_None; __Pyx_INCREF(Py_None);
   goto __pyx_L0;
   __pyx_L1_error:;
   __Pyx_XDECREF(__pyx_t_1);
-  __Pyx_XDECREF(__pyx_t_3);
-  __Pyx_XDECREF(__pyx_t_6);
-  __Pyx_XDECREF(__pyx_t_7);
-  __Pyx_XDECREF(__pyx_t_8);
-  __Pyx_AddTraceback("_cdec.Decoder.weights.__set__", __pyx_clineno, __pyx_lineno, __pyx_filename);
-  __pyx_r = -1;
+  __Pyx_AddTraceback("_cdec.SufficientStats.detail.__get__", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __pyx_r = NULL;
   __pyx_L0:;
-  __Pyx_XDECREF(__pyx_v_fname);
-  __Pyx_XDECREF(__pyx_v_fval);
+  __Pyx_XGIVEREF(__pyx_r);
   __Pyx_RefNannyFinishContext();
   return __pyx_r;
 }
 
 /* Python wrapper */
-static PyObject *__pyx_pw_5_cdec_7Decoder_9formalism_1__get__(PyObject *__pyx_v_self); /*proto*/
-static PyObject *__pyx_pw_5_cdec_7Decoder_9formalism_1__get__(PyObject *__pyx_v_self) {
-  PyObject *__pyx_r = 0;
+static Py_ssize_t __pyx_pw_5_cdec_15SufficientStats_3__len__(PyObject *__pyx_v_self); /*proto*/
+static Py_ssize_t __pyx_pw_5_cdec_15SufficientStats_3__len__(PyObject *__pyx_v_self) {
+  Py_ssize_t __pyx_r;
   __Pyx_RefNannyDeclarations
-  __Pyx_RefNannySetupContext("__get__ (wrapper)", 0);
-  __pyx_r = __pyx_pf_5_cdec_7Decoder_9formalism___get__(((struct __pyx_obj_5_cdec_Decoder *)__pyx_v_self));
+  __Pyx_RefNannySetupContext("__len__ (wrapper)", 0);
+  __pyx_r = __pyx_pf_5_cdec_15SufficientStats_2__len__(((struct __pyx_obj_5_cdec_SufficientStats *)__pyx_v_self));
   __Pyx_RefNannyFinishContext();
   return __pyx_r;
 }
 
-/* "_cdec.pyx":80
+/* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":41
+ *             return self.metric.DetailedScore(self.stats[0]).c_str()
  * 
- *     property formalism:
- *         def __get__(self):             # <<<<<<<<<<<<<<
- *             cdef variables_map* conf = &self.dec.GetConf()
- *             return conf[0]['formalism'].as_str().c_str()
- */
+ *     def __len__(self):             # <<<<<<<<<<<<<<
+ *         return self.stats.size()
+ * 
+ */
 
-static PyObject *__pyx_pf_5_cdec_7Decoder_9formalism___get__(struct __pyx_obj_5_cdec_Decoder *__pyx_v_self) {
-  const boost::program_options::variables_map *__pyx_v_conf;
-  PyObject *__pyx_r = NULL;
+static Py_ssize_t __pyx_pf_5_cdec_15SufficientStats_2__len__(struct __pyx_obj_5_cdec_SufficientStats *__pyx_v_self) {
+  Py_ssize_t __pyx_r;
   __Pyx_RefNannyDeclarations
-  PyObject *__pyx_t_1 = NULL;
-  int __pyx_lineno = 0;
-  const char *__pyx_filename = NULL;
-  int __pyx_clineno = 0;
-  __Pyx_RefNannySetupContext("__get__", 0);
+  __Pyx_RefNannySetupContext("__len__", 0);
 
-  /* "_cdec.pyx":81
- *     property formalism:
- *         def __get__(self):
- *             cdef variables_map* conf = &self.dec.GetConf()             # <<<<<<<<<<<<<<
- *             return conf[0]['formalism'].as_str().c_str()
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":42
  * 
- */
-  __pyx_v_conf = (&__pyx_v_self->dec->GetConf());
-
-  /* "_cdec.pyx":82
- *         def __get__(self):
- *             cdef variables_map* conf = &self.dec.GetConf()
- *             return conf[0]['formalism'].as_str().c_str()             # <<<<<<<<<<<<<<
+ *     def __len__(self):
+ *         return self.stats.size()             # <<<<<<<<<<<<<<
  * 
- *     def read_weights(self, weights):
+ *     def __iter__(self):
  */
-  __Pyx_XDECREF(__pyx_r);
-  __pyx_t_1 = PyBytes_FromString(((__pyx_v_conf[0])[__pyx_k__formalism]).as<std::string>().c_str()); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 82; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __Pyx_GOTREF(((PyObject *)__pyx_t_1));
-  __pyx_r = ((PyObject *)__pyx_t_1);
-  __pyx_t_1 = 0;
+  __pyx_r = __pyx_v_self->stats->size();
   goto __pyx_L0;
 
-  __pyx_r = Py_None; __Pyx_INCREF(Py_None);
-  goto __pyx_L0;
-  __pyx_L1_error:;
-  __Pyx_XDECREF(__pyx_t_1);
-  __Pyx_AddTraceback("_cdec.Decoder.formalism.__get__", __pyx_clineno, __pyx_lineno, __pyx_filename);
-  __pyx_r = NULL;
+  __pyx_r = 0;
   __pyx_L0:;
-  __Pyx_XGIVEREF(__pyx_r);
   __Pyx_RefNannyFinishContext();
   return __pyx_r;
 }
+static PyObject *__pyx_gb_5_cdec_15SufficientStats_6generator14(__pyx_GeneratorObject *__pyx_generator, PyObject *__pyx_sent_value); /* proto */
 
 /* Python wrapper */
-static PyObject *__pyx_pw_5_cdec_7Decoder_5read_weights(PyObject *__pyx_v_self, PyObject *__pyx_v_weights); /*proto*/
-static PyObject *__pyx_pw_5_cdec_7Decoder_5read_weights(PyObject *__pyx_v_self, PyObject *__pyx_v_weights) {
+static PyObject *__pyx_pw_5_cdec_15SufficientStats_5__iter__(PyObject *__pyx_v_self); /*proto*/
+static PyObject *__pyx_pw_5_cdec_15SufficientStats_5__iter__(PyObject *__pyx_v_self) {
   PyObject *__pyx_r = 0;
   __Pyx_RefNannyDeclarations
-  __Pyx_RefNannySetupContext("read_weights (wrapper)", 0);
-  __pyx_r = __pyx_pf_5_cdec_7Decoder_4read_weights(((struct __pyx_obj_5_cdec_Decoder *)__pyx_v_self), ((PyObject *)__pyx_v_weights));
+  __Pyx_RefNannySetupContext("__iter__ (wrapper)", 0);
+  __pyx_r = __pyx_pf_5_cdec_15SufficientStats_4__iter__(((struct __pyx_obj_5_cdec_SufficientStats *)__pyx_v_self));
   __Pyx_RefNannyFinishContext();
   return __pyx_r;
 }
 
-/* "_cdec.pyx":84
- *             return conf[0]['formalism'].as_str().c_str()
+/* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":44
+ *         return self.stats.size()
  * 
- *     def read_weights(self, weights):             # <<<<<<<<<<<<<<
- *         with open(weights) as fp:
- *             for line in fp:
+ *     def __iter__(self):             # <<<<<<<<<<<<<<
+ *         for i in range(len(self)):
+ *             yield self.stats[0][i]
  */
 
-static PyObject *__pyx_pf_5_cdec_7Decoder_4read_weights(struct __pyx_obj_5_cdec_Decoder *__pyx_v_self, PyObject *__pyx_v_weights) {
-  PyObject *__pyx_v_fp = NULL;
-  PyObject *__pyx_v_line = NULL;
-  PyObject *__pyx_v_fname = NULL;
-  PyObject *__pyx_v_value = NULL;
+static PyObject *__pyx_pf_5_cdec_15SufficientStats_4__iter__(struct __pyx_obj_5_cdec_SufficientStats *__pyx_v_self) {
+  struct __pyx_obj_5_cdec___pyx_scope_struct_20___iter__ *__pyx_cur_scope;
   PyObject *__pyx_r = NULL;
   __Pyx_RefNannyDeclarations
-  PyObject *__pyx_t_1 = NULL;
-  PyObject *__pyx_t_2 = NULL;
-  PyObject *__pyx_t_3 = NULL;
-  PyObject *__pyx_t_4 = NULL;
-  PyObject *__pyx_t_5 = NULL;
-  PyObject *__pyx_t_6 = NULL;
-  PyObject *__pyx_t_7 = NULL;
-  Py_ssize_t __pyx_t_8;
-  PyObject *(*__pyx_t_9)(PyObject *);
-  int __pyx_t_10;
-  PyObject *__pyx_t_11 = NULL;
-  PyObject *__pyx_t_12 = NULL;
-  PyObject *(*__pyx_t_13)(PyObject *);
-  double __pyx_t_14;
-  PyObject *__pyx_t_15 = NULL;
-  int __pyx_t_16;
   int __pyx_lineno = 0;
   const char *__pyx_filename = NULL;
   int __pyx_clineno = 0;
-  __Pyx_RefNannySetupContext("read_weights", 0);
+  __Pyx_RefNannySetupContext("__iter__", 0);
+  __pyx_cur_scope = (struct __pyx_obj_5_cdec___pyx_scope_struct_20___iter__ *)__pyx_ptype_5_cdec___pyx_scope_struct_20___iter__->tp_new(__pyx_ptype_5_cdec___pyx_scope_struct_20___iter__, __pyx_empty_tuple, NULL);
+  if (unlikely(!__pyx_cur_scope)) {
+    __Pyx_RefNannyFinishContext();
+    return NULL;
+  }
+  __Pyx_GOTREF(__pyx_cur_scope);
+  __pyx_cur_scope->__pyx_v_self = __pyx_v_self;
+  __Pyx_INCREF((PyObject *)__pyx_cur_scope->__pyx_v_self);
+  __Pyx_GIVEREF((PyObject *)__pyx_cur_scope->__pyx_v_self);
+  {
+    __pyx_GeneratorObject *gen = __Pyx_Generator_New((__pyx_generator_body_t) __pyx_gb_5_cdec_15SufficientStats_6generator14, (PyObject *) __pyx_cur_scope); if (unlikely(!gen)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 44; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_DECREF(__pyx_cur_scope);
+    __Pyx_RefNannyFinishContext();
+    return (PyObject *) gen;
+  }
+
+  __pyx_r = Py_None; __Pyx_INCREF(Py_None);
+  goto __pyx_L0;
+  __pyx_L1_error:;
+  __Pyx_AddTraceback("_cdec.SufficientStats.__iter__", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __pyx_r = NULL;
+  __pyx_L0:;
+  __Pyx_DECREF(((PyObject *)__pyx_cur_scope));
+  __Pyx_XGIVEREF(__pyx_r);
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+static PyObject *__pyx_gb_5_cdec_15SufficientStats_6generator14(__pyx_GeneratorObject *__pyx_generator, PyObject *__pyx_sent_value) /* generator body */
+{
+  struct __pyx_obj_5_cdec___pyx_scope_struct_20___iter__ *__pyx_cur_scope = ((struct __pyx_obj_5_cdec___pyx_scope_struct_20___iter__ *)__pyx_generator->closure);
+  PyObject *__pyx_r = NULL;
+  Py_ssize_t __pyx_t_1;
+  PyObject *__pyx_t_2 = NULL;
+  PyObject *__pyx_t_3 = NULL;
+  PyObject *(*__pyx_t_4)(PyObject *);
+  unsigned int __pyx_t_5;
+  __Pyx_RefNannyDeclarations
+  __Pyx_RefNannySetupContext("None", 0);
+  switch (__pyx_generator->resume_label) {
+    case 0: goto __pyx_L3_first_run;
+    case 1: goto __pyx_L6_resume_from_yield;
+    default: /* CPython raises the right error here */
+    __Pyx_RefNannyFinishContext();
+    return NULL;
+  }
+  __pyx_L3_first_run:;
+  if (unlikely(!__pyx_sent_value)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 44; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
 
-  /* "_cdec.pyx":85
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":45
+ * 
+ *     def __iter__(self):
+ *         for i in range(len(self)):             # <<<<<<<<<<<<<<
+ *             yield self.stats[0][i]
  * 
- *     def read_weights(self, weights):
- *         with open(weights) as fp:             # <<<<<<<<<<<<<<
- *             for line in fp:
- *                 if line.strip().startswith('#'): continue
  */
-  /*with:*/ {
-    __pyx_t_1 = PyTuple_New(1); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 85; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-    __Pyx_GOTREF(__pyx_t_1);
-    __Pyx_INCREF(__pyx_v_weights);
-    PyTuple_SET_ITEM(__pyx_t_1, 0, __pyx_v_weights);
-    __Pyx_GIVEREF(__pyx_v_weights);
-    __pyx_t_2 = PyObject_Call(__pyx_builtin_open, ((PyObject *)__pyx_t_1), NULL); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 85; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-    __Pyx_GOTREF(__pyx_t_2);
-    __Pyx_DECREF(((PyObject *)__pyx_t_1)); __pyx_t_1 = 0;
-    __pyx_t_3 = PyObject_GetAttr(__pyx_t_2, __pyx_n_s____exit__); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 85; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_1 = PyObject_Length(((PyObject *)__pyx_cur_scope->__pyx_v_self)); if (unlikely(__pyx_t_1 == -1)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 45; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_2 = PyInt_FromSsize_t(__pyx_t_1); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 45; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_2);
+  __pyx_t_3 = PyTuple_New(1); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 45; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_3);
+  PyTuple_SET_ITEM(__pyx_t_3, 0, __pyx_t_2);
+  __Pyx_GIVEREF(__pyx_t_2);
+  __pyx_t_2 = 0;
+  __pyx_t_2 = PyObject_Call(__pyx_builtin_range, ((PyObject *)__pyx_t_3), NULL); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 45; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_2);
+  __Pyx_DECREF(((PyObject *)__pyx_t_3)); __pyx_t_3 = 0;
+  if (PyList_CheckExact(__pyx_t_2) || PyTuple_CheckExact(__pyx_t_2)) {
+    __pyx_t_3 = __pyx_t_2; __Pyx_INCREF(__pyx_t_3); __pyx_t_1 = 0;
+    __pyx_t_4 = NULL;
+  } else {
+    __pyx_t_1 = -1; __pyx_t_3 = PyObject_GetIter(__pyx_t_2); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 45; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
     __Pyx_GOTREF(__pyx_t_3);
-    __pyx_t_1 = PyObject_GetAttr(__pyx_t_2, __pyx_n_s____enter__); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 85; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
-    __Pyx_GOTREF(__pyx_t_1);
-    __pyx_t_4 = PyObject_Call(__pyx_t_1, ((PyObject *)__pyx_empty_tuple), NULL); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 85; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
-    __Pyx_GOTREF(__pyx_t_4);
-    __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
-    __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
-    /*try:*/ {
-      {
-        __Pyx_ExceptionSave(&__pyx_t_5, &__pyx_t_6, &__pyx_t_7);
-        __Pyx_XGOTREF(__pyx_t_5);
-        __Pyx_XGOTREF(__pyx_t_6);
-        __Pyx_XGOTREF(__pyx_t_7);
-        /*try:*/ {
-          __Pyx_INCREF(__pyx_t_4);
-          __pyx_v_fp = __pyx_t_4;
-          __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
-
-          /* "_cdec.pyx":86
- *     def read_weights(self, weights):
- *         with open(weights) as fp:
- *             for line in fp:             # <<<<<<<<<<<<<<
- *                 if line.strip().startswith('#'): continue
- *                 fname, value = line.split()
- */
-          if (PyList_CheckExact(__pyx_v_fp) || PyTuple_CheckExact(__pyx_v_fp)) {
-            __pyx_t_4 = __pyx_v_fp; __Pyx_INCREF(__pyx_t_4); __pyx_t_8 = 0;
-            __pyx_t_9 = NULL;
-          } else {
-            __pyx_t_8 = -1; __pyx_t_4 = PyObject_GetIter(__pyx_v_fp); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 86; __pyx_clineno = __LINE__; goto __pyx_L7_error;}
-            __Pyx_GOTREF(__pyx_t_4);
-            __pyx_t_9 = Py_TYPE(__pyx_t_4)->tp_iternext;
-          }
-          for (;;) {
-            if (!__pyx_t_9 && PyList_CheckExact(__pyx_t_4)) {
-              if (__pyx_t_8 >= PyList_GET_SIZE(__pyx_t_4)) break;
-              __pyx_t_2 = PyList_GET_ITEM(__pyx_t_4, __pyx_t_8); __Pyx_INCREF(__pyx_t_2); __pyx_t_8++;
-            } else if (!__pyx_t_9 && PyTuple_CheckExact(__pyx_t_4)) {
-              if (__pyx_t_8 >= PyTuple_GET_SIZE(__pyx_t_4)) break;
-              __pyx_t_2 = PyTuple_GET_ITEM(__pyx_t_4, __pyx_t_8); __Pyx_INCREF(__pyx_t_2); __pyx_t_8++;
-            } else {
-              __pyx_t_2 = __pyx_t_9(__pyx_t_4);
-              if (unlikely(!__pyx_t_2)) {
-                if (PyErr_Occurred()) {
-                  if (likely(PyErr_ExceptionMatches(PyExc_StopIteration))) PyErr_Clear();
-                  else {__pyx_filename = __pyx_f[0]; __pyx_lineno = 86; __pyx_clineno = __LINE__; goto __pyx_L7_error;}
-                }
-                break;
-              }
-              __Pyx_GOTREF(__pyx_t_2);
-            }
-            __Pyx_XDECREF(__pyx_v_line);
-            __pyx_v_line = __pyx_t_2;
-            __pyx_t_2 = 0;
+    __pyx_t_4 = Py_TYPE(__pyx_t_3)->tp_iternext;
+  }
+  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+  for (;;) {
+    if (!__pyx_t_4 && PyList_CheckExact(__pyx_t_3)) {
+      if (__pyx_t_1 >= PyList_GET_SIZE(__pyx_t_3)) break;
+      __pyx_t_2 = PyList_GET_ITEM(__pyx_t_3, __pyx_t_1); __Pyx_INCREF(__pyx_t_2); __pyx_t_1++;
+    } else if (!__pyx_t_4 && PyTuple_CheckExact(__pyx_t_3)) {
+      if (__pyx_t_1 >= PyTuple_GET_SIZE(__pyx_t_3)) break;
+      __pyx_t_2 = PyTuple_GET_ITEM(__pyx_t_3, __pyx_t_1); __Pyx_INCREF(__pyx_t_2); __pyx_t_1++;
+    } else {
+      __pyx_t_2 = __pyx_t_4(__pyx_t_3);
+      if (unlikely(!__pyx_t_2)) {
+        if (PyErr_Occurred()) {
+          if (likely(PyErr_ExceptionMatches(PyExc_StopIteration))) PyErr_Clear();
+          else {__pyx_filename = __pyx_f[5]; __pyx_lineno = 45; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+        }
+        break;
+      }
+      __Pyx_GOTREF(__pyx_t_2);
+    }
+    __Pyx_XGOTREF(__pyx_cur_scope->__pyx_v_i);
+    __Pyx_XDECREF(__pyx_cur_scope->__pyx_v_i);
+    __Pyx_GIVEREF(__pyx_t_2);
+    __pyx_cur_scope->__pyx_v_i = __pyx_t_2;
+    __pyx_t_2 = 0;
 
-            /* "_cdec.pyx":87
- *         with open(weights) as fp:
- *             for line in fp:
- *                 if line.strip().startswith('#'): continue             # <<<<<<<<<<<<<<
- *                 fname, value = line.split()
- *                 self.weights[fname.strip()] = float(value)
+    /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":46
+ *     def __iter__(self):
+ *         for i in range(len(self)):
+ *             yield self.stats[0][i]             # <<<<<<<<<<<<<<
+ * 
+ *     def __iadd__(SufficientStats self, SufficientStats other):
  */
-            __pyx_t_2 = PyObject_GetAttr(__pyx_v_line, __pyx_n_s__strip); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 87; __pyx_clineno = __LINE__; goto __pyx_L7_error;}
-            __Pyx_GOTREF(__pyx_t_2);
-            __pyx_t_1 = PyObject_Call(__pyx_t_2, ((PyObject *)__pyx_empty_tuple), NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 87; __pyx_clineno = __LINE__; goto __pyx_L7_error;}
-            __Pyx_GOTREF(__pyx_t_1);
-            __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
-            __pyx_t_2 = PyObject_GetAttr(__pyx_t_1, __pyx_n_s__startswith); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 87; __pyx_clineno = __LINE__; goto __pyx_L7_error;}
-            __Pyx_GOTREF(__pyx_t_2);
-            __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
-            __pyx_t_1 = PyObject_Call(__pyx_t_2, ((PyObject *)__pyx_k_tuple_45), NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 87; __pyx_clineno = __LINE__; goto __pyx_L7_error;}
-            __Pyx_GOTREF(__pyx_t_1);
-            __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
-            __pyx_t_10 = __Pyx_PyObject_IsTrue(__pyx_t_1); if (unlikely(__pyx_t_10 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 87; __pyx_clineno = __LINE__; goto __pyx_L7_error;}
-            __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
-            if (__pyx_t_10) {
-              goto __pyx_L16_continue;
-              goto __pyx_L18;
-            }
-            __pyx_L18:;
+    __pyx_t_5 = __Pyx_PyInt_AsUnsignedInt(__pyx_cur_scope->__pyx_v_i); if (unlikely((__pyx_t_5 == (unsigned int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 46; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_t_2 = PyFloat_FromDouble(((__pyx_cur_scope->__pyx_v_self->stats[0])[__pyx_t_5])); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 46; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_2);
+    __pyx_r = __pyx_t_2;
+    __pyx_t_2 = 0;
+    __pyx_cur_scope->__pyx_t_0 = __pyx_t_1;
+    __Pyx_XGIVEREF(__pyx_t_3);
+    __pyx_cur_scope->__pyx_t_1 = __pyx_t_3;
+    __pyx_cur_scope->__pyx_t_2 = __pyx_t_4;
+    __Pyx_XGIVEREF(__pyx_r);
+    __Pyx_RefNannyFinishContext();
+    /* return from generator, yielding value */
+    __pyx_generator->resume_label = 1;
+    return __pyx_r;
+    __pyx_L6_resume_from_yield:;
+    __pyx_t_1 = __pyx_cur_scope->__pyx_t_0;
+    __pyx_t_3 = __pyx_cur_scope->__pyx_t_1;
+    __pyx_cur_scope->__pyx_t_1 = 0;
+    __Pyx_XGOTREF(__pyx_t_3);
+    __pyx_t_4 = __pyx_cur_scope->__pyx_t_2;
+    if (unlikely(!__pyx_sent_value)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 46; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  }
+  __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
+  PyErr_SetNone(PyExc_StopIteration);
+  goto __pyx_L0;
+  __pyx_L1_error:;
+  __Pyx_XDECREF(__pyx_t_2);
+  __Pyx_XDECREF(__pyx_t_3);
+  __Pyx_AddTraceback("__iter__", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __pyx_L0:;
+  __Pyx_XDECREF(__pyx_r);
+  __pyx_generator->resume_label = -1;
+  __Pyx_RefNannyFinishContext();
+  return NULL;
+}
 
-            /* "_cdec.pyx":88
- *             for line in fp:
- *                 if line.strip().startswith('#'): continue
- *                 fname, value = line.split()             # <<<<<<<<<<<<<<
- *                 self.weights[fname.strip()] = float(value)
+/* Python wrapper */
+static PyObject *__pyx_pw_5_cdec_15SufficientStats_8__iadd__(PyObject *__pyx_v_self, PyObject *__pyx_v_other); /*proto*/
+static PyObject *__pyx_pw_5_cdec_15SufficientStats_8__iadd__(PyObject *__pyx_v_self, PyObject *__pyx_v_other) {
+  PyObject *__pyx_r = 0;
+  __Pyx_RefNannyDeclarations
+  __Pyx_RefNannySetupContext("__iadd__ (wrapper)", 0);
+  if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_other), __pyx_ptype_5_cdec_SufficientStats, 1, "other", 0))) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 48; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_r = __pyx_pf_5_cdec_15SufficientStats_7__iadd__(((struct __pyx_obj_5_cdec_SufficientStats *)__pyx_v_self), ((struct __pyx_obj_5_cdec_SufficientStats *)__pyx_v_other));
+  goto __pyx_L0;
+  __pyx_L1_error:;
+  __pyx_r = NULL;
+  __pyx_L0:;
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+/* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":48
+ *             yield self.stats[0][i]
  * 
+ *     def __iadd__(SufficientStats self, SufficientStats other):             # <<<<<<<<<<<<<<
+ *         self.stats[0] += other.stats[0]
+ *         return self
  */
-            __pyx_t_1 = PyObject_GetAttr(__pyx_v_line, __pyx_n_s__split); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 88; __pyx_clineno = __LINE__; goto __pyx_L7_error;}
-            __Pyx_GOTREF(__pyx_t_1);
-            __pyx_t_2 = PyObject_Call(__pyx_t_1, ((PyObject *)__pyx_empty_tuple), NULL); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 88; __pyx_clineno = __LINE__; goto __pyx_L7_error;}
-            __Pyx_GOTREF(__pyx_t_2);
-            __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
-            if ((likely(PyTuple_CheckExact(__pyx_t_2))) || (PyList_CheckExact(__pyx_t_2))) {
-              PyObject* sequence = __pyx_t_2;
-              if (likely(PyTuple_CheckExact(sequence))) {
-                if (unlikely(PyTuple_GET_SIZE(sequence) != 2)) {
-                  if (PyTuple_GET_SIZE(sequence) > 2) __Pyx_RaiseTooManyValuesError(2);
-                  else __Pyx_RaiseNeedMoreValuesError(PyTuple_GET_SIZE(sequence));
-                  {__pyx_filename = __pyx_f[0]; __pyx_lineno = 88; __pyx_clineno = __LINE__; goto __pyx_L7_error;}
-                }
-                __pyx_t_1 = PyTuple_GET_ITEM(sequence, 0); 
-                __pyx_t_11 = PyTuple_GET_ITEM(sequence, 1); 
-              } else {
-                if (unlikely(PyList_GET_SIZE(sequence) != 2)) {
-                  if (PyList_GET_SIZE(sequence) > 2) __Pyx_RaiseTooManyValuesError(2);
-                  else __Pyx_RaiseNeedMoreValuesError(PyList_GET_SIZE(sequence));
-                  {__pyx_filename = __pyx_f[0]; __pyx_lineno = 88; __pyx_clineno = __LINE__; goto __pyx_L7_error;}
-                }
-                __pyx_t_1 = PyList_GET_ITEM(sequence, 0); 
-                __pyx_t_11 = PyList_GET_ITEM(sequence, 1); 
-              }
-              __Pyx_INCREF(__pyx_t_1);
-              __Pyx_INCREF(__pyx_t_11);
-              __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
-            } else {
-              Py_ssize_t index = -1;
-              __pyx_t_12 = PyObject_GetIter(__pyx_t_2); if (unlikely(!__pyx_t_12)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 88; __pyx_clineno = __LINE__; goto __pyx_L7_error;}
-              __Pyx_GOTREF(__pyx_t_12);
-              __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
-              __pyx_t_13 = Py_TYPE(__pyx_t_12)->tp_iternext;
-              index = 0; __pyx_t_1 = __pyx_t_13(__pyx_t_12); if (unlikely(!__pyx_t_1)) goto __pyx_L19_unpacking_failed;
-              __Pyx_GOTREF(__pyx_t_1);
-              index = 1; __pyx_t_11 = __pyx_t_13(__pyx_t_12); if (unlikely(!__pyx_t_11)) goto __pyx_L19_unpacking_failed;
-              __Pyx_GOTREF(__pyx_t_11);
-              if (__Pyx_IternextUnpackEndCheck(__pyx_t_13(__pyx_t_12), 2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 88; __pyx_clineno = __LINE__; goto __pyx_L7_error;}
-              __Pyx_DECREF(__pyx_t_12); __pyx_t_12 = 0;
-              goto __pyx_L20_unpacking_done;
-              __pyx_L19_unpacking_failed:;
-              __Pyx_DECREF(__pyx_t_12); __pyx_t_12 = 0;
-              if (PyErr_Occurred() && PyErr_ExceptionMatches(PyExc_StopIteration)) PyErr_Clear();
-              if (!PyErr_Occurred()) __Pyx_RaiseNeedMoreValuesError(index);
-              {__pyx_filename = __pyx_f[0]; __pyx_lineno = 88; __pyx_clineno = __LINE__; goto __pyx_L7_error;}
-              __pyx_L20_unpacking_done:;
-            }
-            __Pyx_XDECREF(__pyx_v_fname);
-            __pyx_v_fname = __pyx_t_1;
-            __pyx_t_1 = 0;
-            __Pyx_XDECREF(__pyx_v_value);
-            __pyx_v_value = __pyx_t_11;
-            __pyx_t_11 = 0;
 
-            /* "_cdec.pyx":89
- *                 if line.strip().startswith('#'): continue
- *                 fname, value = line.split()
- *                 self.weights[fname.strip()] = float(value)             # <<<<<<<<<<<<<<
+static PyObject *__pyx_pf_5_cdec_15SufficientStats_7__iadd__(struct __pyx_obj_5_cdec_SufficientStats *__pyx_v_self, struct __pyx_obj_5_cdec_SufficientStats *__pyx_v_other) {
+  PyObject *__pyx_r = NULL;
+  __Pyx_RefNannyDeclarations
+  __Pyx_RefNannySetupContext("__iadd__", 0);
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":49
+ * 
+ *     def __iadd__(SufficientStats self, SufficientStats other):
+ *         self.stats[0] += other.stats[0]             # <<<<<<<<<<<<<<
+ *         return self
  * 
- *     def translate(self, sentence, grammar=None):
  */
-            __pyx_t_14 = __Pyx_PyObject_AsDouble(__pyx_v_value); if (unlikely(__pyx_t_14 == ((double)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 89; __pyx_clineno = __LINE__; goto __pyx_L7_error;}
-            __pyx_t_2 = PyFloat_FromDouble(__pyx_t_14); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 89; __pyx_clineno = __LINE__; goto __pyx_L7_error;}
-            __Pyx_GOTREF(__pyx_t_2);
-            __pyx_t_11 = PyObject_GetAttr(__pyx_v_fname, __pyx_n_s__strip); if (unlikely(!__pyx_t_11)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 89; __pyx_clineno = __LINE__; goto __pyx_L7_error;}
-            __Pyx_GOTREF(__pyx_t_11);
-            __pyx_t_1 = PyObject_Call(__pyx_t_11, ((PyObject *)__pyx_empty_tuple), NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 89; __pyx_clineno = __LINE__; goto __pyx_L7_error;}
-            __Pyx_GOTREF(__pyx_t_1);
-            __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0;
-            if (PyObject_SetItem(((PyObject *)__pyx_v_self->weights), __pyx_t_1, __pyx_t_2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 89; __pyx_clineno = __LINE__; goto __pyx_L7_error;}
-            __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
-            __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
-            __pyx_L16_continue:;
-          }
-          __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
-        }
-        __Pyx_XDECREF(__pyx_t_5); __pyx_t_5 = 0;
-        __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0;
-        __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0;
-        goto __pyx_L14_try_end;
-        __pyx_L7_error:;
-        __Pyx_XDECREF(__pyx_t_12); __pyx_t_12 = 0;
-        __Pyx_XDECREF(__pyx_t_11); __pyx_t_11 = 0;
-        __Pyx_XDECREF(__pyx_t_1); __pyx_t_1 = 0;
-        __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0;
-        __Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0;
+  (__pyx_v_self->stats[0]) += (__pyx_v_other->stats[0]);
 
-        /* "_cdec.pyx":85
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":50
+ *     def __iadd__(SufficientStats self, SufficientStats other):
+ *         self.stats[0] += other.stats[0]
+ *         return self             # <<<<<<<<<<<<<<
  * 
- *     def read_weights(self, weights):
- *         with open(weights) as fp:             # <<<<<<<<<<<<<<
- *             for line in fp:
- *                 if line.strip().startswith('#'): continue
+ *     def __add__(x, y):
  */
-        /*except:*/ {
-          __Pyx_AddTraceback("_cdec.Decoder.read_weights", __pyx_clineno, __pyx_lineno, __pyx_filename);
-          if (__Pyx_GetException(&__pyx_t_4, &__pyx_t_2, &__pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 85; __pyx_clineno = __LINE__; goto __pyx_L9_except_error;}
-          __Pyx_GOTREF(__pyx_t_4);
-          __Pyx_GOTREF(__pyx_t_2);
-          __Pyx_GOTREF(__pyx_t_1);
-          __pyx_t_11 = PyTuple_New(3); if (unlikely(!__pyx_t_11)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 85; __pyx_clineno = __LINE__; goto __pyx_L9_except_error;}
-          __Pyx_GOTREF(__pyx_t_11);
-          __Pyx_INCREF(__pyx_t_4);
-          PyTuple_SET_ITEM(__pyx_t_11, 0, __pyx_t_4);
-          __Pyx_GIVEREF(__pyx_t_4);
-          __Pyx_INCREF(__pyx_t_2);
-          PyTuple_SET_ITEM(__pyx_t_11, 1, __pyx_t_2);
-          __Pyx_GIVEREF(__pyx_t_2);
-          __Pyx_INCREF(__pyx_t_1);
-          PyTuple_SET_ITEM(__pyx_t_11, 2, __pyx_t_1);
-          __Pyx_GIVEREF(__pyx_t_1);
-          __pyx_t_15 = PyObject_Call(__pyx_t_3, __pyx_t_11, NULL);
-          __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
-          if (unlikely(!__pyx_t_15)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 85; __pyx_clineno = __LINE__; goto __pyx_L9_except_error;}
-          __Pyx_GOTREF(__pyx_t_15);
-          __pyx_t_10 = __Pyx_PyObject_IsTrue(__pyx_t_15);
-          __Pyx_DECREF(__pyx_t_15); __pyx_t_15 = 0;
-          if (unlikely(__pyx_t_10 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 85; __pyx_clineno = __LINE__; goto __pyx_L9_except_error;}
-          __pyx_t_16 = (!__pyx_t_10);
-          if (__pyx_t_16) {
-            __Pyx_GIVEREF(__pyx_t_4);
-            __Pyx_GIVEREF(__pyx_t_2);
-            __Pyx_GIVEREF(__pyx_t_1);
-            __Pyx_ErrRestore(__pyx_t_4, __pyx_t_2, __pyx_t_1);
-            __pyx_t_4 = 0; __pyx_t_2 = 0; __pyx_t_1 = 0; 
-            {__pyx_filename = __pyx_f[0]; __pyx_lineno = 85; __pyx_clineno = __LINE__; goto __pyx_L9_except_error;}
-            goto __pyx_L23;
-          }
-          __pyx_L23:;
-          __Pyx_DECREF(((PyObject *)__pyx_t_11)); __pyx_t_11 = 0;
-          __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
-          __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
-          __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
-          goto __pyx_L8_exception_handled;
-        }
-        __pyx_L9_except_error:;
-        __Pyx_XGIVEREF(__pyx_t_5);
-        __Pyx_XGIVEREF(__pyx_t_6);
-        __Pyx_XGIVEREF(__pyx_t_7);
-        __Pyx_ExceptionReset(__pyx_t_5, __pyx_t_6, __pyx_t_7);
-        goto __pyx_L1_error;
-        __pyx_L8_exception_handled:;
-        __Pyx_XGIVEREF(__pyx_t_5);
-        __Pyx_XGIVEREF(__pyx_t_6);
-        __Pyx_XGIVEREF(__pyx_t_7);
-        __Pyx_ExceptionReset(__pyx_t_5, __pyx_t_6, __pyx_t_7);
-        __pyx_L14_try_end:;
-      }
-    }
-    /*finally:*/ {
-      if (__pyx_t_3) {
-        __pyx_t_7 = PyObject_Call(__pyx_t_3, __pyx_k_tuple_46, NULL);
-        __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
-        if (unlikely(!__pyx_t_7)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 85; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-        __Pyx_GOTREF(__pyx_t_7);
-        __pyx_t_16 = __Pyx_PyObject_IsTrue(__pyx_t_7);
-        __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;
-        if (unlikely(__pyx_t_16 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 85; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-      }
-    }
-    goto __pyx_L24;
-    __pyx_L3_error:;
-    __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
-    goto __pyx_L1_error;
-    __pyx_L24:;
-  }
+  __Pyx_XDECREF(__pyx_r);
+  __Pyx_INCREF(((PyObject *)__pyx_v_self));
+  __pyx_r = ((PyObject *)__pyx_v_self);
+  goto __pyx_L0;
 
   __pyx_r = Py_None; __Pyx_INCREF(Py_None);
-  goto __pyx_L0;
-  __pyx_L1_error:;
-  __Pyx_XDECREF(__pyx_t_1);
-  __Pyx_XDECREF(__pyx_t_2);
-  __Pyx_XDECREF(__pyx_t_4);
-  __Pyx_XDECREF(__pyx_t_11);
-  __Pyx_XDECREF(__pyx_t_12);
-  __Pyx_AddTraceback("_cdec.Decoder.read_weights", __pyx_clineno, __pyx_lineno, __pyx_filename);
-  __pyx_r = NULL;
   __pyx_L0:;
-  __Pyx_XDECREF(__pyx_v_fp);
-  __Pyx_XDECREF(__pyx_v_line);
-  __Pyx_XDECREF(__pyx_v_fname);
-  __Pyx_XDECREF(__pyx_v_value);
   __Pyx_XGIVEREF(__pyx_r);
   __Pyx_RefNannyFinishContext();
   return __pyx_r;
 }
 
 /* Python wrapper */
-static PyObject *__pyx_pw_5_cdec_7Decoder_7translate(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/
-static PyObject *__pyx_pw_5_cdec_7Decoder_7translate(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) {
-  PyObject *__pyx_v_sentence = 0;
-  PyObject *__pyx_v_grammar = 0;
-  static PyObject **__pyx_pyargnames[] = {&__pyx_n_s__sentence,&__pyx_n_s__grammar,0};
+static PyObject *__pyx_pw_5_cdec_15SufficientStats_10__add__(PyObject *__pyx_v_x, PyObject *__pyx_v_y); /*proto*/
+static PyObject *__pyx_pw_5_cdec_15SufficientStats_10__add__(PyObject *__pyx_v_x, PyObject *__pyx_v_y) {
   PyObject *__pyx_r = 0;
   __Pyx_RefNannyDeclarations
-  __Pyx_RefNannySetupContext("translate (wrapper)", 0);
-  {
-    PyObject* values[2] = {0,0};
+  __Pyx_RefNannySetupContext("__add__ (wrapper)", 0);
+  __pyx_r = __pyx_pf_5_cdec_15SufficientStats_9__add__(((PyObject *)__pyx_v_x), ((PyObject *)__pyx_v_y));
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
 
-    /* "_cdec.pyx":91
- *                 self.weights[fname.strip()] = float(value)
+/* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":52
+ *         return self
  * 
- *     def translate(self, sentence, grammar=None):             # <<<<<<<<<<<<<<
- *         if isinstance(sentence, unicode):
- *             inp = sentence.strip().encode('utf8')
- */
-    values[1] = ((PyObject *)Py_None);
+ *     def __add__(x, y):             # <<<<<<<<<<<<<<
+ *         cdef SufficientStats sx = as_stats(x, y)
+ *         cdef SufficientStats sy = as_stats(y, x)
+ */
+
+static PyObject *__pyx_pf_5_cdec_15SufficientStats_9__add__(PyObject *__pyx_v_x, PyObject *__pyx_v_y) {
+  struct __pyx_obj_5_cdec_SufficientStats *__pyx_v_sx = 0;
+  struct __pyx_obj_5_cdec_SufficientStats *__pyx_v_sy = 0;
+  struct __pyx_obj_5_cdec_SufficientStats *__pyx_v_result = 0;
+  PyObject *__pyx_r = NULL;
+  __Pyx_RefNannyDeclarations
+  PyObject *__pyx_t_1 = NULL;
+  int __pyx_lineno = 0;
+  const char *__pyx_filename = NULL;
+  int __pyx_clineno = 0;
+  __Pyx_RefNannySetupContext("__add__", 0);
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":53
+ * 
+ *     def __add__(x, y):
+ *         cdef SufficientStats sx = as_stats(x, y)             # <<<<<<<<<<<<<<
+ *         cdef SufficientStats sy = as_stats(y, x)
+ *         cdef SufficientStats result = SufficientStats()
+ */
+  __pyx_t_1 = ((PyObject *)__pyx_f_5_cdec_as_stats(__pyx_v_x, __pyx_v_y)); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 53; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_1);
+  __pyx_v_sx = ((struct __pyx_obj_5_cdec_SufficientStats *)__pyx_t_1);
+  __pyx_t_1 = 0;
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":54
+ *     def __add__(x, y):
+ *         cdef SufficientStats sx = as_stats(x, y)
+ *         cdef SufficientStats sy = as_stats(y, x)             # <<<<<<<<<<<<<<
+ *         cdef SufficientStats result = SufficientStats()
+ *         result.stats = new mteval.SufficientStats(mteval.add(sx.stats[0], sy.stats[0]))
+ */
+  __pyx_t_1 = ((PyObject *)__pyx_f_5_cdec_as_stats(__pyx_v_y, __pyx_v_x)); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 54; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_1);
+  __pyx_v_sy = ((struct __pyx_obj_5_cdec_SufficientStats *)__pyx_t_1);
+  __pyx_t_1 = 0;
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":55
+ *         cdef SufficientStats sx = as_stats(x, y)
+ *         cdef SufficientStats sy = as_stats(y, x)
+ *         cdef SufficientStats result = SufficientStats()             # <<<<<<<<<<<<<<
+ *         result.stats = new mteval.SufficientStats(mteval.add(sx.stats[0], sy.stats[0]))
+ *         result.metric = sx.metric
+ */
+  __pyx_t_1 = PyObject_Call(((PyObject *)((PyObject*)__pyx_ptype_5_cdec_SufficientStats)), ((PyObject *)__pyx_empty_tuple), NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 55; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_1);
+  __pyx_v_result = ((struct __pyx_obj_5_cdec_SufficientStats *)__pyx_t_1);
+  __pyx_t_1 = 0;
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":56
+ *         cdef SufficientStats sy = as_stats(y, x)
+ *         cdef SufficientStats result = SufficientStats()
+ *         result.stats = new mteval.SufficientStats(mteval.add(sx.stats[0], sy.stats[0]))             # <<<<<<<<<<<<<<
+ *         result.metric = sx.metric
+ *         return result
+ */
+  __pyx_v_result->stats = new SufficientStats(operator+((__pyx_v_sx->stats[0]), (__pyx_v_sy->stats[0])));
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":57
+ *         cdef SufficientStats result = SufficientStats()
+ *         result.stats = new mteval.SufficientStats(mteval.add(sx.stats[0], sy.stats[0]))
+ *         result.metric = sx.metric             # <<<<<<<<<<<<<<
+ *         return result
+ * 
+ */
+  __pyx_v_result->metric = __pyx_v_sx->metric;
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":58
+ *         result.stats = new mteval.SufficientStats(mteval.add(sx.stats[0], sy.stats[0]))
+ *         result.metric = sx.metric
+ *         return result             # <<<<<<<<<<<<<<
+ * 
+ * cdef class CandidateSet:
+ */
+  __Pyx_XDECREF(__pyx_r);
+  __Pyx_INCREF(((PyObject *)__pyx_v_result));
+  __pyx_r = ((PyObject *)__pyx_v_result);
+  goto __pyx_L0;
+
+  __pyx_r = Py_None; __Pyx_INCREF(Py_None);
+  goto __pyx_L0;
+  __pyx_L1_error:;
+  __Pyx_XDECREF(__pyx_t_1);
+  __Pyx_AddTraceback("_cdec.SufficientStats.__add__", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __pyx_r = NULL;
+  __pyx_L0:;
+  __Pyx_XDECREF((PyObject *)__pyx_v_sx);
+  __Pyx_XDECREF((PyObject *)__pyx_v_sy);
+  __Pyx_XDECREF((PyObject *)__pyx_v_result);
+  __Pyx_XGIVEREF(__pyx_r);
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+/* Python wrapper */
+static int __pyx_pw_5_cdec_12CandidateSet_1__cinit__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/
+static int __pyx_pw_5_cdec_12CandidateSet_1__cinit__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) {
+  struct __pyx_obj_5_cdec_SegmentEvaluator *__pyx_v_evaluator = 0;
+  static PyObject **__pyx_pyargnames[] = {&__pyx_n_s__evaluator,0};
+  int __pyx_r;
+  __Pyx_RefNannyDeclarations
+  __Pyx_RefNannySetupContext("__cinit__ (wrapper)", 0);
+  {
+    PyObject* values[1] = {0};
     if (unlikely(__pyx_kwds)) {
       Py_ssize_t kw_args;
       const Py_ssize_t pos_args = PyTuple_GET_SIZE(__pyx_args);
       switch (pos_args) {
-        case  2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1);
         case  1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0);
         case  0: break;
         default: goto __pyx_L5_argtuple_error;
@@ -13719,331 +13415,4591 @@ static PyObject *__pyx_pw_5_cdec_7Decoder_7translate(PyObject *__pyx_v_self, PyO
       kw_args = PyDict_Size(__pyx_kwds);
       switch (pos_args) {
         case  0:
-        values[0] = PyDict_GetItem(__pyx_kwds, __pyx_n_s__sentence);
+        values[0] = PyDict_GetItem(__pyx_kwds, __pyx_n_s__evaluator);
         if (likely(values[0])) kw_args--;
         else goto __pyx_L5_argtuple_error;
-        case  1:
-        if (kw_args > 0) {
-          PyObject* value = PyDict_GetItem(__pyx_kwds, __pyx_n_s__grammar);
-          if (value) { values[1] = value; kw_args--; }
-        }
       }
       if (unlikely(kw_args > 0)) {
-        if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "translate") < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 91; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+        if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "__cinit__") < 0)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 65; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
       }
+    } else if (PyTuple_GET_SIZE(__pyx_args) != 1) {
+      goto __pyx_L5_argtuple_error;
     } else {
-      switch (PyTuple_GET_SIZE(__pyx_args)) {
-        case  2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1);
-        case  1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0);
-        break;
-        default: goto __pyx_L5_argtuple_error;
-      }
+      values[0] = PyTuple_GET_ITEM(__pyx_args, 0);
     }
-    __pyx_v_sentence = values[0];
-    __pyx_v_grammar = values[1];
+    __pyx_v_evaluator = ((struct __pyx_obj_5_cdec_SegmentEvaluator *)values[0]);
   }
   goto __pyx_L4_argument_unpacking_done;
   __pyx_L5_argtuple_error:;
-  __Pyx_RaiseArgtupleInvalid("translate", 0, 1, 2, PyTuple_GET_SIZE(__pyx_args)); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 91; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+  __Pyx_RaiseArgtupleInvalid("__cinit__", 1, 1, 1, PyTuple_GET_SIZE(__pyx_args)); {__pyx_filename = __pyx_f[5]; __pyx_lineno = 65; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
   __pyx_L3_error:;
-  __Pyx_AddTraceback("_cdec.Decoder.translate", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __Pyx_AddTraceback("_cdec.CandidateSet.__cinit__", __pyx_clineno, __pyx_lineno, __pyx_filename);
   __Pyx_RefNannyFinishContext();
-  return NULL;
+  return -1;
   __pyx_L4_argument_unpacking_done:;
-  __pyx_r = __pyx_pf_5_cdec_7Decoder_6translate(((struct __pyx_obj_5_cdec_Decoder *)__pyx_v_self), __pyx_v_sentence, __pyx_v_grammar);
+  if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_evaluator), __pyx_ptype_5_cdec_SegmentEvaluator, 1, "evaluator", 0))) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 65; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_r = __pyx_pf_5_cdec_12CandidateSet___cinit__(((struct __pyx_obj_5_cdec_CandidateSet *)__pyx_v_self), __pyx_v_evaluator);
+  goto __pyx_L0;
+  __pyx_L1_error:;
+  __pyx_r = -1;
+  __pyx_L0:;
   __Pyx_RefNannyFinishContext();
   return __pyx_r;
 }
 
-static PyObject *__pyx_pf_5_cdec_7Decoder_6translate(struct __pyx_obj_5_cdec_Decoder *__pyx_v_self, PyObject *__pyx_v_sentence, PyObject *__pyx_v_grammar) {
-  PyObject *__pyx_v_inp = NULL;
-  BasicObserver __pyx_v_observer;
-  struct __pyx_obj_5_cdec_Hypergraph *__pyx_v_hg = 0;
-  PyObject *__pyx_r = NULL;
+/* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":65
+ *     cdef mteval.CandidateSet* cs
+ * 
+ *     def __cinit__(self, SegmentEvaluator evaluator):             # <<<<<<<<<<<<<<
+ *         self.scorer = new shared_ptr[mteval.SegmentEvaluator](evaluator.scorer[0])
+ *         self.metric = evaluator.metric
+ */
+
+static int __pyx_pf_5_cdec_12CandidateSet___cinit__(struct __pyx_obj_5_cdec_CandidateSet *__pyx_v_self, struct __pyx_obj_5_cdec_SegmentEvaluator *__pyx_v_evaluator) {
+  int __pyx_r;
   __Pyx_RefNannyDeclarations
-  PyObject *__pyx_t_1 = NULL;
-  int __pyx_t_2;
-  PyObject *__pyx_t_3 = NULL;
-  char *__pyx_t_4;
-  int __pyx_lineno = 0;
-  const char *__pyx_filename = NULL;
-  int __pyx_clineno = 0;
-  __Pyx_RefNannySetupContext("translate", 0);
+  __Pyx_RefNannySetupContext("__cinit__", 0);
 
-  /* "_cdec.pyx":92
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":66
  * 
- *     def translate(self, sentence, grammar=None):
- *         if isinstance(sentence, unicode):             # <<<<<<<<<<<<<<
- *             inp = sentence.strip().encode('utf8')
- *         elif isinstance(sentence, str):
+ *     def __cinit__(self, SegmentEvaluator evaluator):
+ *         self.scorer = new shared_ptr[mteval.SegmentEvaluator](evaluator.scorer[0])             # <<<<<<<<<<<<<<
+ *         self.metric = evaluator.metric
+ *         self.cs = new mteval.CandidateSet()
  */
-  __pyx_t_1 = ((PyObject *)((PyObject*)(&PyUnicode_Type)));
-  __Pyx_INCREF(__pyx_t_1);
-  __pyx_t_2 = __Pyx_TypeCheck(__pyx_v_sentence, __pyx_t_1); 
-  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
-  if (__pyx_t_2) {
+  __pyx_v_self->scorer = new boost::shared_ptr<SegmentEvaluator>((__pyx_v_evaluator->scorer[0]));
 
-    /* "_cdec.pyx":93
- *     def translate(self, sentence, grammar=None):
- *         if isinstance(sentence, unicode):
- *             inp = sentence.strip().encode('utf8')             # <<<<<<<<<<<<<<
- *         elif isinstance(sentence, str):
- *             inp = sentence.strip()
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":67
+ *     def __cinit__(self, SegmentEvaluator evaluator):
+ *         self.scorer = new shared_ptr[mteval.SegmentEvaluator](evaluator.scorer[0])
+ *         self.metric = evaluator.metric             # <<<<<<<<<<<<<<
+ *         self.cs = new mteval.CandidateSet()
+ * 
  */
-    __pyx_t_1 = PyObject_GetAttr(__pyx_v_sentence, __pyx_n_s__strip); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 93; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-    __Pyx_GOTREF(__pyx_t_1);
-    __pyx_t_3 = PyObject_Call(__pyx_t_1, ((PyObject *)__pyx_empty_tuple), NULL); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 93; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-    __Pyx_GOTREF(__pyx_t_3);
-    __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
-    __pyx_t_1 = PyObject_GetAttr(__pyx_t_3, __pyx_n_s__encode); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 93; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-    __Pyx_GOTREF(__pyx_t_1);
-    __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
-    __pyx_t_3 = PyObject_Call(__pyx_t_1, ((PyObject *)__pyx_k_tuple_47), NULL); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 93; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-    __Pyx_GOTREF(__pyx_t_3);
-    __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
-    __pyx_v_inp = __pyx_t_3;
-    __pyx_t_3 = 0;
-    goto __pyx_L3;
-  }
+  __pyx_v_self->metric = __pyx_v_evaluator->metric;
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":68
+ *         self.scorer = new shared_ptr[mteval.SegmentEvaluator](evaluator.scorer[0])
+ *         self.metric = evaluator.metric
+ *         self.cs = new mteval.CandidateSet()             # <<<<<<<<<<<<<<
+ * 
+ *     def __dealloc__(self):
+ */
+  __pyx_v_self->cs = new training::CandidateSet();
+
+  __pyx_r = 0;
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+/* Python wrapper */
+static void __pyx_pw_5_cdec_12CandidateSet_3__dealloc__(PyObject *__pyx_v_self); /*proto*/
+static void __pyx_pw_5_cdec_12CandidateSet_3__dealloc__(PyObject *__pyx_v_self) {
+  __Pyx_RefNannyDeclarations
+  __Pyx_RefNannySetupContext("__dealloc__ (wrapper)", 0);
+  __pyx_pf_5_cdec_12CandidateSet_2__dealloc__(((struct __pyx_obj_5_cdec_CandidateSet *)__pyx_v_self));
+  __Pyx_RefNannyFinishContext();
+}
+
+/* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":70
+ *         self.cs = new mteval.CandidateSet()
+ * 
+ *     def __dealloc__(self):             # <<<<<<<<<<<<<<
+ *         del self.scorer
+ *         del self.cs
+ */
+
+static void __pyx_pf_5_cdec_12CandidateSet_2__dealloc__(CYTHON_UNUSED struct __pyx_obj_5_cdec_CandidateSet *__pyx_v_self) {
+  __Pyx_RefNannyDeclarations
+  __Pyx_RefNannySetupContext("__dealloc__", 0);
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":71
+ * 
+ *     def __dealloc__(self):
+ *         del self.scorer             # <<<<<<<<<<<<<<
+ *         del self.cs
+ * 
+ */
+  delete __pyx_v_self->scorer;
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":72
+ *     def __dealloc__(self):
+ *         del self.scorer
+ *         del self.cs             # <<<<<<<<<<<<<<
+ * 
+ *     def __len__(self):
+ */
+  delete __pyx_v_self->cs;
+
+  __Pyx_RefNannyFinishContext();
+}
+
+/* Python wrapper */
+static Py_ssize_t __pyx_pw_5_cdec_12CandidateSet_5__len__(PyObject *__pyx_v_self); /*proto*/
+static Py_ssize_t __pyx_pw_5_cdec_12CandidateSet_5__len__(PyObject *__pyx_v_self) {
+  Py_ssize_t __pyx_r;
+  __Pyx_RefNannyDeclarations
+  __Pyx_RefNannySetupContext("__len__ (wrapper)", 0);
+  __pyx_r = __pyx_pf_5_cdec_12CandidateSet_4__len__(((struct __pyx_obj_5_cdec_CandidateSet *)__pyx_v_self));
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+/* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":74
+ *         del self.cs
+ * 
+ *     def __len__(self):             # <<<<<<<<<<<<<<
+ *         return self.cs.size()
+ * 
+ */
+
+static Py_ssize_t __pyx_pf_5_cdec_12CandidateSet_4__len__(struct __pyx_obj_5_cdec_CandidateSet *__pyx_v_self) {
+  Py_ssize_t __pyx_r;
+  __Pyx_RefNannyDeclarations
+  __Pyx_RefNannySetupContext("__len__", 0);
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":75
+ * 
+ *     def __len__(self):
+ *         return self.cs.size()             # <<<<<<<<<<<<<<
+ * 
+ *     def __getitem__(self,int k):
+ */
+  __pyx_r = __pyx_v_self->cs->size();
+  goto __pyx_L0;
+
+  __pyx_r = 0;
+  __pyx_L0:;
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+/* Python wrapper */
+static PyObject *__pyx_pw_5_cdec_12CandidateSet_7__getitem__(PyObject *__pyx_v_self, PyObject *__pyx_arg_k); /*proto*/
+static PyObject *__pyx_pw_5_cdec_12CandidateSet_7__getitem__(PyObject *__pyx_v_self, PyObject *__pyx_arg_k) {
+  int __pyx_v_k;
+  PyObject *__pyx_r = 0;
+  __Pyx_RefNannyDeclarations
+  __Pyx_RefNannySetupContext("__getitem__ (wrapper)", 0);
+  assert(__pyx_arg_k); {
+    __pyx_v_k = __Pyx_PyInt_AsInt(__pyx_arg_k); if (unlikely((__pyx_v_k == (int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 77; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+  }
+  goto __pyx_L4_argument_unpacking_done;
+  __pyx_L3_error:;
+  __Pyx_AddTraceback("_cdec.CandidateSet.__getitem__", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __Pyx_RefNannyFinishContext();
+  return NULL;
+  __pyx_L4_argument_unpacking_done:;
+  __pyx_r = __pyx_pf_5_cdec_12CandidateSet_6__getitem__(((struct __pyx_obj_5_cdec_CandidateSet *)__pyx_v_self), ((int)__pyx_v_k));
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+/* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":77
+ *         return self.cs.size()
+ * 
+ *     def __getitem__(self,int k):             # <<<<<<<<<<<<<<
+ *         if not 0 <= k < self.cs.size():
+ *             raise IndexError('candidate set index out of range')
+ */
+
+static PyObject *__pyx_pf_5_cdec_12CandidateSet_6__getitem__(struct __pyx_obj_5_cdec_CandidateSet *__pyx_v_self, int __pyx_v_k) {
+  struct __pyx_obj_5_cdec_Candidate *__pyx_v_candidate = 0;
+  PyObject *__pyx_r = NULL;
+  __Pyx_RefNannyDeclarations
+  int __pyx_t_1;
+  int __pyx_t_2;
+  PyObject *__pyx_t_3 = NULL;
+  int __pyx_lineno = 0;
+  const char *__pyx_filename = NULL;
+  int __pyx_clineno = 0;
+  __Pyx_RefNannySetupContext("__getitem__", 0);
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":78
+ * 
+ *     def __getitem__(self,int k):
+ *         if not 0 <= k < self.cs.size():             # <<<<<<<<<<<<<<
+ *             raise IndexError('candidate set index out of range')
+ *         cdef Candidate candidate = Candidate()
+ */
+  __pyx_t_1 = (0 <= __pyx_v_k);
+  if (__pyx_t_1) {
+    __pyx_t_1 = (__pyx_v_k < __pyx_v_self->cs->size());
+  }
+  __pyx_t_2 = (!__pyx_t_1);
+  if (__pyx_t_2) {
+
+    /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":79
+ *     def __getitem__(self,int k):
+ *         if not 0 <= k < self.cs.size():
+ *             raise IndexError('candidate set index out of range')             # <<<<<<<<<<<<<<
+ *         cdef Candidate candidate = Candidate()
+ *         candidate.candidate = &self.cs[0][k]
+ */
+    __pyx_t_3 = PyObject_Call(__pyx_builtin_IndexError, ((PyObject *)__pyx_k_tuple_42), NULL); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 79; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_3);
+    __Pyx_Raise(__pyx_t_3, 0, 0, 0);
+    __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
+    {__pyx_filename = __pyx_f[5]; __pyx_lineno = 79; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    goto __pyx_L3;
+  }
+  __pyx_L3:;
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":80
+ *         if not 0 <= k < self.cs.size():
+ *             raise IndexError('candidate set index out of range')
+ *         cdef Candidate candidate = Candidate()             # <<<<<<<<<<<<<<
+ *         candidate.candidate = &self.cs[0][k]
+ *         candidate.score = self.metric.ComputeScore(self.cs[0][k].eval_feats)
+ */
+  __pyx_t_3 = PyObject_Call(((PyObject *)((PyObject*)__pyx_ptype_5_cdec_Candidate)), ((PyObject *)__pyx_empty_tuple), NULL); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 80; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_3);
+  __pyx_v_candidate = ((struct __pyx_obj_5_cdec_Candidate *)__pyx_t_3);
+  __pyx_t_3 = 0;
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":81
+ *             raise IndexError('candidate set index out of range')
+ *         cdef Candidate candidate = Candidate()
+ *         candidate.candidate = &self.cs[0][k]             # <<<<<<<<<<<<<<
+ *         candidate.score = self.metric.ComputeScore(self.cs[0][k].eval_feats)
+ *         return candidate
+ */
+  __pyx_v_candidate->candidate = (&((__pyx_v_self->cs[0])[__pyx_v_k]));
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":82
+ *         cdef Candidate candidate = Candidate()
+ *         candidate.candidate = &self.cs[0][k]
+ *         candidate.score = self.metric.ComputeScore(self.cs[0][k].eval_feats)             # <<<<<<<<<<<<<<
+ *         return candidate
+ * 
+ */
+  __pyx_v_candidate->score = __pyx_v_self->metric->ComputeScore(((__pyx_v_self->cs[0])[__pyx_v_k]).eval_feats);
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":83
+ *         candidate.candidate = &self.cs[0][k]
+ *         candidate.score = self.metric.ComputeScore(self.cs[0][k].eval_feats)
+ *         return candidate             # <<<<<<<<<<<<<<
+ * 
+ *     def __iter__(self):
+ */
+  __Pyx_XDECREF(__pyx_r);
+  __Pyx_INCREF(((PyObject *)__pyx_v_candidate));
+  __pyx_r = ((PyObject *)__pyx_v_candidate);
+  goto __pyx_L0;
+
+  __pyx_r = Py_None; __Pyx_INCREF(Py_None);
+  goto __pyx_L0;
+  __pyx_L1_error:;
+  __Pyx_XDECREF(__pyx_t_3);
+  __Pyx_AddTraceback("_cdec.CandidateSet.__getitem__", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __pyx_r = NULL;
+  __pyx_L0:;
+  __Pyx_XDECREF((PyObject *)__pyx_v_candidate);
+  __Pyx_XGIVEREF(__pyx_r);
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+static PyObject *__pyx_gb_5_cdec_12CandidateSet_10generator15(__pyx_GeneratorObject *__pyx_generator, PyObject *__pyx_sent_value); /* proto */
+
+/* Python wrapper */
+static PyObject *__pyx_pw_5_cdec_12CandidateSet_9__iter__(PyObject *__pyx_v_self); /*proto*/
+static PyObject *__pyx_pw_5_cdec_12CandidateSet_9__iter__(PyObject *__pyx_v_self) {
+  PyObject *__pyx_r = 0;
+  __Pyx_RefNannyDeclarations
+  __Pyx_RefNannySetupContext("__iter__ (wrapper)", 0);
+  __pyx_r = __pyx_pf_5_cdec_12CandidateSet_8__iter__(((struct __pyx_obj_5_cdec_CandidateSet *)__pyx_v_self));
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+/* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":85
+ *         return candidate
+ * 
+ *     def __iter__(self):             # <<<<<<<<<<<<<<
+ *         cdef unsigned i
+ *         for i in range(len(self)):
+ */
+
+static PyObject *__pyx_pf_5_cdec_12CandidateSet_8__iter__(struct __pyx_obj_5_cdec_CandidateSet *__pyx_v_self) {
+  struct __pyx_obj_5_cdec___pyx_scope_struct_21___iter__ *__pyx_cur_scope;
+  PyObject *__pyx_r = NULL;
+  __Pyx_RefNannyDeclarations
+  int __pyx_lineno = 0;
+  const char *__pyx_filename = NULL;
+  int __pyx_clineno = 0;
+  __Pyx_RefNannySetupContext("__iter__", 0);
+  __pyx_cur_scope = (struct __pyx_obj_5_cdec___pyx_scope_struct_21___iter__ *)__pyx_ptype_5_cdec___pyx_scope_struct_21___iter__->tp_new(__pyx_ptype_5_cdec___pyx_scope_struct_21___iter__, __pyx_empty_tuple, NULL);
+  if (unlikely(!__pyx_cur_scope)) {
+    __Pyx_RefNannyFinishContext();
+    return NULL;
+  }
+  __Pyx_GOTREF(__pyx_cur_scope);
+  __pyx_cur_scope->__pyx_v_self = __pyx_v_self;
+  __Pyx_INCREF((PyObject *)__pyx_cur_scope->__pyx_v_self);
+  __Pyx_GIVEREF((PyObject *)__pyx_cur_scope->__pyx_v_self);
+  {
+    __pyx_GeneratorObject *gen = __Pyx_Generator_New((__pyx_generator_body_t) __pyx_gb_5_cdec_12CandidateSet_10generator15, (PyObject *) __pyx_cur_scope); if (unlikely(!gen)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 85; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_DECREF(__pyx_cur_scope);
+    __Pyx_RefNannyFinishContext();
+    return (PyObject *) gen;
+  }
+
+  __pyx_r = Py_None; __Pyx_INCREF(Py_None);
+  goto __pyx_L0;
+  __pyx_L1_error:;
+  __Pyx_AddTraceback("_cdec.CandidateSet.__iter__", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __pyx_r = NULL;
+  __pyx_L0:;
+  __Pyx_DECREF(((PyObject *)__pyx_cur_scope));
+  __Pyx_XGIVEREF(__pyx_r);
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+static PyObject *__pyx_gb_5_cdec_12CandidateSet_10generator15(__pyx_GeneratorObject *__pyx_generator, PyObject *__pyx_sent_value) /* generator body */
+{
+  struct __pyx_obj_5_cdec___pyx_scope_struct_21___iter__ *__pyx_cur_scope = ((struct __pyx_obj_5_cdec___pyx_scope_struct_21___iter__ *)__pyx_generator->closure);
+  PyObject *__pyx_r = NULL;
+  Py_ssize_t __pyx_t_1;
+  unsigned int __pyx_t_2;
+  PyObject *__pyx_t_3 = NULL;
+  __Pyx_RefNannyDeclarations
+  __Pyx_RefNannySetupContext("None", 0);
+  switch (__pyx_generator->resume_label) {
+    case 0: goto __pyx_L3_first_run;
+    case 1: goto __pyx_L6_resume_from_yield;
+    default: /* CPython raises the right error here */
+    __Pyx_RefNannyFinishContext();
+    return NULL;
+  }
+  __pyx_L3_first_run:;
+  if (unlikely(!__pyx_sent_value)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 85; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":87
+ *     def __iter__(self):
+ *         cdef unsigned i
+ *         for i in range(len(self)):             # <<<<<<<<<<<<<<
+ *             yield self[i]
+ * 
+ */
+  __pyx_t_1 = PyObject_Length(((PyObject *)__pyx_cur_scope->__pyx_v_self)); if (unlikely(__pyx_t_1 == -1)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 87; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  for (__pyx_t_2 = 0; __pyx_t_2 < __pyx_t_1; __pyx_t_2+=1) {
+    __pyx_cur_scope->__pyx_v_i = __pyx_t_2;
+
+    /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":88
+ *         cdef unsigned i
+ *         for i in range(len(self)):
+ *             yield self[i]             # <<<<<<<<<<<<<<
+ * 
+ *     def add_kbest(self, Hypergraph hypergraph, unsigned k):
+ */
+    __pyx_t_3 = __Pyx_GetItemInt(((PyObject *)__pyx_cur_scope->__pyx_v_self), __pyx_cur_scope->__pyx_v_i, sizeof(unsigned int)+1, PyLong_FromUnsignedLong); if (!__pyx_t_3) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 88; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_3);
+    __pyx_r = __pyx_t_3;
+    __pyx_t_3 = 0;
+    __pyx_cur_scope->__pyx_t_0 = __pyx_t_1;
+    __pyx_cur_scope->__pyx_t_1 = __pyx_t_2;
+    __Pyx_XGIVEREF(__pyx_r);
+    __Pyx_RefNannyFinishContext();
+    /* return from generator, yielding value */
+    __pyx_generator->resume_label = 1;
+    return __pyx_r;
+    __pyx_L6_resume_from_yield:;
+    __pyx_t_1 = __pyx_cur_scope->__pyx_t_0;
+    __pyx_t_2 = __pyx_cur_scope->__pyx_t_1;
+    if (unlikely(!__pyx_sent_value)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 88; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  }
+  PyErr_SetNone(PyExc_StopIteration);
+  goto __pyx_L0;
+  __pyx_L1_error:;
+  __Pyx_XDECREF(__pyx_t_3);
+  __Pyx_AddTraceback("__iter__", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __pyx_L0:;
+  __Pyx_XDECREF(__pyx_r);
+  __pyx_generator->resume_label = -1;
+  __Pyx_RefNannyFinishContext();
+  return NULL;
+}
+
+/* Python wrapper */
+static PyObject *__pyx_pw_5_cdec_12CandidateSet_12add_kbest(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/
+static PyObject *__pyx_pw_5_cdec_12CandidateSet_12add_kbest(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) {
+  struct __pyx_obj_5_cdec_Hypergraph *__pyx_v_hypergraph = 0;
+  unsigned int __pyx_v_k;
+  static PyObject **__pyx_pyargnames[] = {&__pyx_n_s__hypergraph,&__pyx_n_s__k,0};
+  PyObject *__pyx_r = 0;
+  __Pyx_RefNannyDeclarations
+  __Pyx_RefNannySetupContext("add_kbest (wrapper)", 0);
+  {
+    PyObject* values[2] = {0,0};
+    if (unlikely(__pyx_kwds)) {
+      Py_ssize_t kw_args;
+      const Py_ssize_t pos_args = PyTuple_GET_SIZE(__pyx_args);
+      switch (pos_args) {
+        case  2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1);
+        case  1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0);
+        case  0: break;
+        default: goto __pyx_L5_argtuple_error;
+      }
+      kw_args = PyDict_Size(__pyx_kwds);
+      switch (pos_args) {
+        case  0:
+        values[0] = PyDict_GetItem(__pyx_kwds, __pyx_n_s__hypergraph);
+        if (likely(values[0])) kw_args--;
+        else goto __pyx_L5_argtuple_error;
+        case  1:
+        values[1] = PyDict_GetItem(__pyx_kwds, __pyx_n_s__k);
+        if (likely(values[1])) kw_args--;
+        else {
+          __Pyx_RaiseArgtupleInvalid("add_kbest", 1, 2, 2, 1); {__pyx_filename = __pyx_f[5]; __pyx_lineno = 90; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+        }
+      }
+      if (unlikely(kw_args > 0)) {
+        if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "add_kbest") < 0)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 90; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+      }
+    } else if (PyTuple_GET_SIZE(__pyx_args) != 2) {
+      goto __pyx_L5_argtuple_error;
+    } else {
+      values[0] = PyTuple_GET_ITEM(__pyx_args, 0);
+      values[1] = PyTuple_GET_ITEM(__pyx_args, 1);
+    }
+    __pyx_v_hypergraph = ((struct __pyx_obj_5_cdec_Hypergraph *)values[0]);
+    __pyx_v_k = __Pyx_PyInt_AsUnsignedInt(values[1]); if (unlikely((__pyx_v_k == (unsigned int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 90; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+  }
+  goto __pyx_L4_argument_unpacking_done;
+  __pyx_L5_argtuple_error:;
+  __Pyx_RaiseArgtupleInvalid("add_kbest", 1, 2, 2, PyTuple_GET_SIZE(__pyx_args)); {__pyx_filename = __pyx_f[5]; __pyx_lineno = 90; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+  __pyx_L3_error:;
+  __Pyx_AddTraceback("_cdec.CandidateSet.add_kbest", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __Pyx_RefNannyFinishContext();
+  return NULL;
+  __pyx_L4_argument_unpacking_done:;
+  if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_hypergraph), __pyx_ptype_5_cdec_Hypergraph, 1, "hypergraph", 0))) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 90; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_r = __pyx_pf_5_cdec_12CandidateSet_11add_kbest(((struct __pyx_obj_5_cdec_CandidateSet *)__pyx_v_self), __pyx_v_hypergraph, __pyx_v_k);
+  goto __pyx_L0;
+  __pyx_L1_error:;
+  __pyx_r = NULL;
+  __pyx_L0:;
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+/* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":90
+ *             yield self[i]
+ * 
+ *     def add_kbest(self, Hypergraph hypergraph, unsigned k):             # <<<<<<<<<<<<<<
+ *         self.cs.AddKBestCandidates(hypergraph.hg[0], k, self.scorer.get())
+ * 
+ */
+
+static PyObject *__pyx_pf_5_cdec_12CandidateSet_11add_kbest(struct __pyx_obj_5_cdec_CandidateSet *__pyx_v_self, struct __pyx_obj_5_cdec_Hypergraph *__pyx_v_hypergraph, unsigned int __pyx_v_k) {
+  PyObject *__pyx_r = NULL;
+  __Pyx_RefNannyDeclarations
+  __Pyx_RefNannySetupContext("add_kbest", 0);
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":91
+ * 
+ *     def add_kbest(self, Hypergraph hypergraph, unsigned k):
+ *         self.cs.AddKBestCandidates(hypergraph.hg[0], k, self.scorer.get())             # <<<<<<<<<<<<<<
+ * 
+ * cdef class SegmentEvaluator:
+ */
+  __pyx_v_self->cs->AddKBestCandidates((__pyx_v_hypergraph->hg[0]), __pyx_v_k, __pyx_v_self->scorer->get());
+
+  __pyx_r = Py_None; __Pyx_INCREF(Py_None);
+  __Pyx_XGIVEREF(__pyx_r);
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+/* Python wrapper */
+static void __pyx_pw_5_cdec_16SegmentEvaluator_1__dealloc__(PyObject *__pyx_v_self); /*proto*/
+static void __pyx_pw_5_cdec_16SegmentEvaluator_1__dealloc__(PyObject *__pyx_v_self) {
+  __Pyx_RefNannyDeclarations
+  __Pyx_RefNannySetupContext("__dealloc__ (wrapper)", 0);
+  __pyx_pf_5_cdec_16SegmentEvaluator___dealloc__(((struct __pyx_obj_5_cdec_SegmentEvaluator *)__pyx_v_self));
+  __Pyx_RefNannyFinishContext();
+}
+
+/* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":97
+ *     cdef mteval.EvaluationMetric* metric
+ * 
+ *     def __dealloc__(self):             # <<<<<<<<<<<<<<
+ *         del self.scorer
+ * 
+ */
+
+static void __pyx_pf_5_cdec_16SegmentEvaluator___dealloc__(CYTHON_UNUSED struct __pyx_obj_5_cdec_SegmentEvaluator *__pyx_v_self) {
+  __Pyx_RefNannyDeclarations
+  __Pyx_RefNannySetupContext("__dealloc__", 0);
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":98
+ * 
+ *     def __dealloc__(self):
+ *         del self.scorer             # <<<<<<<<<<<<<<
+ * 
+ *     def evaluate(self, sentence):
+ */
+  delete __pyx_v_self->scorer;
+
+  __Pyx_RefNannyFinishContext();
+}
+
+/* Python wrapper */
+static PyObject *__pyx_pw_5_cdec_16SegmentEvaluator_3evaluate(PyObject *__pyx_v_self, PyObject *__pyx_v_sentence); /*proto*/
+static PyObject *__pyx_pw_5_cdec_16SegmentEvaluator_3evaluate(PyObject *__pyx_v_self, PyObject *__pyx_v_sentence) {
+  PyObject *__pyx_r = 0;
+  __Pyx_RefNannyDeclarations
+  __Pyx_RefNannySetupContext("evaluate (wrapper)", 0);
+  __pyx_r = __pyx_pf_5_cdec_16SegmentEvaluator_2evaluate(((struct __pyx_obj_5_cdec_SegmentEvaluator *)__pyx_v_self), ((PyObject *)__pyx_v_sentence));
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+/* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":100
+ *         del self.scorer
+ * 
+ *     def evaluate(self, sentence):             # <<<<<<<<<<<<<<
+ *         cdef vector[WordID] hyp
+ *         cdef SufficientStats sf = SufficientStats()
+ */
+
+static PyObject *__pyx_pf_5_cdec_16SegmentEvaluator_2evaluate(struct __pyx_obj_5_cdec_SegmentEvaluator *__pyx_v_self, PyObject *__pyx_v_sentence) {
+  std::vector<WordID> __pyx_v_hyp;
+  struct __pyx_obj_5_cdec_SufficientStats *__pyx_v_sf = 0;
+  PyObject *__pyx_r = NULL;
+  __Pyx_RefNannyDeclarations
+  PyObject *__pyx_t_1 = NULL;
+  PyObject *__pyx_t_2 = NULL;
+  int __pyx_lineno = 0;
+  const char *__pyx_filename = NULL;
+  int __pyx_clineno = 0;
+  __Pyx_RefNannySetupContext("evaluate", 0);
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":102
+ *     def evaluate(self, sentence):
+ *         cdef vector[WordID] hyp
+ *         cdef SufficientStats sf = SufficientStats()             # <<<<<<<<<<<<<<
+ *         sf.metric = self.metric
+ *         sf.stats = new mteval.SufficientStats()
+ */
+  __pyx_t_1 = PyObject_Call(((PyObject *)((PyObject*)__pyx_ptype_5_cdec_SufficientStats)), ((PyObject *)__pyx_empty_tuple), NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 102; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_1);
+  __pyx_v_sf = ((struct __pyx_obj_5_cdec_SufficientStats *)__pyx_t_1);
+  __pyx_t_1 = 0;
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":103
+ *         cdef vector[WordID] hyp
+ *         cdef SufficientStats sf = SufficientStats()
+ *         sf.metric = self.metric             # <<<<<<<<<<<<<<
+ *         sf.stats = new mteval.SufficientStats()
+ *         ConvertSentence(string(as_str(sentence.strip())), &hyp)
+ */
+  __pyx_v_sf->metric = __pyx_v_self->metric;
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":104
+ *         cdef SufficientStats sf = SufficientStats()
+ *         sf.metric = self.metric
+ *         sf.stats = new mteval.SufficientStats()             # <<<<<<<<<<<<<<
+ *         ConvertSentence(string(as_str(sentence.strip())), &hyp)
+ *         self.scorer.get().Evaluate(hyp, sf.stats)
+ */
+  __pyx_v_sf->stats = new SufficientStats();
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":105
+ *         sf.metric = self.metric
+ *         sf.stats = new mteval.SufficientStats()
+ *         ConvertSentence(string(as_str(sentence.strip())), &hyp)             # <<<<<<<<<<<<<<
+ *         self.scorer.get().Evaluate(hyp, sf.stats)
+ *         return sf
+ */
+  __pyx_t_1 = PyObject_GetAttr(__pyx_v_sentence, __pyx_n_s__strip); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 105; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_1);
+  __pyx_t_2 = PyObject_Call(__pyx_t_1, ((PyObject *)__pyx_empty_tuple), NULL); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 105; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_2);
+  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+  TD::ConvertSentence(std::string(__pyx_f_5_cdec_as_str(__pyx_t_2, NULL)), (&__pyx_v_hyp));
+  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":106
+ *         sf.stats = new mteval.SufficientStats()
+ *         ConvertSentence(string(as_str(sentence.strip())), &hyp)
+ *         self.scorer.get().Evaluate(hyp, sf.stats)             # <<<<<<<<<<<<<<
+ *         return sf
+ * 
+ */
+  __pyx_v_self->scorer->get()->Evaluate(__pyx_v_hyp, __pyx_v_sf->stats);
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":107
+ *         ConvertSentence(string(as_str(sentence.strip())), &hyp)
+ *         self.scorer.get().Evaluate(hyp, sf.stats)
+ *         return sf             # <<<<<<<<<<<<<<
+ * 
+ *     def candidate_set(self):
+ */
+  __Pyx_XDECREF(__pyx_r);
+  __Pyx_INCREF(((PyObject *)__pyx_v_sf));
+  __pyx_r = ((PyObject *)__pyx_v_sf);
+  goto __pyx_L0;
+
+  __pyx_r = Py_None; __Pyx_INCREF(Py_None);
+  goto __pyx_L0;
+  __pyx_L1_error:;
+  __Pyx_XDECREF(__pyx_t_1);
+  __Pyx_XDECREF(__pyx_t_2);
+  __Pyx_AddTraceback("_cdec.SegmentEvaluator.evaluate", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __pyx_r = NULL;
+  __pyx_L0:;
+  __Pyx_XDECREF((PyObject *)__pyx_v_sf);
+  __Pyx_XGIVEREF(__pyx_r);
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+/* Python wrapper */
+static PyObject *__pyx_pw_5_cdec_16SegmentEvaluator_5candidate_set(PyObject *__pyx_v_self, CYTHON_UNUSED PyObject *unused); /*proto*/
+static PyObject *__pyx_pw_5_cdec_16SegmentEvaluator_5candidate_set(PyObject *__pyx_v_self, CYTHON_UNUSED PyObject *unused) {
+  PyObject *__pyx_r = 0;
+  __Pyx_RefNannyDeclarations
+  __Pyx_RefNannySetupContext("candidate_set (wrapper)", 0);
+  __pyx_r = __pyx_pf_5_cdec_16SegmentEvaluator_4candidate_set(((struct __pyx_obj_5_cdec_SegmentEvaluator *)__pyx_v_self));
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+/* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":109
+ *         return sf
+ * 
+ *     def candidate_set(self):             # <<<<<<<<<<<<<<
+ *         return CandidateSet(self)
+ * 
+ */
+
+static PyObject *__pyx_pf_5_cdec_16SegmentEvaluator_4candidate_set(struct __pyx_obj_5_cdec_SegmentEvaluator *__pyx_v_self) {
+  PyObject *__pyx_r = NULL;
+  __Pyx_RefNannyDeclarations
+  PyObject *__pyx_t_1 = NULL;
+  PyObject *__pyx_t_2 = NULL;
+  int __pyx_lineno = 0;
+  const char *__pyx_filename = NULL;
+  int __pyx_clineno = 0;
+  __Pyx_RefNannySetupContext("candidate_set", 0);
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":110
+ * 
+ *     def candidate_set(self):
+ *         return CandidateSet(self)             # <<<<<<<<<<<<<<
+ * 
+ * cdef class Scorer:
+ */
+  __Pyx_XDECREF(__pyx_r);
+  __pyx_t_1 = PyTuple_New(1); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 110; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_1);
+  __Pyx_INCREF(((PyObject *)__pyx_v_self));
+  PyTuple_SET_ITEM(__pyx_t_1, 0, ((PyObject *)__pyx_v_self));
+  __Pyx_GIVEREF(((PyObject *)__pyx_v_self));
+  __pyx_t_2 = PyObject_Call(((PyObject *)((PyObject*)__pyx_ptype_5_cdec_CandidateSet)), ((PyObject *)__pyx_t_1), NULL); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 110; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_2);
+  __Pyx_DECREF(((PyObject *)__pyx_t_1)); __pyx_t_1 = 0;
+  __pyx_r = __pyx_t_2;
+  __pyx_t_2 = 0;
+  goto __pyx_L0;
+
+  __pyx_r = Py_None; __Pyx_INCREF(Py_None);
+  goto __pyx_L0;
+  __pyx_L1_error:;
+  __Pyx_XDECREF(__pyx_t_1);
+  __Pyx_XDECREF(__pyx_t_2);
+  __Pyx_AddTraceback("_cdec.SegmentEvaluator.candidate_set", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __pyx_r = NULL;
+  __pyx_L0:;
+  __Pyx_XGIVEREF(__pyx_r);
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+/* Python wrapper */
+static int __pyx_pw_5_cdec_6Scorer_1__cinit__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/
+static int __pyx_pw_5_cdec_6Scorer_1__cinit__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) {
+  char *__pyx_v_name;
+  static PyObject **__pyx_pyargnames[] = {&__pyx_n_s__name,0};
+  int __pyx_r;
+  __Pyx_RefNannyDeclarations
+  __Pyx_RefNannySetupContext("__cinit__ (wrapper)", 0);
+  {
+    PyObject* values[1] = {0};
+    if (unlikely(__pyx_kwds)) {
+      Py_ssize_t kw_args;
+      const Py_ssize_t pos_args = PyTuple_GET_SIZE(__pyx_args);
+      switch (pos_args) {
+        case  1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0);
+        case  0: break;
+        default: goto __pyx_L5_argtuple_error;
+      }
+      kw_args = PyDict_Size(__pyx_kwds);
+      switch (pos_args) {
+        case  0:
+        values[0] = PyDict_GetItem(__pyx_kwds, __pyx_n_s__name);
+        if (likely(values[0])) kw_args--;
+        else goto __pyx_L5_argtuple_error;
+      }
+      if (unlikely(kw_args > 0)) {
+        if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "__cinit__") < 0)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 115; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+      }
+    } else if (PyTuple_GET_SIZE(__pyx_args) != 1) {
+      goto __pyx_L5_argtuple_error;
+    } else {
+      values[0] = PyTuple_GET_ITEM(__pyx_args, 0);
+    }
+    __pyx_v_name = PyBytes_AsString(values[0]); if (unlikely((!__pyx_v_name) && PyErr_Occurred())) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 115; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+  }
+  goto __pyx_L4_argument_unpacking_done;
+  __pyx_L5_argtuple_error:;
+  __Pyx_RaiseArgtupleInvalid("__cinit__", 1, 1, 1, PyTuple_GET_SIZE(__pyx_args)); {__pyx_filename = __pyx_f[5]; __pyx_lineno = 115; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+  __pyx_L3_error:;
+  __Pyx_AddTraceback("_cdec.Scorer.__cinit__", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __Pyx_RefNannyFinishContext();
+  return -1;
+  __pyx_L4_argument_unpacking_done:;
+  __pyx_r = __pyx_pf_5_cdec_6Scorer___cinit__(((struct __pyx_obj_5_cdec_Scorer *)__pyx_v_self), __pyx_v_name);
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+/* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":115
+ *     cdef string* name
+ * 
+ *     def __cinit__(self, char* name):             # <<<<<<<<<<<<<<
+ *         self.name = new string(name)
+ * 
+ */
+
+static int __pyx_pf_5_cdec_6Scorer___cinit__(struct __pyx_obj_5_cdec_Scorer *__pyx_v_self, char *__pyx_v_name) {
+  int __pyx_r;
+  __Pyx_RefNannyDeclarations
+  __Pyx_RefNannySetupContext("__cinit__", 0);
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":116
+ * 
+ *     def __cinit__(self, char* name):
+ *         self.name = new string(name)             # <<<<<<<<<<<<<<
+ * 
+ *     def __dealloc__(self):
+ */
+  __pyx_v_self->name = new std::string(__pyx_v_name);
+
+  __pyx_r = 0;
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+/* Python wrapper */
+static void __pyx_pw_5_cdec_6Scorer_3__dealloc__(PyObject *__pyx_v_self); /*proto*/
+static void __pyx_pw_5_cdec_6Scorer_3__dealloc__(PyObject *__pyx_v_self) {
+  __Pyx_RefNannyDeclarations
+  __Pyx_RefNannySetupContext("__dealloc__ (wrapper)", 0);
+  __pyx_pf_5_cdec_6Scorer_2__dealloc__(((struct __pyx_obj_5_cdec_Scorer *)__pyx_v_self));
+  __Pyx_RefNannyFinishContext();
+}
+
+/* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":118
+ *         self.name = new string(name)
+ * 
+ *     def __dealloc__(self):             # <<<<<<<<<<<<<<
+ *         del self.name
+ * 
+ */
+
+static void __pyx_pf_5_cdec_6Scorer_2__dealloc__(CYTHON_UNUSED struct __pyx_obj_5_cdec_Scorer *__pyx_v_self) {
+  __Pyx_RefNannyDeclarations
+  __Pyx_RefNannySetupContext("__dealloc__", 0);
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":119
+ * 
+ *     def __dealloc__(self):
+ *         del self.name             # <<<<<<<<<<<<<<
+ * 
+ *     def __call__(self, refs):
+ */
+  delete __pyx_v_self->name;
+
+  __Pyx_RefNannyFinishContext();
+}
+
+/* Python wrapper */
+static PyObject *__pyx_pw_5_cdec_6Scorer_5__call__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/
+static PyObject *__pyx_pw_5_cdec_6Scorer_5__call__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) {
+  PyObject *__pyx_v_refs = 0;
+  static PyObject **__pyx_pyargnames[] = {&__pyx_n_s__refs,0};
+  PyObject *__pyx_r = 0;
+  __Pyx_RefNannyDeclarations
+  __Pyx_RefNannySetupContext("__call__ (wrapper)", 0);
+  {
+    PyObject* values[1] = {0};
+    if (unlikely(__pyx_kwds)) {
+      Py_ssize_t kw_args;
+      const Py_ssize_t pos_args = PyTuple_GET_SIZE(__pyx_args);
+      switch (pos_args) {
+        case  1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0);
+        case  0: break;
+        default: goto __pyx_L5_argtuple_error;
+      }
+      kw_args = PyDict_Size(__pyx_kwds);
+      switch (pos_args) {
+        case  0:
+        values[0] = PyDict_GetItem(__pyx_kwds, __pyx_n_s__refs);
+        if (likely(values[0])) kw_args--;
+        else goto __pyx_L5_argtuple_error;
+      }
+      if (unlikely(kw_args > 0)) {
+        if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "__call__") < 0)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 121; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+      }
+    } else if (PyTuple_GET_SIZE(__pyx_args) != 1) {
+      goto __pyx_L5_argtuple_error;
+    } else {
+      values[0] = PyTuple_GET_ITEM(__pyx_args, 0);
+    }
+    __pyx_v_refs = values[0];
+  }
+  goto __pyx_L4_argument_unpacking_done;
+  __pyx_L5_argtuple_error:;
+  __Pyx_RaiseArgtupleInvalid("__call__", 1, 1, 1, PyTuple_GET_SIZE(__pyx_args)); {__pyx_filename = __pyx_f[5]; __pyx_lineno = 121; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+  __pyx_L3_error:;
+  __Pyx_AddTraceback("_cdec.Scorer.__call__", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __Pyx_RefNannyFinishContext();
+  return NULL;
+  __pyx_L4_argument_unpacking_done:;
+  __pyx_r = __pyx_pf_5_cdec_6Scorer_4__call__(((struct __pyx_obj_5_cdec_Scorer *)__pyx_v_self), __pyx_v_refs);
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+/* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":121
+ *         del self.name
+ * 
+ *     def __call__(self, refs):             # <<<<<<<<<<<<<<
+ *         cdef mteval.EvaluationMetric* metric = mteval.Instance(self.name[0])
+ *         if isinstance(refs, unicode) or isinstance(refs, str):
+ */
+
+static PyObject *__pyx_pf_5_cdec_6Scorer_4__call__(struct __pyx_obj_5_cdec_Scorer *__pyx_v_self, PyObject *__pyx_v_refs) {
+  EvaluationMetric *__pyx_v_metric;
+  std::vector<std::vector<WordID> > *__pyx_v_refsv;
+  std::vector<WordID> *__pyx_v_refv;
+  PyObject *__pyx_v_ref = NULL;
+  struct __pyx_obj_5_cdec_SegmentEvaluator *__pyx_v_evaluator = 0;
+  PyObject *__pyx_r = NULL;
+  __Pyx_RefNannyDeclarations
+  PyObject *__pyx_t_1 = NULL;
+  int __pyx_t_2;
+  int __pyx_t_3;
+  int __pyx_t_4;
+  Py_ssize_t __pyx_t_5;
+  PyObject *(*__pyx_t_6)(PyObject *);
+  PyObject *__pyx_t_7 = NULL;
+  PyObject *__pyx_t_8 = NULL;
+  int __pyx_lineno = 0;
+  const char *__pyx_filename = NULL;
+  int __pyx_clineno = 0;
+  __Pyx_RefNannySetupContext("__call__", 0);
+  __Pyx_INCREF(__pyx_v_refs);
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":122
+ * 
+ *     def __call__(self, refs):
+ *         cdef mteval.EvaluationMetric* metric = mteval.Instance(self.name[0])             # <<<<<<<<<<<<<<
+ *         if isinstance(refs, unicode) or isinstance(refs, str):
+ *             refs = [refs]
+ */
+  __pyx_v_metric = EvaluationMetric::Instance((__pyx_v_self->name[0]));
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":123
+ *     def __call__(self, refs):
+ *         cdef mteval.EvaluationMetric* metric = mteval.Instance(self.name[0])
+ *         if isinstance(refs, unicode) or isinstance(refs, str):             # <<<<<<<<<<<<<<
+ *             refs = [refs]
+ *         cdef vector[vector[WordID]]* refsv = new vector[vector[WordID]]()
+ */
+  __pyx_t_1 = ((PyObject *)((PyObject*)(&PyUnicode_Type)));
+  __Pyx_INCREF(__pyx_t_1);
+  __pyx_t_2 = __Pyx_TypeCheck(__pyx_v_refs, __pyx_t_1); 
+  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+  if (!__pyx_t_2) {
+    __pyx_t_1 = ((PyObject *)((PyObject*)(&PyString_Type)));
+    __Pyx_INCREF(__pyx_t_1);
+    __pyx_t_3 = __Pyx_TypeCheck(__pyx_v_refs, __pyx_t_1); 
+    __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+    __pyx_t_4 = __pyx_t_3;
+  } else {
+    __pyx_t_4 = __pyx_t_2;
+  }
+  if (__pyx_t_4) {
+
+    /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":124
+ *         cdef mteval.EvaluationMetric* metric = mteval.Instance(self.name[0])
+ *         if isinstance(refs, unicode) or isinstance(refs, str):
+ *             refs = [refs]             # <<<<<<<<<<<<<<
+ *         cdef vector[vector[WordID]]* refsv = new vector[vector[WordID]]()
+ *         cdef vector[WordID]* refv
+ */
+    __pyx_t_1 = PyList_New(1); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 124; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_1);
+    __Pyx_INCREF(__pyx_v_refs);
+    PyList_SET_ITEM(__pyx_t_1, 0, __pyx_v_refs);
+    __Pyx_GIVEREF(__pyx_v_refs);
+    __Pyx_DECREF(__pyx_v_refs);
+    __pyx_v_refs = ((PyObject *)__pyx_t_1);
+    __pyx_t_1 = 0;
+    goto __pyx_L3;
+  }
+  __pyx_L3:;
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":125
+ *         if isinstance(refs, unicode) or isinstance(refs, str):
+ *             refs = [refs]
+ *         cdef vector[vector[WordID]]* refsv = new vector[vector[WordID]]()             # <<<<<<<<<<<<<<
+ *         cdef vector[WordID]* refv
+ *         cdef bytes ref_str
+ */
+  __pyx_v_refsv = new std::vector<std::vector<WordID> >();
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":128
+ *         cdef vector[WordID]* refv
+ *         cdef bytes ref_str
+ *         for ref in refs:             # <<<<<<<<<<<<<<
+ *             refv = new vector[WordID]()
+ *             ConvertSentence(string(as_str(ref.strip())), refv)
+ */
+  if (PyList_CheckExact(__pyx_v_refs) || PyTuple_CheckExact(__pyx_v_refs)) {
+    __pyx_t_1 = __pyx_v_refs; __Pyx_INCREF(__pyx_t_1); __pyx_t_5 = 0;
+    __pyx_t_6 = NULL;
+  } else {
+    __pyx_t_5 = -1; __pyx_t_1 = PyObject_GetIter(__pyx_v_refs); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 128; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_1);
+    __pyx_t_6 = Py_TYPE(__pyx_t_1)->tp_iternext;
+  }
+  for (;;) {
+    if (!__pyx_t_6 && PyList_CheckExact(__pyx_t_1)) {
+      if (__pyx_t_5 >= PyList_GET_SIZE(__pyx_t_1)) break;
+      __pyx_t_7 = PyList_GET_ITEM(__pyx_t_1, __pyx_t_5); __Pyx_INCREF(__pyx_t_7); __pyx_t_5++;
+    } else if (!__pyx_t_6 && PyTuple_CheckExact(__pyx_t_1)) {
+      if (__pyx_t_5 >= PyTuple_GET_SIZE(__pyx_t_1)) break;
+      __pyx_t_7 = PyTuple_GET_ITEM(__pyx_t_1, __pyx_t_5); __Pyx_INCREF(__pyx_t_7); __pyx_t_5++;
+    } else {
+      __pyx_t_7 = __pyx_t_6(__pyx_t_1);
+      if (unlikely(!__pyx_t_7)) {
+        if (PyErr_Occurred()) {
+          if (likely(PyErr_ExceptionMatches(PyExc_StopIteration))) PyErr_Clear();
+          else {__pyx_filename = __pyx_f[5]; __pyx_lineno = 128; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+        }
+        break;
+      }
+      __Pyx_GOTREF(__pyx_t_7);
+    }
+    __Pyx_XDECREF(__pyx_v_ref);
+    __pyx_v_ref = __pyx_t_7;
+    __pyx_t_7 = 0;
+
+    /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":129
+ *         cdef bytes ref_str
+ *         for ref in refs:
+ *             refv = new vector[WordID]()             # <<<<<<<<<<<<<<
+ *             ConvertSentence(string(as_str(ref.strip())), refv)
+ *             refsv.push_back(refv[0])
+ */
+    __pyx_v_refv = new std::vector<WordID>();
+
+    /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":130
+ *         for ref in refs:
+ *             refv = new vector[WordID]()
+ *             ConvertSentence(string(as_str(ref.strip())), refv)             # <<<<<<<<<<<<<<
+ *             refsv.push_back(refv[0])
+ *             del refv
+ */
+    __pyx_t_7 = PyObject_GetAttr(__pyx_v_ref, __pyx_n_s__strip); if (unlikely(!__pyx_t_7)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 130; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_7);
+    __pyx_t_8 = PyObject_Call(__pyx_t_7, ((PyObject *)__pyx_empty_tuple), NULL); if (unlikely(!__pyx_t_8)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 130; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_8);
+    __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;
+    TD::ConvertSentence(std::string(__pyx_f_5_cdec_as_str(__pyx_t_8, NULL)), __pyx_v_refv);
+    __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0;
+
+    /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":131
+ *             refv = new vector[WordID]()
+ *             ConvertSentence(string(as_str(ref.strip())), refv)
+ *             refsv.push_back(refv[0])             # <<<<<<<<<<<<<<
+ *             del refv
+ *         cdef unsigned i
+ */
+    __pyx_v_refsv->push_back((__pyx_v_refv[0]));
+
+    /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":132
+ *             ConvertSentence(string(as_str(ref.strip())), refv)
+ *             refsv.push_back(refv[0])
+ *             del refv             # <<<<<<<<<<<<<<
+ *         cdef unsigned i
+ *         cdef SegmentEvaluator evaluator = SegmentEvaluator()
+ */
+    delete __pyx_v_refv;
+  }
+  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":134
+ *             del refv
+ *         cdef unsigned i
+ *         cdef SegmentEvaluator evaluator = SegmentEvaluator()             # <<<<<<<<<<<<<<
+ *         evaluator.metric = metric
+ *         evaluator.scorer = new shared_ptr[mteval.SegmentEvaluator](metric.CreateSegmentEvaluator(refsv[0]))
+ */
+  __pyx_t_1 = PyObject_Call(((PyObject *)((PyObject*)__pyx_ptype_5_cdec_SegmentEvaluator)), ((PyObject *)__pyx_empty_tuple), NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 134; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_1);
+  __pyx_v_evaluator = ((struct __pyx_obj_5_cdec_SegmentEvaluator *)__pyx_t_1);
+  __pyx_t_1 = 0;
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":135
+ *         cdef unsigned i
+ *         cdef SegmentEvaluator evaluator = SegmentEvaluator()
+ *         evaluator.metric = metric             # <<<<<<<<<<<<<<
+ *         evaluator.scorer = new shared_ptr[mteval.SegmentEvaluator](metric.CreateSegmentEvaluator(refsv[0]))
+ *         del refsv # in theory should not delete but store in SegmentEvaluator
+ */
+  __pyx_v_evaluator->metric = __pyx_v_metric;
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":136
+ *         cdef SegmentEvaluator evaluator = SegmentEvaluator()
+ *         evaluator.metric = metric
+ *         evaluator.scorer = new shared_ptr[mteval.SegmentEvaluator](metric.CreateSegmentEvaluator(refsv[0]))             # <<<<<<<<<<<<<<
+ *         del refsv # in theory should not delete but store in SegmentEvaluator
+ *         return evaluator
+ */
+  __pyx_v_evaluator->scorer = new boost::shared_ptr<SegmentEvaluator>(__pyx_v_metric->CreateSegmentEvaluator((__pyx_v_refsv[0])));
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":137
+ *         evaluator.metric = metric
+ *         evaluator.scorer = new shared_ptr[mteval.SegmentEvaluator](metric.CreateSegmentEvaluator(refsv[0]))
+ *         del refsv # in theory should not delete but store in SegmentEvaluator             # <<<<<<<<<<<<<<
+ *         return evaluator
+ * 
+ */
+  delete __pyx_v_refsv;
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":138
+ *         evaluator.scorer = new shared_ptr[mteval.SegmentEvaluator](metric.CreateSegmentEvaluator(refsv[0]))
+ *         del refsv # in theory should not delete but store in SegmentEvaluator
+ *         return evaluator             # <<<<<<<<<<<<<<
+ * 
+ *     def __str__(self):
+ */
+  __Pyx_XDECREF(__pyx_r);
+  __Pyx_INCREF(((PyObject *)__pyx_v_evaluator));
+  __pyx_r = ((PyObject *)__pyx_v_evaluator);
+  goto __pyx_L0;
+
+  __pyx_r = Py_None; __Pyx_INCREF(Py_None);
+  goto __pyx_L0;
+  __pyx_L1_error:;
+  __Pyx_XDECREF(__pyx_t_1);
+  __Pyx_XDECREF(__pyx_t_7);
+  __Pyx_XDECREF(__pyx_t_8);
+  __Pyx_AddTraceback("_cdec.Scorer.__call__", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __pyx_r = NULL;
+  __pyx_L0:;
+  __Pyx_XDECREF(__pyx_v_ref);
+  __Pyx_XDECREF((PyObject *)__pyx_v_evaluator);
+  __Pyx_XDECREF(__pyx_v_refs);
+  __Pyx_XGIVEREF(__pyx_r);
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+/* Python wrapper */
+static PyObject *__pyx_pw_5_cdec_6Scorer_7__str__(PyObject *__pyx_v_self); /*proto*/
+static PyObject *__pyx_pw_5_cdec_6Scorer_7__str__(PyObject *__pyx_v_self) {
+  PyObject *__pyx_r = 0;
+  __Pyx_RefNannyDeclarations
+  __Pyx_RefNannySetupContext("__str__ (wrapper)", 0);
+  __pyx_r = __pyx_pf_5_cdec_6Scorer_6__str__(((struct __pyx_obj_5_cdec_Scorer *)__pyx_v_self));
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+/* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":140
+ *         return evaluator
+ * 
+ *     def __str__(self):             # <<<<<<<<<<<<<<
+ *         return self.name.c_str()
+ * 
+ */
+
+static PyObject *__pyx_pf_5_cdec_6Scorer_6__str__(struct __pyx_obj_5_cdec_Scorer *__pyx_v_self) {
+  PyObject *__pyx_r = NULL;
+  __Pyx_RefNannyDeclarations
+  PyObject *__pyx_t_1 = NULL;
+  int __pyx_lineno = 0;
+  const char *__pyx_filename = NULL;
+  int __pyx_clineno = 0;
+  __Pyx_RefNannySetupContext("__str__", 0);
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":141
+ * 
+ *     def __str__(self):
+ *         return self.name.c_str()             # <<<<<<<<<<<<<<
+ * 
+ * BLEU = Scorer('IBM_BLEU')
+ */
+  __Pyx_XDECREF(__pyx_r);
+  __pyx_t_1 = PyBytes_FromString(__pyx_v_self->name->c_str()); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 141; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(((PyObject *)__pyx_t_1));
+  __pyx_r = ((PyObject *)__pyx_t_1);
+  __pyx_t_1 = 0;
+  goto __pyx_L0;
+
+  __pyx_r = Py_None; __Pyx_INCREF(Py_None);
+  goto __pyx_L0;
+  __pyx_L1_error:;
+  __Pyx_XDECREF(__pyx_t_1);
+  __Pyx_AddTraceback("_cdec.Scorer.__str__", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __pyx_r = NULL;
+  __pyx_L0:;
+  __Pyx_XGIVEREF(__pyx_r);
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+static PyObject *__pyx_gb_5_cdec_4generator16(__pyx_GeneratorObject *__pyx_generator, PyObject *__pyx_sent_value); /* proto */
+
+/* Python wrapper */
+static PyObject *__pyx_pw_5_cdec_3_make_config(PyObject *__pyx_self, PyObject *__pyx_v_config); /*proto*/
+static PyMethodDef __pyx_mdef_5_cdec_3_make_config = {__Pyx_NAMESTR("_make_config"), (PyCFunction)__pyx_pw_5_cdec_3_make_config, METH_O, __Pyx_DOCSTR(0)};
+static PyObject *__pyx_pw_5_cdec_3_make_config(PyObject *__pyx_self, PyObject *__pyx_v_config) {
+  PyObject *__pyx_r = 0;
+  __Pyx_RefNannyDeclarations
+  __Pyx_RefNannySetupContext("_make_config (wrapper)", 0);
+  __pyx_self = __pyx_self;
+  __pyx_r = __pyx_pf_5_cdec_2_make_config(__pyx_self, ((PyObject *)__pyx_v_config));
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+/* "_cdec.pyx":28
+ * class ParseFailed(Exception): pass
+ * 
+ * def _make_config(config):             # <<<<<<<<<<<<<<
+ *     for key, value in config.items():
+ *         if isinstance(value, dict):
+ */
+
+static PyObject *__pyx_pf_5_cdec_2_make_config(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_config) {
+  struct __pyx_obj_5_cdec___pyx_scope_struct_22__make_config *__pyx_cur_scope;
+  PyObject *__pyx_r = NULL;
+  __Pyx_RefNannyDeclarations
+  int __pyx_lineno = 0;
+  const char *__pyx_filename = NULL;
+  int __pyx_clineno = 0;
+  __Pyx_RefNannySetupContext("_make_config", 0);
+  __pyx_cur_scope = (struct __pyx_obj_5_cdec___pyx_scope_struct_22__make_config *)__pyx_ptype_5_cdec___pyx_scope_struct_22__make_config->tp_new(__pyx_ptype_5_cdec___pyx_scope_struct_22__make_config, __pyx_empty_tuple, NULL);
+  if (unlikely(!__pyx_cur_scope)) {
+    __Pyx_RefNannyFinishContext();
+    return NULL;
+  }
+  __Pyx_GOTREF(__pyx_cur_scope);
+  __pyx_cur_scope->__pyx_v_config = __pyx_v_config;
+  __Pyx_INCREF(__pyx_cur_scope->__pyx_v_config);
+  __Pyx_GIVEREF(__pyx_cur_scope->__pyx_v_config);
+  {
+    __pyx_GeneratorObject *gen = __Pyx_Generator_New((__pyx_generator_body_t) __pyx_gb_5_cdec_4generator16, (PyObject *) __pyx_cur_scope); if (unlikely(!gen)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 28; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_DECREF(__pyx_cur_scope);
+    __Pyx_RefNannyFinishContext();
+    return (PyObject *) gen;
+  }
+
+  __pyx_r = Py_None; __Pyx_INCREF(Py_None);
+  goto __pyx_L0;
+  __pyx_L1_error:;
+  __Pyx_AddTraceback("_cdec._make_config", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __pyx_r = NULL;
+  __pyx_L0:;
+  __Pyx_DECREF(((PyObject *)__pyx_cur_scope));
+  __Pyx_XGIVEREF(__pyx_r);
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+static PyObject *__pyx_gb_5_cdec_4generator16(__pyx_GeneratorObject *__pyx_generator, PyObject *__pyx_sent_value) /* generator body */
+{
+  struct __pyx_obj_5_cdec___pyx_scope_struct_22__make_config *__pyx_cur_scope = ((struct __pyx_obj_5_cdec___pyx_scope_struct_22__make_config *)__pyx_generator->closure);
+  PyObject *__pyx_r = NULL;
+  PyObject *__pyx_t_1 = NULL;
+  PyObject *__pyx_t_2 = NULL;
+  Py_ssize_t __pyx_t_3;
+  PyObject *(*__pyx_t_4)(PyObject *);
+  PyObject *__pyx_t_5 = NULL;
+  PyObject *__pyx_t_6 = NULL;
+  PyObject *__pyx_t_7 = NULL;
+  PyObject *(*__pyx_t_8)(PyObject *);
+  int __pyx_t_9;
+  Py_ssize_t __pyx_t_10;
+  PyObject *(*__pyx_t_11)(PyObject *);
+  PyObject *__pyx_t_12 = NULL;
+  __Pyx_RefNannyDeclarations
+  __Pyx_RefNannySetupContext("None", 0);
+  switch (__pyx_generator->resume_label) {
+    case 0: goto __pyx_L3_first_run;
+    case 1: goto __pyx_L13_resume_from_yield;
+    case 2: goto __pyx_L16_resume_from_yield;
+    case 3: goto __pyx_L17_resume_from_yield;
+    default: /* CPython raises the right error here */
+    __Pyx_RefNannyFinishContext();
+    return NULL;
+  }
+  __pyx_L3_first_run:;
+  if (unlikely(!__pyx_sent_value)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 28; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+
+  /* "_cdec.pyx":29
+ * 
+ * def _make_config(config):
+ *     for key, value in config.items():             # <<<<<<<<<<<<<<
+ *         if isinstance(value, dict):
+ *             for name, info in value.items():
+ */
+  __pyx_t_1 = PyObject_GetAttr(__pyx_cur_scope->__pyx_v_config, __pyx_n_s__items); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 29; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_1);
+  __pyx_t_2 = PyObject_Call(__pyx_t_1, ((PyObject *)__pyx_empty_tuple), NULL); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 29; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_2);
+  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+  if (PyList_CheckExact(__pyx_t_2) || PyTuple_CheckExact(__pyx_t_2)) {
+    __pyx_t_1 = __pyx_t_2; __Pyx_INCREF(__pyx_t_1); __pyx_t_3 = 0;
+    __pyx_t_4 = NULL;
+  } else {
+    __pyx_t_3 = -1; __pyx_t_1 = PyObject_GetIter(__pyx_t_2); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 29; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_1);
+    __pyx_t_4 = Py_TYPE(__pyx_t_1)->tp_iternext;
+  }
+  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+  for (;;) {
+    if (!__pyx_t_4 && PyList_CheckExact(__pyx_t_1)) {
+      if (__pyx_t_3 >= PyList_GET_SIZE(__pyx_t_1)) break;
+      __pyx_t_2 = PyList_GET_ITEM(__pyx_t_1, __pyx_t_3); __Pyx_INCREF(__pyx_t_2); __pyx_t_3++;
+    } else if (!__pyx_t_4 && PyTuple_CheckExact(__pyx_t_1)) {
+      if (__pyx_t_3 >= PyTuple_GET_SIZE(__pyx_t_1)) break;
+      __pyx_t_2 = PyTuple_GET_ITEM(__pyx_t_1, __pyx_t_3); __Pyx_INCREF(__pyx_t_2); __pyx_t_3++;
+    } else {
+      __pyx_t_2 = __pyx_t_4(__pyx_t_1);
+      if (unlikely(!__pyx_t_2)) {
+        if (PyErr_Occurred()) {
+          if (likely(PyErr_ExceptionMatches(PyExc_StopIteration))) PyErr_Clear();
+          else {__pyx_filename = __pyx_f[0]; __pyx_lineno = 29; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+        }
+        break;
+      }
+      __Pyx_GOTREF(__pyx_t_2);
+    }
+    if ((likely(PyTuple_CheckExact(__pyx_t_2))) || (PyList_CheckExact(__pyx_t_2))) {
+      PyObject* sequence = __pyx_t_2;
+      if (likely(PyTuple_CheckExact(sequence))) {
+        if (unlikely(PyTuple_GET_SIZE(sequence) != 2)) {
+          if (PyTuple_GET_SIZE(sequence) > 2) __Pyx_RaiseTooManyValuesError(2);
+          else __Pyx_RaiseNeedMoreValuesError(PyTuple_GET_SIZE(sequence));
+          {__pyx_filename = __pyx_f[0]; __pyx_lineno = 29; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+        }
+        __pyx_t_5 = PyTuple_GET_ITEM(sequence, 0); 
+        __pyx_t_6 = PyTuple_GET_ITEM(sequence, 1); 
+      } else {
+        if (unlikely(PyList_GET_SIZE(sequence) != 2)) {
+          if (PyList_GET_SIZE(sequence) > 2) __Pyx_RaiseTooManyValuesError(2);
+          else __Pyx_RaiseNeedMoreValuesError(PyList_GET_SIZE(sequence));
+          {__pyx_filename = __pyx_f[0]; __pyx_lineno = 29; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+        }
+        __pyx_t_5 = PyList_GET_ITEM(sequence, 0); 
+        __pyx_t_6 = PyList_GET_ITEM(sequence, 1); 
+      }
+      __Pyx_INCREF(__pyx_t_5);
+      __Pyx_INCREF(__pyx_t_6);
+      __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+    } else {
+      Py_ssize_t index = -1;
+      __pyx_t_7 = PyObject_GetIter(__pyx_t_2); if (unlikely(!__pyx_t_7)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 29; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __Pyx_GOTREF(__pyx_t_7);
+      __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+      __pyx_t_8 = Py_TYPE(__pyx_t_7)->tp_iternext;
+      index = 0; __pyx_t_5 = __pyx_t_8(__pyx_t_7); if (unlikely(!__pyx_t_5)) goto __pyx_L6_unpacking_failed;
+      __Pyx_GOTREF(__pyx_t_5);
+      index = 1; __pyx_t_6 = __pyx_t_8(__pyx_t_7); if (unlikely(!__pyx_t_6)) goto __pyx_L6_unpacking_failed;
+      __Pyx_GOTREF(__pyx_t_6);
+      if (__Pyx_IternextUnpackEndCheck(__pyx_t_8(__pyx_t_7), 2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 29; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;
+      goto __pyx_L7_unpacking_done;
+      __pyx_L6_unpacking_failed:;
+      __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;
+      if (PyErr_Occurred() && PyErr_ExceptionMatches(PyExc_StopIteration)) PyErr_Clear();
+      if (!PyErr_Occurred()) __Pyx_RaiseNeedMoreValuesError(index);
+      {__pyx_filename = __pyx_f[0]; __pyx_lineno = 29; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __pyx_L7_unpacking_done:;
+    }
+    __Pyx_XGOTREF(__pyx_cur_scope->__pyx_v_key);
+    __Pyx_XDECREF(__pyx_cur_scope->__pyx_v_key);
+    __Pyx_GIVEREF(__pyx_t_5);
+    __pyx_cur_scope->__pyx_v_key = __pyx_t_5;
+    __pyx_t_5 = 0;
+    __Pyx_XGOTREF(__pyx_cur_scope->__pyx_v_value);
+    __Pyx_XDECREF(__pyx_cur_scope->__pyx_v_value);
+    __Pyx_GIVEREF(__pyx_t_6);
+    __pyx_cur_scope->__pyx_v_value = __pyx_t_6;
+    __pyx_t_6 = 0;
+
+    /* "_cdec.pyx":30
+ * def _make_config(config):
+ *     for key, value in config.items():
+ *         if isinstance(value, dict):             # <<<<<<<<<<<<<<
+ *             for name, info in value.items():
+ *                 yield key, '%s %s' % (name, info)
+ */
+    __pyx_t_2 = ((PyObject *)((PyObject*)(&PyDict_Type)));
+    __Pyx_INCREF(__pyx_t_2);
+    __pyx_t_9 = __Pyx_TypeCheck(__pyx_cur_scope->__pyx_v_value, __pyx_t_2); 
+    __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+    if (__pyx_t_9) {
+
+      /* "_cdec.pyx":31
+ *     for key, value in config.items():
+ *         if isinstance(value, dict):
+ *             for name, info in value.items():             # <<<<<<<<<<<<<<
+ *                 yield key, '%s %s' % (name, info)
+ *         elif isinstance(value, list):
+ */
+      __pyx_t_2 = PyObject_GetAttr(__pyx_cur_scope->__pyx_v_value, __pyx_n_s__items); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 31; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __Pyx_GOTREF(__pyx_t_2);
+      __pyx_t_6 = PyObject_Call(__pyx_t_2, ((PyObject *)__pyx_empty_tuple), NULL); if (unlikely(!__pyx_t_6)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 31; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __Pyx_GOTREF(__pyx_t_6);
+      __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+      if (PyList_CheckExact(__pyx_t_6) || PyTuple_CheckExact(__pyx_t_6)) {
+        __pyx_t_2 = __pyx_t_6; __Pyx_INCREF(__pyx_t_2); __pyx_t_10 = 0;
+        __pyx_t_11 = NULL;
+      } else {
+        __pyx_t_10 = -1; __pyx_t_2 = PyObject_GetIter(__pyx_t_6); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 31; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+        __Pyx_GOTREF(__pyx_t_2);
+        __pyx_t_11 = Py_TYPE(__pyx_t_2)->tp_iternext;
+      }
+      __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0;
+      for (;;) {
+        if (!__pyx_t_11 && PyList_CheckExact(__pyx_t_2)) {
+          if (__pyx_t_10 >= PyList_GET_SIZE(__pyx_t_2)) break;
+          __pyx_t_6 = PyList_GET_ITEM(__pyx_t_2, __pyx_t_10); __Pyx_INCREF(__pyx_t_6); __pyx_t_10++;
+        } else if (!__pyx_t_11 && PyTuple_CheckExact(__pyx_t_2)) {
+          if (__pyx_t_10 >= PyTuple_GET_SIZE(__pyx_t_2)) break;
+          __pyx_t_6 = PyTuple_GET_ITEM(__pyx_t_2, __pyx_t_10); __Pyx_INCREF(__pyx_t_6); __pyx_t_10++;
+        } else {
+          __pyx_t_6 = __pyx_t_11(__pyx_t_2);
+          if (unlikely(!__pyx_t_6)) {
+            if (PyErr_Occurred()) {
+              if (likely(PyErr_ExceptionMatches(PyExc_StopIteration))) PyErr_Clear();
+              else {__pyx_filename = __pyx_f[0]; __pyx_lineno = 31; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+            }
+            break;
+          }
+          __Pyx_GOTREF(__pyx_t_6);
+        }
+        if ((likely(PyTuple_CheckExact(__pyx_t_6))) || (PyList_CheckExact(__pyx_t_6))) {
+          PyObject* sequence = __pyx_t_6;
+          if (likely(PyTuple_CheckExact(sequence))) {
+            if (unlikely(PyTuple_GET_SIZE(sequence) != 2)) {
+              if (PyTuple_GET_SIZE(sequence) > 2) __Pyx_RaiseTooManyValuesError(2);
+              else __Pyx_RaiseNeedMoreValuesError(PyTuple_GET_SIZE(sequence));
+              {__pyx_filename = __pyx_f[0]; __pyx_lineno = 31; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+            }
+            __pyx_t_5 = PyTuple_GET_ITEM(sequence, 0); 
+            __pyx_t_7 = PyTuple_GET_ITEM(sequence, 1); 
+          } else {
+            if (unlikely(PyList_GET_SIZE(sequence) != 2)) {
+              if (PyList_GET_SIZE(sequence) > 2) __Pyx_RaiseTooManyValuesError(2);
+              else __Pyx_RaiseNeedMoreValuesError(PyList_GET_SIZE(sequence));
+              {__pyx_filename = __pyx_f[0]; __pyx_lineno = 31; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+            }
+            __pyx_t_5 = PyList_GET_ITEM(sequence, 0); 
+            __pyx_t_7 = PyList_GET_ITEM(sequence, 1); 
+          }
+          __Pyx_INCREF(__pyx_t_5);
+          __Pyx_INCREF(__pyx_t_7);
+          __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0;
+        } else {
+          Py_ssize_t index = -1;
+          __pyx_t_12 = PyObject_GetIter(__pyx_t_6); if (unlikely(!__pyx_t_12)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 31; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+          __Pyx_GOTREF(__pyx_t_12);
+          __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0;
+          __pyx_t_8 = Py_TYPE(__pyx_t_12)->tp_iternext;
+          index = 0; __pyx_t_5 = __pyx_t_8(__pyx_t_12); if (unlikely(!__pyx_t_5)) goto __pyx_L11_unpacking_failed;
+          __Pyx_GOTREF(__pyx_t_5);
+          index = 1; __pyx_t_7 = __pyx_t_8(__pyx_t_12); if (unlikely(!__pyx_t_7)) goto __pyx_L11_unpacking_failed;
+          __Pyx_GOTREF(__pyx_t_7);
+          if (__Pyx_IternextUnpackEndCheck(__pyx_t_8(__pyx_t_12), 2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 31; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+          __Pyx_DECREF(__pyx_t_12); __pyx_t_12 = 0;
+          goto __pyx_L12_unpacking_done;
+          __pyx_L11_unpacking_failed:;
+          __Pyx_DECREF(__pyx_t_12); __pyx_t_12 = 0;
+          if (PyErr_Occurred() && PyErr_ExceptionMatches(PyExc_StopIteration)) PyErr_Clear();
+          if (!PyErr_Occurred()) __Pyx_RaiseNeedMoreValuesError(index);
+          {__pyx_filename = __pyx_f[0]; __pyx_lineno = 31; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+          __pyx_L12_unpacking_done:;
+        }
+        __Pyx_XGOTREF(__pyx_cur_scope->__pyx_v_name);
+        __Pyx_XDECREF(__pyx_cur_scope->__pyx_v_name);
+        __Pyx_GIVEREF(__pyx_t_5);
+        __pyx_cur_scope->__pyx_v_name = __pyx_t_5;
+        __pyx_t_5 = 0;
+        __Pyx_XGOTREF(__pyx_cur_scope->__pyx_v_info);
+        __Pyx_XDECREF(__pyx_cur_scope->__pyx_v_info);
+        __Pyx_GIVEREF(__pyx_t_7);
+        __pyx_cur_scope->__pyx_v_info = __pyx_t_7;
+        __pyx_t_7 = 0;
+
+        /* "_cdec.pyx":32
+ *         if isinstance(value, dict):
+ *             for name, info in value.items():
+ *                 yield key, '%s %s' % (name, info)             # <<<<<<<<<<<<<<
+ *         elif isinstance(value, list):
+ *             for name in value:
+ */
+        __pyx_t_6 = PyTuple_New(2); if (unlikely(!__pyx_t_6)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 32; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+        __Pyx_GOTREF(__pyx_t_6);
+        __Pyx_INCREF(__pyx_cur_scope->__pyx_v_name);
+        PyTuple_SET_ITEM(__pyx_t_6, 0, __pyx_cur_scope->__pyx_v_name);
+        __Pyx_GIVEREF(__pyx_cur_scope->__pyx_v_name);
+        __Pyx_INCREF(__pyx_cur_scope->__pyx_v_info);
+        PyTuple_SET_ITEM(__pyx_t_6, 1, __pyx_cur_scope->__pyx_v_info);
+        __Pyx_GIVEREF(__pyx_cur_scope->__pyx_v_info);
+        __pyx_t_7 = PyNumber_Remainder(((PyObject *)__pyx_kp_s_43), ((PyObject *)__pyx_t_6)); if (unlikely(!__pyx_t_7)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 32; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+        __Pyx_GOTREF(((PyObject *)__pyx_t_7));
+        __Pyx_DECREF(((PyObject *)__pyx_t_6)); __pyx_t_6 = 0;
+        __pyx_t_6 = PyTuple_New(2); if (unlikely(!__pyx_t_6)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 32; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+        __Pyx_GOTREF(__pyx_t_6);
+        __Pyx_INCREF(__pyx_cur_scope->__pyx_v_key);
+        PyTuple_SET_ITEM(__pyx_t_6, 0, __pyx_cur_scope->__pyx_v_key);
+        __Pyx_GIVEREF(__pyx_cur_scope->__pyx_v_key);
+        PyTuple_SET_ITEM(__pyx_t_6, 1, ((PyObject *)__pyx_t_7));
+        __Pyx_GIVEREF(((PyObject *)__pyx_t_7));
+        __pyx_t_7 = 0;
+        __pyx_r = ((PyObject *)__pyx_t_6);
+        __pyx_t_6 = 0;
+        __Pyx_XGIVEREF(__pyx_t_1);
+        __pyx_cur_scope->__pyx_t_0 = __pyx_t_1;
+        __Pyx_XGIVEREF(__pyx_t_2);
+        __pyx_cur_scope->__pyx_t_1 = __pyx_t_2;
+        __pyx_cur_scope->__pyx_t_2 = __pyx_t_3;
+        __pyx_cur_scope->__pyx_t_3 = __pyx_t_4;
+        __pyx_cur_scope->__pyx_t_4 = __pyx_t_10;
+        __pyx_cur_scope->__pyx_t_5 = __pyx_t_11;
+        __Pyx_XGIVEREF(__pyx_r);
+        __Pyx_RefNannyFinishContext();
+        /* return from generator, yielding value */
+        __pyx_generator->resume_label = 1;
+        return __pyx_r;
+        __pyx_L13_resume_from_yield:;
+        __pyx_t_1 = __pyx_cur_scope->__pyx_t_0;
+        __pyx_cur_scope->__pyx_t_0 = 0;
+        __Pyx_XGOTREF(__pyx_t_1);
+        __pyx_t_2 = __pyx_cur_scope->__pyx_t_1;
+        __pyx_cur_scope->__pyx_t_1 = 0;
+        __Pyx_XGOTREF(__pyx_t_2);
+        __pyx_t_3 = __pyx_cur_scope->__pyx_t_2;
+        __pyx_t_4 = __pyx_cur_scope->__pyx_t_3;
+        __pyx_t_10 = __pyx_cur_scope->__pyx_t_4;
+        __pyx_t_11 = __pyx_cur_scope->__pyx_t_5;
+        if (unlikely(!__pyx_sent_value)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 32; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      }
+      __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+      goto __pyx_L8;
+    }
+
+    /* "_cdec.pyx":33
+ *             for name, info in value.items():
+ *                 yield key, '%s %s' % (name, info)
+ *         elif isinstance(value, list):             # <<<<<<<<<<<<<<
+ *             for name in value:
+ *                 yield key, name
+ */
+    __pyx_t_2 = ((PyObject *)((PyObject*)(&PyList_Type)));
+    __Pyx_INCREF(__pyx_t_2);
+    __pyx_t_9 = __Pyx_TypeCheck(__pyx_cur_scope->__pyx_v_value, __pyx_t_2); 
+    __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+    if (__pyx_t_9) {
+
+      /* "_cdec.pyx":34
+ *                 yield key, '%s %s' % (name, info)
+ *         elif isinstance(value, list):
+ *             for name in value:             # <<<<<<<<<<<<<<
+ *                 yield key, name
+ *         else:
+ */
+      if (PyList_CheckExact(__pyx_cur_scope->__pyx_v_value) || PyTuple_CheckExact(__pyx_cur_scope->__pyx_v_value)) {
+        __pyx_t_2 = __pyx_cur_scope->__pyx_v_value; __Pyx_INCREF(__pyx_t_2); __pyx_t_10 = 0;
+        __pyx_t_11 = NULL;
+      } else {
+        __pyx_t_10 = -1; __pyx_t_2 = PyObject_GetIter(__pyx_cur_scope->__pyx_v_value); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 34; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+        __Pyx_GOTREF(__pyx_t_2);
+        __pyx_t_11 = Py_TYPE(__pyx_t_2)->tp_iternext;
+      }
+      for (;;) {
+        if (!__pyx_t_11 && PyList_CheckExact(__pyx_t_2)) {
+          if (__pyx_t_10 >= PyList_GET_SIZE(__pyx_t_2)) break;
+          __pyx_t_6 = PyList_GET_ITEM(__pyx_t_2, __pyx_t_10); __Pyx_INCREF(__pyx_t_6); __pyx_t_10++;
+        } else if (!__pyx_t_11 && PyTuple_CheckExact(__pyx_t_2)) {
+          if (__pyx_t_10 >= PyTuple_GET_SIZE(__pyx_t_2)) break;
+          __pyx_t_6 = PyTuple_GET_ITEM(__pyx_t_2, __pyx_t_10); __Pyx_INCREF(__pyx_t_6); __pyx_t_10++;
+        } else {
+          __pyx_t_6 = __pyx_t_11(__pyx_t_2);
+          if (unlikely(!__pyx_t_6)) {
+            if (PyErr_Occurred()) {
+              if (likely(PyErr_ExceptionMatches(PyExc_StopIteration))) PyErr_Clear();
+              else {__pyx_filename = __pyx_f[0]; __pyx_lineno = 34; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+            }
+            break;
+          }
+          __Pyx_GOTREF(__pyx_t_6);
+        }
+        __Pyx_XGOTREF(__pyx_cur_scope->__pyx_v_name);
+        __Pyx_XDECREF(__pyx_cur_scope->__pyx_v_name);
+        __Pyx_GIVEREF(__pyx_t_6);
+        __pyx_cur_scope->__pyx_v_name = __pyx_t_6;
+        __pyx_t_6 = 0;
+
+        /* "_cdec.pyx":35
+ *         elif isinstance(value, list):
+ *             for name in value:
+ *                 yield key, name             # <<<<<<<<<<<<<<
+ *         else:
+ *             yield key, bytes(value)
+ */
+        __pyx_t_6 = PyTuple_New(2); if (unlikely(!__pyx_t_6)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 35; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+        __Pyx_GOTREF(__pyx_t_6);
+        __Pyx_INCREF(__pyx_cur_scope->__pyx_v_key);
+        PyTuple_SET_ITEM(__pyx_t_6, 0, __pyx_cur_scope->__pyx_v_key);
+        __Pyx_GIVEREF(__pyx_cur_scope->__pyx_v_key);
+        __Pyx_INCREF(__pyx_cur_scope->__pyx_v_name);
+        PyTuple_SET_ITEM(__pyx_t_6, 1, __pyx_cur_scope->__pyx_v_name);
+        __Pyx_GIVEREF(__pyx_cur_scope->__pyx_v_name);
+        __pyx_r = ((PyObject *)__pyx_t_6);
+        __pyx_t_6 = 0;
+        __Pyx_XGIVEREF(__pyx_t_1);
+        __pyx_cur_scope->__pyx_t_0 = __pyx_t_1;
+        __Pyx_XGIVEREF(__pyx_t_2);
+        __pyx_cur_scope->__pyx_t_1 = __pyx_t_2;
+        __pyx_cur_scope->__pyx_t_2 = __pyx_t_3;
+        __pyx_cur_scope->__pyx_t_3 = __pyx_t_4;
+        __pyx_cur_scope->__pyx_t_4 = __pyx_t_10;
+        __pyx_cur_scope->__pyx_t_5 = __pyx_t_11;
+        __Pyx_XGIVEREF(__pyx_r);
+        __Pyx_RefNannyFinishContext();
+        /* return from generator, yielding value */
+        __pyx_generator->resume_label = 2;
+        return __pyx_r;
+        __pyx_L16_resume_from_yield:;
+        __pyx_t_1 = __pyx_cur_scope->__pyx_t_0;
+        __pyx_cur_scope->__pyx_t_0 = 0;
+        __Pyx_XGOTREF(__pyx_t_1);
+        __pyx_t_2 = __pyx_cur_scope->__pyx_t_1;
+        __pyx_cur_scope->__pyx_t_1 = 0;
+        __Pyx_XGOTREF(__pyx_t_2);
+        __pyx_t_3 = __pyx_cur_scope->__pyx_t_2;
+        __pyx_t_4 = __pyx_cur_scope->__pyx_t_3;
+        __pyx_t_10 = __pyx_cur_scope->__pyx_t_4;
+        __pyx_t_11 = __pyx_cur_scope->__pyx_t_5;
+        if (unlikely(!__pyx_sent_value)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 35; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      }
+      __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+      goto __pyx_L8;
+    }
+    /*else*/ {
+
+      /* "_cdec.pyx":37
+ *                 yield key, name
+ *         else:
+ *             yield key, bytes(value)             # <<<<<<<<<<<<<<
+ * 
+ * cdef class Decoder:
+ */
+      __pyx_t_2 = PyTuple_New(1); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 37; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __Pyx_GOTREF(__pyx_t_2);
+      __Pyx_INCREF(__pyx_cur_scope->__pyx_v_value);
+      PyTuple_SET_ITEM(__pyx_t_2, 0, __pyx_cur_scope->__pyx_v_value);
+      __Pyx_GIVEREF(__pyx_cur_scope->__pyx_v_value);
+      __pyx_t_6 = PyObject_Call(((PyObject *)((PyObject*)(&PyBytes_Type))), ((PyObject *)__pyx_t_2), NULL); if (unlikely(!__pyx_t_6)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 37; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __Pyx_GOTREF(__pyx_t_6);
+      __Pyx_DECREF(((PyObject *)__pyx_t_2)); __pyx_t_2 = 0;
+      __pyx_t_2 = PyTuple_New(2); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 37; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __Pyx_GOTREF(__pyx_t_2);
+      __Pyx_INCREF(__pyx_cur_scope->__pyx_v_key);
+      PyTuple_SET_ITEM(__pyx_t_2, 0, __pyx_cur_scope->__pyx_v_key);
+      __Pyx_GIVEREF(__pyx_cur_scope->__pyx_v_key);
+      PyTuple_SET_ITEM(__pyx_t_2, 1, __pyx_t_6);
+      __Pyx_GIVEREF(__pyx_t_6);
+      __pyx_t_6 = 0;
+      __pyx_r = ((PyObject *)__pyx_t_2);
+      __pyx_t_2 = 0;
+      __Pyx_XGIVEREF(__pyx_t_1);
+      __pyx_cur_scope->__pyx_t_0 = __pyx_t_1;
+      __pyx_cur_scope->__pyx_t_2 = __pyx_t_3;
+      __pyx_cur_scope->__pyx_t_3 = __pyx_t_4;
+      __Pyx_XGIVEREF(__pyx_r);
+      __Pyx_RefNannyFinishContext();
+      /* return from generator, yielding value */
+      __pyx_generator->resume_label = 3;
+      return __pyx_r;
+      __pyx_L17_resume_from_yield:;
+      __pyx_t_1 = __pyx_cur_scope->__pyx_t_0;
+      __pyx_cur_scope->__pyx_t_0 = 0;
+      __Pyx_XGOTREF(__pyx_t_1);
+      __pyx_t_3 = __pyx_cur_scope->__pyx_t_2;
+      __pyx_t_4 = __pyx_cur_scope->__pyx_t_3;
+      if (unlikely(!__pyx_sent_value)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 37; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    }
+    __pyx_L8:;
+  }
+  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+  PyErr_SetNone(PyExc_StopIteration);
+  goto __pyx_L0;
+  __pyx_L1_error:;
+  __Pyx_XDECREF(__pyx_t_1);
+  __Pyx_XDECREF(__pyx_t_2);
+  __Pyx_XDECREF(__pyx_t_5);
+  __Pyx_XDECREF(__pyx_t_6);
+  __Pyx_XDECREF(__pyx_t_7);
+  __Pyx_XDECREF(__pyx_t_12);
+  __Pyx_AddTraceback("_make_config", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __pyx_L0:;
+  __Pyx_XDECREF(__pyx_r);
+  __pyx_generator->resume_label = -1;
+  __Pyx_RefNannyFinishContext();
+  return NULL;
+}
+
+/* Python wrapper */
+static int __pyx_pw_5_cdec_7Decoder_1__cinit__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/
+static int __pyx_pw_5_cdec_7Decoder_1__cinit__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) {
+  PyObject *__pyx_v_config_str = 0;
+  PyObject *__pyx_v_config = 0;
+  static PyObject **__pyx_pyargnames[] = {&__pyx_n_s__config_str,0};
+  int __pyx_r;
+  __Pyx_RefNannyDeclarations
+  __Pyx_RefNannySetupContext("__cinit__ (wrapper)", 0);
+  __pyx_v_config = PyDict_New(); if (unlikely(!__pyx_v_config)) return -1;
+  __Pyx_GOTREF(__pyx_v_config);
+  {
+    PyObject* values[1] = {0};
+
+    /* "_cdec.pyx":43
+ *     cdef DenseVector weights
+ * 
+ *     def __cinit__(self, config_str=None, **config):             # <<<<<<<<<<<<<<
+ *         """ Configuration can be given as a string:
+ *                 Decoder('formalism = scfg')
+ */
+    values[0] = ((PyObject *)Py_None);
+    if (unlikely(__pyx_kwds)) {
+      Py_ssize_t kw_args;
+      const Py_ssize_t pos_args = PyTuple_GET_SIZE(__pyx_args);
+      switch (pos_args) {
+        case  1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0);
+        case  0: break;
+        default: goto __pyx_L5_argtuple_error;
+      }
+      kw_args = PyDict_Size(__pyx_kwds);
+      switch (pos_args) {
+        case  0:
+        if (kw_args > 0) {
+          PyObject* value = PyDict_GetItem(__pyx_kwds, __pyx_n_s__config_str);
+          if (value) { values[0] = value; kw_args--; }
+        }
+      }
+      if (unlikely(kw_args > 0)) {
+        if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, __pyx_v_config, values, pos_args, "__cinit__") < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 43; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+      }
+    } else {
+      switch (PyTuple_GET_SIZE(__pyx_args)) {
+        case  1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0);
+        case  0: break;
+        default: goto __pyx_L5_argtuple_error;
+      }
+    }
+    __pyx_v_config_str = values[0];
+  }
+  goto __pyx_L4_argument_unpacking_done;
+  __pyx_L5_argtuple_error:;
+  __Pyx_RaiseArgtupleInvalid("__cinit__", 0, 0, 1, PyTuple_GET_SIZE(__pyx_args)); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 43; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+  __pyx_L3_error:;
+  __Pyx_CLEAR(__pyx_v_config);
+  __Pyx_AddTraceback("_cdec.Decoder.__cinit__", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __Pyx_RefNannyFinishContext();
+  return -1;
+  __pyx_L4_argument_unpacking_done:;
+  __pyx_r = __pyx_pf_5_cdec_7Decoder___cinit__(((struct __pyx_obj_5_cdec_Decoder *)__pyx_v_self), __pyx_v_config_str, __pyx_v_config);
+  __Pyx_XDECREF(__pyx_v_config);
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+static PyObject *__pyx_gb_5_cdec_7Decoder_9__cinit___2generator20(__pyx_GeneratorObject *__pyx_generator, PyObject *__pyx_sent_value); /* proto */
+
+/* "_cdec.pyx":54
+ *                     'csplit', 'tagger', 'lexalign'):
+ *                 raise InvalidConfig('formalism "%s" unknown' % formalism)
+ *             config_str = '\n'.join('%s = %s' % kv for kv in _make_config(config))             # <<<<<<<<<<<<<<
+ *         cdef istringstream* config_stream = new istringstream(config_str)
+ *         self.dec = new decoder.Decoder(config_stream)
+ */
+
+static PyObject *__pyx_pf_5_cdec_7Decoder_9__cinit___genexpr(PyObject *__pyx_self) {
+  struct __pyx_obj_5_cdec___pyx_scope_struct_24_genexpr *__pyx_cur_scope;
+  PyObject *__pyx_r = NULL;
+  __Pyx_RefNannyDeclarations
+  int __pyx_lineno = 0;
+  const char *__pyx_filename = NULL;
+  int __pyx_clineno = 0;
+  __Pyx_RefNannySetupContext("genexpr", 0);
+  __pyx_cur_scope = (struct __pyx_obj_5_cdec___pyx_scope_struct_24_genexpr *)__pyx_ptype_5_cdec___pyx_scope_struct_24_genexpr->tp_new(__pyx_ptype_5_cdec___pyx_scope_struct_24_genexpr, __pyx_empty_tuple, NULL);
+  if (unlikely(!__pyx_cur_scope)) {
+    __Pyx_RefNannyFinishContext();
+    return NULL;
+  }
+  __Pyx_GOTREF(__pyx_cur_scope);
+  __pyx_cur_scope->__pyx_outer_scope = (struct __pyx_obj_5_cdec___pyx_scope_struct_23___cinit__ *) __pyx_self;
+  __Pyx_INCREF(((PyObject *)__pyx_cur_scope->__pyx_outer_scope));
+  __Pyx_GIVEREF(__pyx_cur_scope->__pyx_outer_scope);
+  {
+    __pyx_GeneratorObject *gen = __Pyx_Generator_New((__pyx_generator_body_t) __pyx_gb_5_cdec_7Decoder_9__cinit___2generator20, (PyObject *) __pyx_cur_scope); if (unlikely(!gen)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 54; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_DECREF(__pyx_cur_scope);
+    __Pyx_RefNannyFinishContext();
+    return (PyObject *) gen;
+  }
+
+  __pyx_r = Py_None; __Pyx_INCREF(Py_None);
+  goto __pyx_L0;
+  __pyx_L1_error:;
+  __Pyx_AddTraceback("_cdec.Decoder.__cinit__.genexpr", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __pyx_r = NULL;
+  __pyx_L0:;
+  __Pyx_DECREF(((PyObject *)__pyx_cur_scope));
+  __Pyx_XGIVEREF(__pyx_r);
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+static PyObject *__pyx_gb_5_cdec_7Decoder_9__cinit___2generator20(__pyx_GeneratorObject *__pyx_generator, PyObject *__pyx_sent_value) /* generator body */
+{
+  struct __pyx_obj_5_cdec___pyx_scope_struct_24_genexpr *__pyx_cur_scope = ((struct __pyx_obj_5_cdec___pyx_scope_struct_24_genexpr *)__pyx_generator->closure);
+  PyObject *__pyx_r = NULL;
+  PyObject *__pyx_t_1 = NULL;
+  PyObject *__pyx_t_2 = NULL;
+  PyObject *__pyx_t_3 = NULL;
+  Py_ssize_t __pyx_t_4;
+  PyObject *(*__pyx_t_5)(PyObject *);
+  __Pyx_RefNannyDeclarations
+  __Pyx_RefNannySetupContext("None", 0);
+  switch (__pyx_generator->resume_label) {
+    case 0: goto __pyx_L3_first_run;
+    case 1: goto __pyx_L6_resume_from_yield;
+    default: /* CPython raises the right error here */
+    __Pyx_RefNannyFinishContext();
+    return NULL;
+  }
+  __pyx_L3_first_run:;
+  if (unlikely(!__pyx_sent_value)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 54; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_1 = __Pyx_GetName(__pyx_m, __pyx_n_s___make_config); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 54; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_1);
+  if (unlikely(!__pyx_cur_scope->__pyx_outer_scope->__pyx_v_config)) { __Pyx_RaiseClosureNameError("config"); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 54; __pyx_clineno = __LINE__; goto __pyx_L1_error;} }
+  __pyx_t_2 = PyTuple_New(1); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 54; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_2);
+  __Pyx_INCREF(__pyx_cur_scope->__pyx_outer_scope->__pyx_v_config);
+  PyTuple_SET_ITEM(__pyx_t_2, 0, __pyx_cur_scope->__pyx_outer_scope->__pyx_v_config);
+  __Pyx_GIVEREF(__pyx_cur_scope->__pyx_outer_scope->__pyx_v_config);
+  __pyx_t_3 = PyObject_Call(__pyx_t_1, ((PyObject *)__pyx_t_2), NULL); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 54; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_3);
+  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+  __Pyx_DECREF(((PyObject *)__pyx_t_2)); __pyx_t_2 = 0;
+  if (PyList_CheckExact(__pyx_t_3) || PyTuple_CheckExact(__pyx_t_3)) {
+    __pyx_t_2 = __pyx_t_3; __Pyx_INCREF(__pyx_t_2); __pyx_t_4 = 0;
+    __pyx_t_5 = NULL;
+  } else {
+    __pyx_t_4 = -1; __pyx_t_2 = PyObject_GetIter(__pyx_t_3); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 54; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_2);
+    __pyx_t_5 = Py_TYPE(__pyx_t_2)->tp_iternext;
+  }
+  __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
+  for (;;) {
+    if (!__pyx_t_5 && PyList_CheckExact(__pyx_t_2)) {
+      if (__pyx_t_4 >= PyList_GET_SIZE(__pyx_t_2)) break;
+      __pyx_t_3 = PyList_GET_ITEM(__pyx_t_2, __pyx_t_4); __Pyx_INCREF(__pyx_t_3); __pyx_t_4++;
+    } else if (!__pyx_t_5 && PyTuple_CheckExact(__pyx_t_2)) {
+      if (__pyx_t_4 >= PyTuple_GET_SIZE(__pyx_t_2)) break;
+      __pyx_t_3 = PyTuple_GET_ITEM(__pyx_t_2, __pyx_t_4); __Pyx_INCREF(__pyx_t_3); __pyx_t_4++;
+    } else {
+      __pyx_t_3 = __pyx_t_5(__pyx_t_2);
+      if (unlikely(!__pyx_t_3)) {
+        if (PyErr_Occurred()) {
+          if (likely(PyErr_ExceptionMatches(PyExc_StopIteration))) PyErr_Clear();
+          else {__pyx_filename = __pyx_f[0]; __pyx_lineno = 54; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+        }
+        break;
+      }
+      __Pyx_GOTREF(__pyx_t_3);
+    }
+    __Pyx_XGOTREF(__pyx_cur_scope->__pyx_v_kv);
+    __Pyx_XDECREF(__pyx_cur_scope->__pyx_v_kv);
+    __Pyx_GIVEREF(__pyx_t_3);
+    __pyx_cur_scope->__pyx_v_kv = __pyx_t_3;
+    __pyx_t_3 = 0;
+    __pyx_t_3 = PyNumber_Remainder(((PyObject *)__pyx_kp_s_44), __pyx_cur_scope->__pyx_v_kv); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 54; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(((PyObject *)__pyx_t_3));
+    __pyx_r = ((PyObject *)__pyx_t_3);
+    __pyx_t_3 = 0;
+    __Pyx_XGIVEREF(__pyx_t_2);
+    __pyx_cur_scope->__pyx_t_0 = __pyx_t_2;
+    __pyx_cur_scope->__pyx_t_1 = __pyx_t_4;
+    __pyx_cur_scope->__pyx_t_2 = __pyx_t_5;
+    __Pyx_XGIVEREF(__pyx_r);
+    __Pyx_RefNannyFinishContext();
+    /* return from generator, yielding value */
+    __pyx_generator->resume_label = 1;
+    return __pyx_r;
+    __pyx_L6_resume_from_yield:;
+    __pyx_t_2 = __pyx_cur_scope->__pyx_t_0;
+    __pyx_cur_scope->__pyx_t_0 = 0;
+    __Pyx_XGOTREF(__pyx_t_2);
+    __pyx_t_4 = __pyx_cur_scope->__pyx_t_1;
+    __pyx_t_5 = __pyx_cur_scope->__pyx_t_2;
+    if (unlikely(!__pyx_sent_value)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 54; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  }
+  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+  PyErr_SetNone(PyExc_StopIteration);
+  goto __pyx_L0;
+  __pyx_L1_error:;
+  __Pyx_XDECREF(__pyx_t_1);
+  __Pyx_XDECREF(__pyx_t_2);
+  __Pyx_XDECREF(__pyx_t_3);
+  __Pyx_AddTraceback("genexpr", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __pyx_L0:;
+  __Pyx_XDECREF(__pyx_r);
+  __pyx_generator->resume_label = -1;
+  __Pyx_RefNannyFinishContext();
+  return NULL;
+}
+
+/* "_cdec.pyx":43
+ *     cdef DenseVector weights
+ * 
+ *     def __cinit__(self, config_str=None, **config):             # <<<<<<<<<<<<<<
+ *         """ Configuration can be given as a string:
+ *                 Decoder('formalism = scfg')
+ */
+
+static int __pyx_pf_5_cdec_7Decoder___cinit__(struct __pyx_obj_5_cdec_Decoder *__pyx_v_self, PyObject *__pyx_v_config_str, PyObject *__pyx_v_config) {
+  struct __pyx_obj_5_cdec___pyx_scope_struct_23___cinit__ *__pyx_cur_scope;
+  PyObject *__pyx_v_formalism = NULL;
+  std::istringstream *__pyx_v_config_stream;
+  int __pyx_r;
+  __Pyx_RefNannyDeclarations
+  int __pyx_t_1;
+  PyObject *__pyx_t_2 = NULL;
+  PyObject *__pyx_t_3 = NULL;
+  int __pyx_t_4;
+  int __pyx_t_5;
+  PyObject *__pyx_t_6 = NULL;
+  char *__pyx_t_7;
+  int __pyx_lineno = 0;
+  const char *__pyx_filename = NULL;
+  int __pyx_clineno = 0;
+  __Pyx_RefNannySetupContext("__cinit__", 0);
+  __pyx_cur_scope = (struct __pyx_obj_5_cdec___pyx_scope_struct_23___cinit__ *)__pyx_ptype_5_cdec___pyx_scope_struct_23___cinit__->tp_new(__pyx_ptype_5_cdec___pyx_scope_struct_23___cinit__, __pyx_empty_tuple, NULL);
+  if (unlikely(!__pyx_cur_scope)) {
+    __Pyx_RefNannyFinishContext();
+    return -1;
+  }
+  __Pyx_GOTREF(__pyx_cur_scope);
+  __pyx_cur_scope->__pyx_v_config = __pyx_v_config;
+  __Pyx_INCREF(__pyx_cur_scope->__pyx_v_config);
+  __Pyx_GIVEREF(__pyx_cur_scope->__pyx_v_config);
+  __Pyx_INCREF(__pyx_v_config_str);
+
+  /* "_cdec.pyx":49
+ *                 Decoder(formalism='scfg')
+ *         """
+ *         if config_str is None:             # <<<<<<<<<<<<<<
+ *             formalism = config.get('formalism', None)
+ *             if formalism not in ('scfg', 'fst', 'lextrans', 'pb',
+ */
+  __pyx_t_1 = (__pyx_v_config_str == Py_None);
+  if (__pyx_t_1) {
+
+    /* "_cdec.pyx":50
+ *         """
+ *         if config_str is None:
+ *             formalism = config.get('formalism', None)             # <<<<<<<<<<<<<<
+ *             if formalism not in ('scfg', 'fst', 'lextrans', 'pb',
+ *                     'csplit', 'tagger', 'lexalign'):
+ */
+    __pyx_t_2 = PyObject_GetAttr(__pyx_cur_scope->__pyx_v_config, __pyx_n_s__get); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 50; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_2);
+    __pyx_t_3 = PyObject_Call(__pyx_t_2, ((PyObject *)__pyx_k_tuple_45), NULL); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 50; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_3);
+    __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+    __pyx_v_formalism = __pyx_t_3;
+    __pyx_t_3 = 0;
+
+    /* "_cdec.pyx":51
+ *         if config_str is None:
+ *             formalism = config.get('formalism', None)
+ *             if formalism not in ('scfg', 'fst', 'lextrans', 'pb',             # <<<<<<<<<<<<<<
+ *                     'csplit', 'tagger', 'lexalign'):
+ *                 raise InvalidConfig('formalism "%s" unknown' % formalism)
+ */
+    __Pyx_INCREF(__pyx_v_formalism);
+    __pyx_t_3 = __pyx_v_formalism;
+    __pyx_t_1 = __Pyx_PyString_Equals(__pyx_t_3, ((PyObject *)__pyx_n_s__scfg), Py_NE); if (unlikely(__pyx_t_1 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 51; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    if (((int)__pyx_t_1)) {
+      __pyx_t_4 = __Pyx_PyString_Equals(__pyx_t_3, ((PyObject *)__pyx_n_s__fst), Py_NE); if (unlikely(__pyx_t_4 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 51; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __pyx_t_5 = ((int)__pyx_t_4);
+    } else {
+      __pyx_t_5 = ((int)__pyx_t_1);
+    }
+    if (__pyx_t_5) {
+      __pyx_t_1 = __Pyx_PyString_Equals(__pyx_t_3, ((PyObject *)__pyx_n_s__lextrans), Py_NE); if (unlikely(__pyx_t_1 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 51; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __pyx_t_4 = ((int)__pyx_t_1);
+    } else {
+      __pyx_t_4 = __pyx_t_5;
+    }
+    if (__pyx_t_4) {
+      __pyx_t_5 = __Pyx_PyString_Equals(__pyx_t_3, ((PyObject *)__pyx_n_s__pb), Py_NE); if (unlikely(__pyx_t_5 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 51; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __pyx_t_1 = ((int)__pyx_t_5);
+    } else {
+      __pyx_t_1 = __pyx_t_4;
+    }
+    if (__pyx_t_1) {
+      __pyx_t_4 = __Pyx_PyString_Equals(__pyx_t_3, ((PyObject *)__pyx_n_s__csplit), Py_NE); if (unlikely(__pyx_t_4 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 51; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __pyx_t_5 = ((int)__pyx_t_4);
+    } else {
+      __pyx_t_5 = __pyx_t_1;
+    }
+    if (__pyx_t_5) {
+      __pyx_t_1 = __Pyx_PyString_Equals(__pyx_t_3, ((PyObject *)__pyx_n_s__tagger), Py_NE); if (unlikely(__pyx_t_1 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 51; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __pyx_t_4 = ((int)__pyx_t_1);
+    } else {
+      __pyx_t_4 = __pyx_t_5;
+    }
+    if (__pyx_t_4) {
+      __pyx_t_5 = __Pyx_PyString_Equals(__pyx_t_3, ((PyObject *)__pyx_n_s__lexalign), Py_NE); if (unlikely(__pyx_t_5 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 51; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __pyx_t_1 = ((int)__pyx_t_5);
+    } else {
+      __pyx_t_1 = __pyx_t_4;
+    }
+    __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
+    __pyx_t_4 = __pyx_t_1;
+    if (__pyx_t_4) {
+
+      /* "_cdec.pyx":53
+ *             if formalism not in ('scfg', 'fst', 'lextrans', 'pb',
+ *                     'csplit', 'tagger', 'lexalign'):
+ *                 raise InvalidConfig('formalism "%s" unknown' % formalism)             # <<<<<<<<<<<<<<
+ *             config_str = '\n'.join('%s = %s' % kv for kv in _make_config(config))
+ *         cdef istringstream* config_stream = new istringstream(config_str)
+ */
+      __pyx_t_3 = __Pyx_GetName(__pyx_m, __pyx_n_s__InvalidConfig); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 53; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __Pyx_GOTREF(__pyx_t_3);
+      __pyx_t_2 = PyNumber_Remainder(((PyObject *)__pyx_kp_s_46), __pyx_v_formalism); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 53; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __Pyx_GOTREF(((PyObject *)__pyx_t_2));
+      __pyx_t_6 = PyTuple_New(1); if (unlikely(!__pyx_t_6)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 53; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __Pyx_GOTREF(__pyx_t_6);
+      PyTuple_SET_ITEM(__pyx_t_6, 0, ((PyObject *)__pyx_t_2));
+      __Pyx_GIVEREF(((PyObject *)__pyx_t_2));
+      __pyx_t_2 = 0;
+      __pyx_t_2 = PyObject_Call(__pyx_t_3, ((PyObject *)__pyx_t_6), NULL); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 53; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __Pyx_GOTREF(__pyx_t_2);
+      __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
+      __Pyx_DECREF(((PyObject *)__pyx_t_6)); __pyx_t_6 = 0;
+      __Pyx_Raise(__pyx_t_2, 0, 0, 0);
+      __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+      {__pyx_filename = __pyx_f[0]; __pyx_lineno = 53; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      goto __pyx_L4;
+    }
+    __pyx_L4:;
+
+    /* "_cdec.pyx":54
+ *                     'csplit', 'tagger', 'lexalign'):
+ *                 raise InvalidConfig('formalism "%s" unknown' % formalism)
+ *             config_str = '\n'.join('%s = %s' % kv for kv in _make_config(config))             # <<<<<<<<<<<<<<
+ *         cdef istringstream* config_stream = new istringstream(config_str)
+ *         self.dec = new decoder.Decoder(config_stream)
+ */
+    __pyx_t_2 = PyObject_GetAttr(((PyObject *)__pyx_kp_s_39), __pyx_n_s__join); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 54; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_2);
+    __pyx_t_6 = __pyx_pf_5_cdec_7Decoder_9__cinit___genexpr(((PyObject*)__pyx_cur_scope)); if (unlikely(!__pyx_t_6)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 54; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_6);
+    __pyx_t_3 = PyTuple_New(1); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 54; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_3);
+    PyTuple_SET_ITEM(__pyx_t_3, 0, __pyx_t_6);
+    __Pyx_GIVEREF(__pyx_t_6);
+    __pyx_t_6 = 0;
+    __pyx_t_6 = PyObject_Call(__pyx_t_2, ((PyObject *)__pyx_t_3), NULL); if (unlikely(!__pyx_t_6)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 54; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_6);
+    __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+    __Pyx_DECREF(((PyObject *)__pyx_t_3)); __pyx_t_3 = 0;
+    __Pyx_DECREF(__pyx_v_config_str);
+    __pyx_v_config_str = __pyx_t_6;
+    __pyx_t_6 = 0;
+    goto __pyx_L3;
+  }
+  __pyx_L3:;
+
+  /* "_cdec.pyx":55
+ *                 raise InvalidConfig('formalism "%s" unknown' % formalism)
+ *             config_str = '\n'.join('%s = %s' % kv for kv in _make_config(config))
+ *         cdef istringstream* config_stream = new istringstream(config_str)             # <<<<<<<<<<<<<<
+ *         self.dec = new decoder.Decoder(config_stream)
+ *         del config_stream
+ */
+  __pyx_t_7 = PyBytes_AsString(__pyx_v_config_str); if (unlikely((!__pyx_t_7) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 55; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_v_config_stream = new std::istringstream(__pyx_t_7);
+
+  /* "_cdec.pyx":56
+ *             config_str = '\n'.join('%s = %s' % kv for kv in _make_config(config))
+ *         cdef istringstream* config_stream = new istringstream(config_str)
+ *         self.dec = new decoder.Decoder(config_stream)             # <<<<<<<<<<<<<<
+ *         del config_stream
+ *         self.weights = DenseVector()
+ */
+  __pyx_v_self->dec = new Decoder(__pyx_v_config_stream);
+
+  /* "_cdec.pyx":57
+ *         cdef istringstream* config_stream = new istringstream(config_str)
+ *         self.dec = new decoder.Decoder(config_stream)
+ *         del config_stream             # <<<<<<<<<<<<<<
+ *         self.weights = DenseVector()
+ *         self.weights.vector = &self.dec.CurrentWeightVector()
+ */
+  delete __pyx_v_config_stream;
+
+  /* "_cdec.pyx":58
+ *         self.dec = new decoder.Decoder(config_stream)
+ *         del config_stream
+ *         self.weights = DenseVector()             # <<<<<<<<<<<<<<
+ *         self.weights.vector = &self.dec.CurrentWeightVector()
+ * 
+ */
+  __pyx_t_6 = PyObject_Call(((PyObject *)((PyObject*)__pyx_ptype_5_cdec_DenseVector)), ((PyObject *)__pyx_empty_tuple), NULL); if (unlikely(!__pyx_t_6)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 58; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_6);
+  __Pyx_GIVEREF(__pyx_t_6);
+  __Pyx_GOTREF(__pyx_v_self->weights);
+  __Pyx_DECREF(((PyObject *)__pyx_v_self->weights));
+  __pyx_v_self->weights = ((struct __pyx_obj_5_cdec_DenseVector *)__pyx_t_6);
+  __pyx_t_6 = 0;
+
+  /* "_cdec.pyx":59
+ *         del config_stream
+ *         self.weights = DenseVector()
+ *         self.weights.vector = &self.dec.CurrentWeightVector()             # <<<<<<<<<<<<<<
+ * 
+ *     def __dealloc__(self):
+ */
+  __pyx_v_self->weights->vector = (&__pyx_v_self->dec->CurrentWeightVector());
+
+  __pyx_r = 0;
+  goto __pyx_L0;
+  __pyx_L1_error:;
+  __Pyx_XDECREF(__pyx_t_2);
+  __Pyx_XDECREF(__pyx_t_3);
+  __Pyx_XDECREF(__pyx_t_6);
+  __Pyx_AddTraceback("_cdec.Decoder.__cinit__", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __pyx_r = -1;
+  __pyx_L0:;
+  __Pyx_XDECREF(__pyx_v_formalism);
+  __Pyx_XDECREF(__pyx_v_config_str);
+  __Pyx_DECREF(((PyObject *)__pyx_cur_scope));
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+/* Python wrapper */
+static void __pyx_pw_5_cdec_7Decoder_3__dealloc__(PyObject *__pyx_v_self); /*proto*/
+static void __pyx_pw_5_cdec_7Decoder_3__dealloc__(PyObject *__pyx_v_self) {
+  __Pyx_RefNannyDeclarations
+  __Pyx_RefNannySetupContext("__dealloc__ (wrapper)", 0);
+  __pyx_pf_5_cdec_7Decoder_2__dealloc__(((struct __pyx_obj_5_cdec_Decoder *)__pyx_v_self));
+  __Pyx_RefNannyFinishContext();
+}
+
+/* "_cdec.pyx":61
+ *         self.weights.vector = &self.dec.CurrentWeightVector()
+ * 
+ *     def __dealloc__(self):             # <<<<<<<<<<<<<<
+ *         del self.dec
+ * 
+ */
+
+static void __pyx_pf_5_cdec_7Decoder_2__dealloc__(CYTHON_UNUSED struct __pyx_obj_5_cdec_Decoder *__pyx_v_self) {
+  __Pyx_RefNannyDeclarations
+  __Pyx_RefNannySetupContext("__dealloc__", 0);
+
+  /* "_cdec.pyx":62
+ * 
+ *     def __dealloc__(self):
+ *         del self.dec             # <<<<<<<<<<<<<<
+ * 
+ *     property weights:
+ */
+  delete __pyx_v_self->dec;
+
+  __Pyx_RefNannyFinishContext();
+}
+
+/* Python wrapper */
+static PyObject *__pyx_pw_5_cdec_7Decoder_7weights_1__get__(PyObject *__pyx_v_self); /*proto*/
+static PyObject *__pyx_pw_5_cdec_7Decoder_7weights_1__get__(PyObject *__pyx_v_self) {
+  PyObject *__pyx_r = 0;
+  __Pyx_RefNannyDeclarations
+  __Pyx_RefNannySetupContext("__get__ (wrapper)", 0);
+  __pyx_r = __pyx_pf_5_cdec_7Decoder_7weights___get__(((struct __pyx_obj_5_cdec_Decoder *)__pyx_v_self));
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+/* "_cdec.pyx":65
+ * 
+ *     property weights:
+ *         def __get__(self):             # <<<<<<<<<<<<<<
+ *             return self.weights
+ * 
+ */
+
+static PyObject *__pyx_pf_5_cdec_7Decoder_7weights___get__(struct __pyx_obj_5_cdec_Decoder *__pyx_v_self) {
+  PyObject *__pyx_r = NULL;
+  __Pyx_RefNannyDeclarations
+  __Pyx_RefNannySetupContext("__get__", 0);
+
+  /* "_cdec.pyx":66
+ *     property weights:
+ *         def __get__(self):
+ *             return self.weights             # <<<<<<<<<<<<<<
+ * 
+ *         def __set__(self, weights):
+ */
+  __Pyx_XDECREF(__pyx_r);
+  __Pyx_INCREF(((PyObject *)__pyx_v_self->weights));
+  __pyx_r = ((PyObject *)__pyx_v_self->weights);
+  goto __pyx_L0;
+
+  __pyx_r = Py_None; __Pyx_INCREF(Py_None);
+  __pyx_L0:;
+  __Pyx_XGIVEREF(__pyx_r);
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+/* Python wrapper */
+static int __pyx_pw_5_cdec_7Decoder_7weights_3__set__(PyObject *__pyx_v_self, PyObject *__pyx_v_weights); /*proto*/
+static int __pyx_pw_5_cdec_7Decoder_7weights_3__set__(PyObject *__pyx_v_self, PyObject *__pyx_v_weights) {
+  int __pyx_r;
+  __Pyx_RefNannyDeclarations
+  __Pyx_RefNannySetupContext("__set__ (wrapper)", 0);
+  __pyx_r = __pyx_pf_5_cdec_7Decoder_7weights_2__set__(((struct __pyx_obj_5_cdec_Decoder *)__pyx_v_self), ((PyObject *)__pyx_v_weights));
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+/* "_cdec.pyx":68
+ *             return self.weights
+ * 
+ *         def __set__(self, weights):             # <<<<<<<<<<<<<<
+ *             if isinstance(weights, DenseVector):
+ *                 self.weights.vector[0] = (<DenseVector> weights).vector[0]
+ */
+
+static int __pyx_pf_5_cdec_7Decoder_7weights_2__set__(struct __pyx_obj_5_cdec_Decoder *__pyx_v_self, PyObject *__pyx_v_weights) {
+  PyObject *__pyx_v_fname = NULL;
+  PyObject *__pyx_v_fval = NULL;
+  int __pyx_r;
+  __Pyx_RefNannyDeclarations
+  PyObject *__pyx_t_1 = NULL;
+  int __pyx_t_2;
+  PyObject *__pyx_t_3 = NULL;
+  Py_ssize_t __pyx_t_4;
+  PyObject *(*__pyx_t_5)(PyObject *);
+  PyObject *__pyx_t_6 = NULL;
+  PyObject *__pyx_t_7 = NULL;
+  PyObject *__pyx_t_8 = NULL;
+  PyObject *(*__pyx_t_9)(PyObject *);
+  int __pyx_lineno = 0;
+  const char *__pyx_filename = NULL;
+  int __pyx_clineno = 0;
+  __Pyx_RefNannySetupContext("__set__", 0);
+
+  /* "_cdec.pyx":69
+ * 
+ *         def __set__(self, weights):
+ *             if isinstance(weights, DenseVector):             # <<<<<<<<<<<<<<
+ *                 self.weights.vector[0] = (<DenseVector> weights).vector[0]
+ *             elif isinstance(weights, SparseVector):
+ */
+  __pyx_t_1 = ((PyObject *)((PyObject*)__pyx_ptype_5_cdec_DenseVector));
+  __Pyx_INCREF(__pyx_t_1);
+  __pyx_t_2 = __Pyx_TypeCheck(__pyx_v_weights, __pyx_t_1); 
+  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+  if (__pyx_t_2) {
+
+    /* "_cdec.pyx":70
+ *         def __set__(self, weights):
+ *             if isinstance(weights, DenseVector):
+ *                 self.weights.vector[0] = (<DenseVector> weights).vector[0]             # <<<<<<<<<<<<<<
+ *             elif isinstance(weights, SparseVector):
+ *                 self.weights.vector.clear()
+ */
+    (__pyx_v_self->weights->vector[0]) = (((struct __pyx_obj_5_cdec_DenseVector *)__pyx_v_weights)->vector[0]);
+    goto __pyx_L3;
+  }
+
+  /* "_cdec.pyx":71
+ *             if isinstance(weights, DenseVector):
+ *                 self.weights.vector[0] = (<DenseVector> weights).vector[0]
+ *             elif isinstance(weights, SparseVector):             # <<<<<<<<<<<<<<
+ *                 self.weights.vector.clear()
+ *                 ((<SparseVector> weights).vector[0]).init_vector(self.weights.vector)
+ */
+  __pyx_t_1 = ((PyObject *)((PyObject*)__pyx_ptype_5_cdec_SparseVector));
+  __Pyx_INCREF(__pyx_t_1);
+  __pyx_t_2 = __Pyx_TypeCheck(__pyx_v_weights, __pyx_t_1); 
+  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+  if (__pyx_t_2) {
+
+    /* "_cdec.pyx":72
+ *                 self.weights.vector[0] = (<DenseVector> weights).vector[0]
+ *             elif isinstance(weights, SparseVector):
+ *                 self.weights.vector.clear()             # <<<<<<<<<<<<<<
+ *                 ((<SparseVector> weights).vector[0]).init_vector(self.weights.vector)
+ *             elif isinstance(weights, dict):
+ */
+    __pyx_v_self->weights->vector->clear();
+
+    /* "_cdec.pyx":73
+ *             elif isinstance(weights, SparseVector):
+ *                 self.weights.vector.clear()
+ *                 ((<SparseVector> weights).vector[0]).init_vector(self.weights.vector)             # <<<<<<<<<<<<<<
+ *             elif isinstance(weights, dict):
+ *                 for fname, fval in weights.items():
+ */
+    (((struct __pyx_obj_5_cdec_SparseVector *)__pyx_v_weights)->vector[0]).init_vector(__pyx_v_self->weights->vector);
+    goto __pyx_L3;
+  }
+
+  /* "_cdec.pyx":74
+ *                 self.weights.vector.clear()
+ *                 ((<SparseVector> weights).vector[0]).init_vector(self.weights.vector)
+ *             elif isinstance(weights, dict):             # <<<<<<<<<<<<<<
+ *                 for fname, fval in weights.items():
+ *                     self.weights[fname] = fval
+ */
+  __pyx_t_1 = ((PyObject *)((PyObject*)(&PyDict_Type)));
+  __Pyx_INCREF(__pyx_t_1);
+  __pyx_t_2 = __Pyx_TypeCheck(__pyx_v_weights, __pyx_t_1); 
+  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+  if (__pyx_t_2) {
+
+    /* "_cdec.pyx":75
+ *                 ((<SparseVector> weights).vector[0]).init_vector(self.weights.vector)
+ *             elif isinstance(weights, dict):
+ *                 for fname, fval in weights.items():             # <<<<<<<<<<<<<<
+ *                     self.weights[fname] = fval
+ *             else:
+ */
+    __pyx_t_1 = PyObject_GetAttr(__pyx_v_weights, __pyx_n_s__items); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 75; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_1);
+    __pyx_t_3 = PyObject_Call(__pyx_t_1, ((PyObject *)__pyx_empty_tuple), NULL); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 75; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_3);
+    __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+    if (PyList_CheckExact(__pyx_t_3) || PyTuple_CheckExact(__pyx_t_3)) {
+      __pyx_t_1 = __pyx_t_3; __Pyx_INCREF(__pyx_t_1); __pyx_t_4 = 0;
+      __pyx_t_5 = NULL;
+    } else {
+      __pyx_t_4 = -1; __pyx_t_1 = PyObject_GetIter(__pyx_t_3); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 75; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __Pyx_GOTREF(__pyx_t_1);
+      __pyx_t_5 = Py_TYPE(__pyx_t_1)->tp_iternext;
+    }
+    __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
+    for (;;) {
+      if (!__pyx_t_5 && PyList_CheckExact(__pyx_t_1)) {
+        if (__pyx_t_4 >= PyList_GET_SIZE(__pyx_t_1)) break;
+        __pyx_t_3 = PyList_GET_ITEM(__pyx_t_1, __pyx_t_4); __Pyx_INCREF(__pyx_t_3); __pyx_t_4++;
+      } else if (!__pyx_t_5 && PyTuple_CheckExact(__pyx_t_1)) {
+        if (__pyx_t_4 >= PyTuple_GET_SIZE(__pyx_t_1)) break;
+        __pyx_t_3 = PyTuple_GET_ITEM(__pyx_t_1, __pyx_t_4); __Pyx_INCREF(__pyx_t_3); __pyx_t_4++;
+      } else {
+        __pyx_t_3 = __pyx_t_5(__pyx_t_1);
+        if (unlikely(!__pyx_t_3)) {
+          if (PyErr_Occurred()) {
+            if (likely(PyErr_ExceptionMatches(PyExc_StopIteration))) PyErr_Clear();
+            else {__pyx_filename = __pyx_f[0]; __pyx_lineno = 75; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+          }
+          break;
+        }
+        __Pyx_GOTREF(__pyx_t_3);
+      }
+      if ((likely(PyTuple_CheckExact(__pyx_t_3))) || (PyList_CheckExact(__pyx_t_3))) {
+        PyObject* sequence = __pyx_t_3;
+        if (likely(PyTuple_CheckExact(sequence))) {
+          if (unlikely(PyTuple_GET_SIZE(sequence) != 2)) {
+            if (PyTuple_GET_SIZE(sequence) > 2) __Pyx_RaiseTooManyValuesError(2);
+            else __Pyx_RaiseNeedMoreValuesError(PyTuple_GET_SIZE(sequence));
+            {__pyx_filename = __pyx_f[0]; __pyx_lineno = 75; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+          }
+          __pyx_t_6 = PyTuple_GET_ITEM(sequence, 0); 
+          __pyx_t_7 = PyTuple_GET_ITEM(sequence, 1); 
+        } else {
+          if (unlikely(PyList_GET_SIZE(sequence) != 2)) {
+            if (PyList_GET_SIZE(sequence) > 2) __Pyx_RaiseTooManyValuesError(2);
+            else __Pyx_RaiseNeedMoreValuesError(PyList_GET_SIZE(sequence));
+            {__pyx_filename = __pyx_f[0]; __pyx_lineno = 75; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+          }
+          __pyx_t_6 = PyList_GET_ITEM(sequence, 0); 
+          __pyx_t_7 = PyList_GET_ITEM(sequence, 1); 
+        }
+        __Pyx_INCREF(__pyx_t_6);
+        __Pyx_INCREF(__pyx_t_7);
+        __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
+      } else {
+        Py_ssize_t index = -1;
+        __pyx_t_8 = PyObject_GetIter(__pyx_t_3); if (unlikely(!__pyx_t_8)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 75; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+        __Pyx_GOTREF(__pyx_t_8);
+        __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
+        __pyx_t_9 = Py_TYPE(__pyx_t_8)->tp_iternext;
+        index = 0; __pyx_t_6 = __pyx_t_9(__pyx_t_8); if (unlikely(!__pyx_t_6)) goto __pyx_L6_unpacking_failed;
+        __Pyx_GOTREF(__pyx_t_6);
+        index = 1; __pyx_t_7 = __pyx_t_9(__pyx_t_8); if (unlikely(!__pyx_t_7)) goto __pyx_L6_unpacking_failed;
+        __Pyx_GOTREF(__pyx_t_7);
+        if (__Pyx_IternextUnpackEndCheck(__pyx_t_9(__pyx_t_8), 2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 75; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+        __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0;
+        goto __pyx_L7_unpacking_done;
+        __pyx_L6_unpacking_failed:;
+        __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0;
+        if (PyErr_Occurred() && PyErr_ExceptionMatches(PyExc_StopIteration)) PyErr_Clear();
+        if (!PyErr_Occurred()) __Pyx_RaiseNeedMoreValuesError(index);
+        {__pyx_filename = __pyx_f[0]; __pyx_lineno = 75; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+        __pyx_L7_unpacking_done:;
+      }
+      __Pyx_XDECREF(__pyx_v_fname);
+      __pyx_v_fname = __pyx_t_6;
+      __pyx_t_6 = 0;
+      __Pyx_XDECREF(__pyx_v_fval);
+      __pyx_v_fval = __pyx_t_7;
+      __pyx_t_7 = 0;
+
+      /* "_cdec.pyx":76
+ *             elif isinstance(weights, dict):
+ *                 for fname, fval in weights.items():
+ *                     self.weights[fname] = fval             # <<<<<<<<<<<<<<
+ *             else:
+ *                 raise TypeError('cannot initialize weights with %s' % type(weights))
+ */
+      if (PyObject_SetItem(((PyObject *)__pyx_v_self->weights), __pyx_v_fname, __pyx_v_fval) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 76; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    }
+    __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+    goto __pyx_L3;
+  }
+  /*else*/ {
+
+    /* "_cdec.pyx":78
+ *                     self.weights[fname] = fval
+ *             else:
+ *                 raise TypeError('cannot initialize weights with %s' % type(weights))             # <<<<<<<<<<<<<<
+ * 
+ *     property formalism:
+ */
+    __pyx_t_1 = PyNumber_Remainder(((PyObject *)__pyx_kp_s_47), ((PyObject *)Py_TYPE(__pyx_v_weights))); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 78; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(((PyObject *)__pyx_t_1));
+    __pyx_t_3 = PyTuple_New(1); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 78; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_3);
+    PyTuple_SET_ITEM(__pyx_t_3, 0, ((PyObject *)__pyx_t_1));
+    __Pyx_GIVEREF(((PyObject *)__pyx_t_1));
+    __pyx_t_1 = 0;
+    __pyx_t_1 = PyObject_Call(__pyx_builtin_TypeError, ((PyObject *)__pyx_t_3), NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 78; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_1);
+    __Pyx_DECREF(((PyObject *)__pyx_t_3)); __pyx_t_3 = 0;
+    __Pyx_Raise(__pyx_t_1, 0, 0, 0);
+    __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+    {__pyx_filename = __pyx_f[0]; __pyx_lineno = 78; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  }
+  __pyx_L3:;
+
+  __pyx_r = 0;
+  goto __pyx_L0;
+  __pyx_L1_error:;
+  __Pyx_XDECREF(__pyx_t_1);
+  __Pyx_XDECREF(__pyx_t_3);
+  __Pyx_XDECREF(__pyx_t_6);
+  __Pyx_XDECREF(__pyx_t_7);
+  __Pyx_XDECREF(__pyx_t_8);
+  __Pyx_AddTraceback("_cdec.Decoder.weights.__set__", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __pyx_r = -1;
+  __pyx_L0:;
+  __Pyx_XDECREF(__pyx_v_fname);
+  __Pyx_XDECREF(__pyx_v_fval);
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+/* Python wrapper */
+static PyObject *__pyx_pw_5_cdec_7Decoder_9formalism_1__get__(PyObject *__pyx_v_self); /*proto*/
+static PyObject *__pyx_pw_5_cdec_7Decoder_9formalism_1__get__(PyObject *__pyx_v_self) {
+  PyObject *__pyx_r = 0;
+  __Pyx_RefNannyDeclarations
+  __Pyx_RefNannySetupContext("__get__ (wrapper)", 0);
+  __pyx_r = __pyx_pf_5_cdec_7Decoder_9formalism___get__(((struct __pyx_obj_5_cdec_Decoder *)__pyx_v_self));
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+/* "_cdec.pyx":81
+ * 
+ *     property formalism:
+ *         def __get__(self):             # <<<<<<<<<<<<<<
+ *             cdef variables_map* conf = &self.dec.GetConf()
+ *             return conf[0]['formalism'].as_str().c_str()
+ */
+
+static PyObject *__pyx_pf_5_cdec_7Decoder_9formalism___get__(struct __pyx_obj_5_cdec_Decoder *__pyx_v_self) {
+  const boost::program_options::variables_map *__pyx_v_conf;
+  PyObject *__pyx_r = NULL;
+  __Pyx_RefNannyDeclarations
+  PyObject *__pyx_t_1 = NULL;
+  int __pyx_lineno = 0;
+  const char *__pyx_filename = NULL;
+  int __pyx_clineno = 0;
+  __Pyx_RefNannySetupContext("__get__", 0);
+
+  /* "_cdec.pyx":82
+ *     property formalism:
+ *         def __get__(self):
+ *             cdef variables_map* conf = &self.dec.GetConf()             # <<<<<<<<<<<<<<
+ *             return conf[0]['formalism'].as_str().c_str()
+ * 
+ */
+  __pyx_v_conf = (&__pyx_v_self->dec->GetConf());
+
+  /* "_cdec.pyx":83
+ *         def __get__(self):
+ *             cdef variables_map* conf = &self.dec.GetConf()
+ *             return conf[0]['formalism'].as_str().c_str()             # <<<<<<<<<<<<<<
+ * 
+ *     def read_weights(self, weights):
+ */
+  __Pyx_XDECREF(__pyx_r);
+  __pyx_t_1 = PyBytes_FromString(((__pyx_v_conf[0])[__pyx_k__formalism]).as<std::string>().c_str()); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 83; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(((PyObject *)__pyx_t_1));
+  __pyx_r = ((PyObject *)__pyx_t_1);
+  __pyx_t_1 = 0;
+  goto __pyx_L0;
+
+  __pyx_r = Py_None; __Pyx_INCREF(Py_None);
+  goto __pyx_L0;
+  __pyx_L1_error:;
+  __Pyx_XDECREF(__pyx_t_1);
+  __Pyx_AddTraceback("_cdec.Decoder.formalism.__get__", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __pyx_r = NULL;
+  __pyx_L0:;
+  __Pyx_XGIVEREF(__pyx_r);
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+/* Python wrapper */
+static PyObject *__pyx_pw_5_cdec_7Decoder_5read_weights(PyObject *__pyx_v_self, PyObject *__pyx_v_weights); /*proto*/
+static PyObject *__pyx_pw_5_cdec_7Decoder_5read_weights(PyObject *__pyx_v_self, PyObject *__pyx_v_weights) {
+  PyObject *__pyx_r = 0;
+  __Pyx_RefNannyDeclarations
+  __Pyx_RefNannySetupContext("read_weights (wrapper)", 0);
+  __pyx_r = __pyx_pf_5_cdec_7Decoder_4read_weights(((struct __pyx_obj_5_cdec_Decoder *)__pyx_v_self), ((PyObject *)__pyx_v_weights));
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+/* "_cdec.pyx":85
+ *             return conf[0]['formalism'].as_str().c_str()
+ * 
+ *     def read_weights(self, weights):             # <<<<<<<<<<<<<<
+ *         with open(weights) as fp:
+ *             for line in fp:
+ */
+
+static PyObject *__pyx_pf_5_cdec_7Decoder_4read_weights(struct __pyx_obj_5_cdec_Decoder *__pyx_v_self, PyObject *__pyx_v_weights) {
+  PyObject *__pyx_v_fp = NULL;
+  PyObject *__pyx_v_line = NULL;
+  PyObject *__pyx_v_fname = NULL;
+  PyObject *__pyx_v_value = NULL;
+  PyObject *__pyx_r = NULL;
+  __Pyx_RefNannyDeclarations
+  PyObject *__pyx_t_1 = NULL;
+  PyObject *__pyx_t_2 = NULL;
+  PyObject *__pyx_t_3 = NULL;
+  PyObject *__pyx_t_4 = NULL;
+  PyObject *__pyx_t_5 = NULL;
+  PyObject *__pyx_t_6 = NULL;
+  PyObject *__pyx_t_7 = NULL;
+  Py_ssize_t __pyx_t_8;
+  PyObject *(*__pyx_t_9)(PyObject *);
+  int __pyx_t_10;
+  PyObject *__pyx_t_11 = NULL;
+  PyObject *__pyx_t_12 = NULL;
+  PyObject *(*__pyx_t_13)(PyObject *);
+  double __pyx_t_14;
+  PyObject *__pyx_t_15 = NULL;
+  int __pyx_t_16;
+  int __pyx_lineno = 0;
+  const char *__pyx_filename = NULL;
+  int __pyx_clineno = 0;
+  __Pyx_RefNannySetupContext("read_weights", 0);
+
+  /* "_cdec.pyx":86
+ * 
+ *     def read_weights(self, weights):
+ *         with open(weights) as fp:             # <<<<<<<<<<<<<<
+ *             for line in fp:
+ *                 if line.strip().startswith('#'): continue
+ */
+  /*with:*/ {
+    __pyx_t_1 = PyTuple_New(1); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 86; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_1);
+    __Pyx_INCREF(__pyx_v_weights);
+    PyTuple_SET_ITEM(__pyx_t_1, 0, __pyx_v_weights);
+    __Pyx_GIVEREF(__pyx_v_weights);
+    __pyx_t_2 = PyObject_Call(__pyx_builtin_open, ((PyObject *)__pyx_t_1), NULL); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 86; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_2);
+    __Pyx_DECREF(((PyObject *)__pyx_t_1)); __pyx_t_1 = 0;
+    __pyx_t_3 = PyObject_GetAttr(__pyx_t_2, __pyx_n_s____exit__); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 86; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_3);
+    __pyx_t_1 = PyObject_GetAttr(__pyx_t_2, __pyx_n_s____enter__); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 86; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+    __Pyx_GOTREF(__pyx_t_1);
+    __pyx_t_4 = PyObject_Call(__pyx_t_1, ((PyObject *)__pyx_empty_tuple), NULL); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 86; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+    __Pyx_GOTREF(__pyx_t_4);
+    __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+    __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+    /*try:*/ {
+      {
+        __Pyx_ExceptionSave(&__pyx_t_5, &__pyx_t_6, &__pyx_t_7);
+        __Pyx_XGOTREF(__pyx_t_5);
+        __Pyx_XGOTREF(__pyx_t_6);
+        __Pyx_XGOTREF(__pyx_t_7);
+        /*try:*/ {
+          __Pyx_INCREF(__pyx_t_4);
+          __pyx_v_fp = __pyx_t_4;
+          __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
+
+          /* "_cdec.pyx":87
+ *     def read_weights(self, weights):
+ *         with open(weights) as fp:
+ *             for line in fp:             # <<<<<<<<<<<<<<
+ *                 if line.strip().startswith('#'): continue
+ *                 fname, value = line.split()
+ */
+          if (PyList_CheckExact(__pyx_v_fp) || PyTuple_CheckExact(__pyx_v_fp)) {
+            __pyx_t_4 = __pyx_v_fp; __Pyx_INCREF(__pyx_t_4); __pyx_t_8 = 0;
+            __pyx_t_9 = NULL;
+          } else {
+            __pyx_t_8 = -1; __pyx_t_4 = PyObject_GetIter(__pyx_v_fp); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 87; __pyx_clineno = __LINE__; goto __pyx_L7_error;}
+            __Pyx_GOTREF(__pyx_t_4);
+            __pyx_t_9 = Py_TYPE(__pyx_t_4)->tp_iternext;
+          }
+          for (;;) {
+            if (!__pyx_t_9 && PyList_CheckExact(__pyx_t_4)) {
+              if (__pyx_t_8 >= PyList_GET_SIZE(__pyx_t_4)) break;
+              __pyx_t_2 = PyList_GET_ITEM(__pyx_t_4, __pyx_t_8); __Pyx_INCREF(__pyx_t_2); __pyx_t_8++;
+            } else if (!__pyx_t_9 && PyTuple_CheckExact(__pyx_t_4)) {
+              if (__pyx_t_8 >= PyTuple_GET_SIZE(__pyx_t_4)) break;
+              __pyx_t_2 = PyTuple_GET_ITEM(__pyx_t_4, __pyx_t_8); __Pyx_INCREF(__pyx_t_2); __pyx_t_8++;
+            } else {
+              __pyx_t_2 = __pyx_t_9(__pyx_t_4);
+              if (unlikely(!__pyx_t_2)) {
+                if (PyErr_Occurred()) {
+                  if (likely(PyErr_ExceptionMatches(PyExc_StopIteration))) PyErr_Clear();
+                  else {__pyx_filename = __pyx_f[0]; __pyx_lineno = 87; __pyx_clineno = __LINE__; goto __pyx_L7_error;}
+                }
+                break;
+              }
+              __Pyx_GOTREF(__pyx_t_2);
+            }
+            __Pyx_XDECREF(__pyx_v_line);
+            __pyx_v_line = __pyx_t_2;
+            __pyx_t_2 = 0;
+
+            /* "_cdec.pyx":88
+ *         with open(weights) as fp:
+ *             for line in fp:
+ *                 if line.strip().startswith('#'): continue             # <<<<<<<<<<<<<<
+ *                 fname, value = line.split()
+ *                 self.weights[fname.strip()] = float(value)
+ */
+            __pyx_t_2 = PyObject_GetAttr(__pyx_v_line, __pyx_n_s__strip); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 88; __pyx_clineno = __LINE__; goto __pyx_L7_error;}
+            __Pyx_GOTREF(__pyx_t_2);
+            __pyx_t_1 = PyObject_Call(__pyx_t_2, ((PyObject *)__pyx_empty_tuple), NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 88; __pyx_clineno = __LINE__; goto __pyx_L7_error;}
+            __Pyx_GOTREF(__pyx_t_1);
+            __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+            __pyx_t_2 = PyObject_GetAttr(__pyx_t_1, __pyx_n_s__startswith); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 88; __pyx_clineno = __LINE__; goto __pyx_L7_error;}
+            __Pyx_GOTREF(__pyx_t_2);
+            __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+            __pyx_t_1 = PyObject_Call(__pyx_t_2, ((PyObject *)__pyx_k_tuple_49), NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 88; __pyx_clineno = __LINE__; goto __pyx_L7_error;}
+            __Pyx_GOTREF(__pyx_t_1);
+            __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+            __pyx_t_10 = __Pyx_PyObject_IsTrue(__pyx_t_1); if (unlikely(__pyx_t_10 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 88; __pyx_clineno = __LINE__; goto __pyx_L7_error;}
+            __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+            if (__pyx_t_10) {
+              goto __pyx_L16_continue;
+              goto __pyx_L18;
+            }
+            __pyx_L18:;
+
+            /* "_cdec.pyx":89
+ *             for line in fp:
+ *                 if line.strip().startswith('#'): continue
+ *                 fname, value = line.split()             # <<<<<<<<<<<<<<
+ *                 self.weights[fname.strip()] = float(value)
+ * 
+ */
+            __pyx_t_1 = PyObject_GetAttr(__pyx_v_line, __pyx_n_s__split); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 89; __pyx_clineno = __LINE__; goto __pyx_L7_error;}
+            __Pyx_GOTREF(__pyx_t_1);
+            __pyx_t_2 = PyObject_Call(__pyx_t_1, ((PyObject *)__pyx_empty_tuple), NULL); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 89; __pyx_clineno = __LINE__; goto __pyx_L7_error;}
+            __Pyx_GOTREF(__pyx_t_2);
+            __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+            if ((likely(PyTuple_CheckExact(__pyx_t_2))) || (PyList_CheckExact(__pyx_t_2))) {
+              PyObject* sequence = __pyx_t_2;
+              if (likely(PyTuple_CheckExact(sequence))) {
+                if (unlikely(PyTuple_GET_SIZE(sequence) != 2)) {
+                  if (PyTuple_GET_SIZE(sequence) > 2) __Pyx_RaiseTooManyValuesError(2);
+                  else __Pyx_RaiseNeedMoreValuesError(PyTuple_GET_SIZE(sequence));
+                  {__pyx_filename = __pyx_f[0]; __pyx_lineno = 89; __pyx_clineno = __LINE__; goto __pyx_L7_error;}
+                }
+                __pyx_t_1 = PyTuple_GET_ITEM(sequence, 0); 
+                __pyx_t_11 = PyTuple_GET_ITEM(sequence, 1); 
+              } else {
+                if (unlikely(PyList_GET_SIZE(sequence) != 2)) {
+                  if (PyList_GET_SIZE(sequence) > 2) __Pyx_RaiseTooManyValuesError(2);
+                  else __Pyx_RaiseNeedMoreValuesError(PyList_GET_SIZE(sequence));
+                  {__pyx_filename = __pyx_f[0]; __pyx_lineno = 89; __pyx_clineno = __LINE__; goto __pyx_L7_error;}
+                }
+                __pyx_t_1 = PyList_GET_ITEM(sequence, 0); 
+                __pyx_t_11 = PyList_GET_ITEM(sequence, 1); 
+              }
+              __Pyx_INCREF(__pyx_t_1);
+              __Pyx_INCREF(__pyx_t_11);
+              __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+            } else {
+              Py_ssize_t index = -1;
+              __pyx_t_12 = PyObject_GetIter(__pyx_t_2); if (unlikely(!__pyx_t_12)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 89; __pyx_clineno = __LINE__; goto __pyx_L7_error;}
+              __Pyx_GOTREF(__pyx_t_12);
+              __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+              __pyx_t_13 = Py_TYPE(__pyx_t_12)->tp_iternext;
+              index = 0; __pyx_t_1 = __pyx_t_13(__pyx_t_12); if (unlikely(!__pyx_t_1)) goto __pyx_L19_unpacking_failed;
+              __Pyx_GOTREF(__pyx_t_1);
+              index = 1; __pyx_t_11 = __pyx_t_13(__pyx_t_12); if (unlikely(!__pyx_t_11)) goto __pyx_L19_unpacking_failed;
+              __Pyx_GOTREF(__pyx_t_11);
+              if (__Pyx_IternextUnpackEndCheck(__pyx_t_13(__pyx_t_12), 2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 89; __pyx_clineno = __LINE__; goto __pyx_L7_error;}
+              __Pyx_DECREF(__pyx_t_12); __pyx_t_12 = 0;
+              goto __pyx_L20_unpacking_done;
+              __pyx_L19_unpacking_failed:;
+              __Pyx_DECREF(__pyx_t_12); __pyx_t_12 = 0;
+              if (PyErr_Occurred() && PyErr_ExceptionMatches(PyExc_StopIteration)) PyErr_Clear();
+              if (!PyErr_Occurred()) __Pyx_RaiseNeedMoreValuesError(index);
+              {__pyx_filename = __pyx_f[0]; __pyx_lineno = 89; __pyx_clineno = __LINE__; goto __pyx_L7_error;}
+              __pyx_L20_unpacking_done:;
+            }
+            __Pyx_XDECREF(__pyx_v_fname);
+            __pyx_v_fname = __pyx_t_1;
+            __pyx_t_1 = 0;
+            __Pyx_XDECREF(__pyx_v_value);
+            __pyx_v_value = __pyx_t_11;
+            __pyx_t_11 = 0;
+
+            /* "_cdec.pyx":90
+ *                 if line.strip().startswith('#'): continue
+ *                 fname, value = line.split()
+ *                 self.weights[fname.strip()] = float(value)             # <<<<<<<<<<<<<<
+ * 
+ *     def translate(self, sentence, grammar=None):
+ */
+            __pyx_t_14 = __Pyx_PyObject_AsDouble(__pyx_v_value); if (unlikely(__pyx_t_14 == ((double)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 90; __pyx_clineno = __LINE__; goto __pyx_L7_error;}
+            __pyx_t_2 = PyFloat_FromDouble(__pyx_t_14); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 90; __pyx_clineno = __LINE__; goto __pyx_L7_error;}
+            __Pyx_GOTREF(__pyx_t_2);
+            __pyx_t_11 = PyObject_GetAttr(__pyx_v_fname, __pyx_n_s__strip); if (unlikely(!__pyx_t_11)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 90; __pyx_clineno = __LINE__; goto __pyx_L7_error;}
+            __Pyx_GOTREF(__pyx_t_11);
+            __pyx_t_1 = PyObject_Call(__pyx_t_11, ((PyObject *)__pyx_empty_tuple), NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 90; __pyx_clineno = __LINE__; goto __pyx_L7_error;}
+            __Pyx_GOTREF(__pyx_t_1);
+            __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0;
+            if (PyObject_SetItem(((PyObject *)__pyx_v_self->weights), __pyx_t_1, __pyx_t_2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 90; __pyx_clineno = __LINE__; goto __pyx_L7_error;}
+            __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+            __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+            __pyx_L16_continue:;
+          }
+          __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
+        }
+        __Pyx_XDECREF(__pyx_t_5); __pyx_t_5 = 0;
+        __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0;
+        __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0;
+        goto __pyx_L14_try_end;
+        __pyx_L7_error:;
+        __Pyx_XDECREF(__pyx_t_12); __pyx_t_12 = 0;
+        __Pyx_XDECREF(__pyx_t_11); __pyx_t_11 = 0;
+        __Pyx_XDECREF(__pyx_t_1); __pyx_t_1 = 0;
+        __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0;
+        __Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0;
+
+        /* "_cdec.pyx":86
+ * 
+ *     def read_weights(self, weights):
+ *         with open(weights) as fp:             # <<<<<<<<<<<<<<
+ *             for line in fp:
+ *                 if line.strip().startswith('#'): continue
+ */
+        /*except:*/ {
+          __Pyx_AddTraceback("_cdec.Decoder.read_weights", __pyx_clineno, __pyx_lineno, __pyx_filename);
+          if (__Pyx_GetException(&__pyx_t_4, &__pyx_t_2, &__pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 86; __pyx_clineno = __LINE__; goto __pyx_L9_except_error;}
+          __Pyx_GOTREF(__pyx_t_4);
+          __Pyx_GOTREF(__pyx_t_2);
+          __Pyx_GOTREF(__pyx_t_1);
+          __pyx_t_11 = PyTuple_New(3); if (unlikely(!__pyx_t_11)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 86; __pyx_clineno = __LINE__; goto __pyx_L9_except_error;}
+          __Pyx_GOTREF(__pyx_t_11);
+          __Pyx_INCREF(__pyx_t_4);
+          PyTuple_SET_ITEM(__pyx_t_11, 0, __pyx_t_4);
+          __Pyx_GIVEREF(__pyx_t_4);
+          __Pyx_INCREF(__pyx_t_2);
+          PyTuple_SET_ITEM(__pyx_t_11, 1, __pyx_t_2);
+          __Pyx_GIVEREF(__pyx_t_2);
+          __Pyx_INCREF(__pyx_t_1);
+          PyTuple_SET_ITEM(__pyx_t_11, 2, __pyx_t_1);
+          __Pyx_GIVEREF(__pyx_t_1);
+          __pyx_t_15 = PyObject_Call(__pyx_t_3, __pyx_t_11, NULL);
+          __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
+          if (unlikely(!__pyx_t_15)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 86; __pyx_clineno = __LINE__; goto __pyx_L9_except_error;}
+          __Pyx_GOTREF(__pyx_t_15);
+          __pyx_t_10 = __Pyx_PyObject_IsTrue(__pyx_t_15);
+          __Pyx_DECREF(__pyx_t_15); __pyx_t_15 = 0;
+          if (unlikely(__pyx_t_10 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 86; __pyx_clineno = __LINE__; goto __pyx_L9_except_error;}
+          __pyx_t_16 = (!__pyx_t_10);
+          if (__pyx_t_16) {
+            __Pyx_GIVEREF(__pyx_t_4);
+            __Pyx_GIVEREF(__pyx_t_2);
+            __Pyx_GIVEREF(__pyx_t_1);
+            __Pyx_ErrRestore(__pyx_t_4, __pyx_t_2, __pyx_t_1);
+            __pyx_t_4 = 0; __pyx_t_2 = 0; __pyx_t_1 = 0; 
+            {__pyx_filename = __pyx_f[0]; __pyx_lineno = 86; __pyx_clineno = __LINE__; goto __pyx_L9_except_error;}
+            goto __pyx_L23;
+          }
+          __pyx_L23:;
+          __Pyx_DECREF(((PyObject *)__pyx_t_11)); __pyx_t_11 = 0;
+          __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
+          __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+          __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+          goto __pyx_L8_exception_handled;
+        }
+        __pyx_L9_except_error:;
+        __Pyx_XGIVEREF(__pyx_t_5);
+        __Pyx_XGIVEREF(__pyx_t_6);
+        __Pyx_XGIVEREF(__pyx_t_7);
+        __Pyx_ExceptionReset(__pyx_t_5, __pyx_t_6, __pyx_t_7);
+        goto __pyx_L1_error;
+        __pyx_L8_exception_handled:;
+        __Pyx_XGIVEREF(__pyx_t_5);
+        __Pyx_XGIVEREF(__pyx_t_6);
+        __Pyx_XGIVEREF(__pyx_t_7);
+        __Pyx_ExceptionReset(__pyx_t_5, __pyx_t_6, __pyx_t_7);
+        __pyx_L14_try_end:;
+      }
+    }
+    /*finally:*/ {
+      if (__pyx_t_3) {
+        __pyx_t_7 = PyObject_Call(__pyx_t_3, __pyx_k_tuple_50, NULL);
+        __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
+        if (unlikely(!__pyx_t_7)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 86; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+        __Pyx_GOTREF(__pyx_t_7);
+        __pyx_t_16 = __Pyx_PyObject_IsTrue(__pyx_t_7);
+        __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;
+        if (unlikely(__pyx_t_16 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 86; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      }
+    }
+    goto __pyx_L24;
+    __pyx_L3_error:;
+    __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
+    goto __pyx_L1_error;
+    __pyx_L24:;
+  }
+
+  __pyx_r = Py_None; __Pyx_INCREF(Py_None);
+  goto __pyx_L0;
+  __pyx_L1_error:;
+  __Pyx_XDECREF(__pyx_t_1);
+  __Pyx_XDECREF(__pyx_t_2);
+  __Pyx_XDECREF(__pyx_t_4);
+  __Pyx_XDECREF(__pyx_t_11);
+  __Pyx_XDECREF(__pyx_t_12);
+  __Pyx_AddTraceback("_cdec.Decoder.read_weights", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __pyx_r = NULL;
+  __pyx_L0:;
+  __Pyx_XDECREF(__pyx_v_fp);
+  __Pyx_XDECREF(__pyx_v_line);
+  __Pyx_XDECREF(__pyx_v_fname);
+  __Pyx_XDECREF(__pyx_v_value);
+  __Pyx_XGIVEREF(__pyx_r);
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+/* Python wrapper */
+static PyObject *__pyx_pw_5_cdec_7Decoder_7translate(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/
+static PyObject *__pyx_pw_5_cdec_7Decoder_7translate(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) {
+  PyObject *__pyx_v_sentence = 0;
+  PyObject *__pyx_v_grammar = 0;
+  static PyObject **__pyx_pyargnames[] = {&__pyx_n_s__sentence,&__pyx_n_s__grammar,0};
+  PyObject *__pyx_r = 0;
+  __Pyx_RefNannyDeclarations
+  __Pyx_RefNannySetupContext("translate (wrapper)", 0);
+  {
+    PyObject* values[2] = {0,0};
+
+    /* "_cdec.pyx":92
+ *                 self.weights[fname.strip()] = float(value)
+ * 
+ *     def translate(self, sentence, grammar=None):             # <<<<<<<<<<<<<<
+ *         cdef bytes input_str
+ *         if isinstance(sentence, unicode) or isinstance(sentence, str):
+ */
+    values[1] = ((PyObject *)Py_None);
+    if (unlikely(__pyx_kwds)) {
+      Py_ssize_t kw_args;
+      const Py_ssize_t pos_args = PyTuple_GET_SIZE(__pyx_args);
+      switch (pos_args) {
+        case  2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1);
+        case  1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0);
+        case  0: break;
+        default: goto __pyx_L5_argtuple_error;
+      }
+      kw_args = PyDict_Size(__pyx_kwds);
+      switch (pos_args) {
+        case  0:
+        values[0] = PyDict_GetItem(__pyx_kwds, __pyx_n_s__sentence);
+        if (likely(values[0])) kw_args--;
+        else goto __pyx_L5_argtuple_error;
+        case  1:
+        if (kw_args > 0) {
+          PyObject* value = PyDict_GetItem(__pyx_kwds, __pyx_n_s__grammar);
+          if (value) { values[1] = value; kw_args--; }
+        }
+      }
+      if (unlikely(kw_args > 0)) {
+        if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "translate") < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 92; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+      }
+    } else {
+      switch (PyTuple_GET_SIZE(__pyx_args)) {
+        case  2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1);
+        case  1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0);
+        break;
+        default: goto __pyx_L5_argtuple_error;
+      }
+    }
+    __pyx_v_sentence = values[0];
+    __pyx_v_grammar = values[1];
+  }
+  goto __pyx_L4_argument_unpacking_done;
+  __pyx_L5_argtuple_error:;
+  __Pyx_RaiseArgtupleInvalid("translate", 0, 1, 2, PyTuple_GET_SIZE(__pyx_args)); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 92; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+  __pyx_L3_error:;
+  __Pyx_AddTraceback("_cdec.Decoder.translate", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __Pyx_RefNannyFinishContext();
+  return NULL;
+  __pyx_L4_argument_unpacking_done:;
+  __pyx_r = __pyx_pf_5_cdec_7Decoder_6translate(((struct __pyx_obj_5_cdec_Decoder *)__pyx_v_self), __pyx_v_sentence, __pyx_v_grammar);
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+static PyObject *__pyx_pf_5_cdec_7Decoder_6translate(struct __pyx_obj_5_cdec_Decoder *__pyx_v_self, PyObject *__pyx_v_sentence, PyObject *__pyx_v_grammar) {
+  PyObject *__pyx_v_input_str = 0;
+  BasicObserver __pyx_v_observer;
+  struct __pyx_obj_5_cdec_Hypergraph *__pyx_v_hg = 0;
+  PyObject *__pyx_r = NULL;
+  __Pyx_RefNannyDeclarations
+  PyObject *__pyx_t_1 = NULL;
+  int __pyx_t_2;
+  int __pyx_t_3;
+  int __pyx_t_4;
+  PyObject *__pyx_t_5 = NULL;
+  char *__pyx_t_6;
+  int __pyx_lineno = 0;
+  const char *__pyx_filename = NULL;
+  int __pyx_clineno = 0;
+  __Pyx_RefNannySetupContext("translate", 0);
+
+  /* "_cdec.pyx":94
+ *     def translate(self, sentence, grammar=None):
+ *         cdef bytes input_str
+ *         if isinstance(sentence, unicode) or isinstance(sentence, str):             # <<<<<<<<<<<<<<
+ *             input_str = as_str(sentence.strip())
+ *         elif isinstance(sentence, Lattice):
+ */
+  __pyx_t_1 = ((PyObject *)((PyObject*)(&PyUnicode_Type)));
+  __Pyx_INCREF(__pyx_t_1);
+  __pyx_t_2 = __Pyx_TypeCheck(__pyx_v_sentence, __pyx_t_1); 
+  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+  if (!__pyx_t_2) {
+    __pyx_t_1 = ((PyObject *)((PyObject*)(&PyString_Type)));
+    __Pyx_INCREF(__pyx_t_1);
+    __pyx_t_3 = __Pyx_TypeCheck(__pyx_v_sentence, __pyx_t_1); 
+    __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+    __pyx_t_4 = __pyx_t_3;
+  } else {
+    __pyx_t_4 = __pyx_t_2;
+  }
+  if (__pyx_t_4) {
+
+    /* "_cdec.pyx":95
+ *         cdef bytes input_str
+ *         if isinstance(sentence, unicode) or isinstance(sentence, str):
+ *             input_str = as_str(sentence.strip())             # <<<<<<<<<<<<<<
+ *         elif isinstance(sentence, Lattice):
+ *             input_str = str(sentence) # PLF format
+ */
+    __pyx_t_1 = PyObject_GetAttr(__pyx_v_sentence, __pyx_n_s__strip); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 95; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_1);
+    __pyx_t_5 = PyObject_Call(__pyx_t_1, ((PyObject *)__pyx_empty_tuple), NULL); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 95; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_5);
+    __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+    __pyx_t_1 = PyBytes_FromString(__pyx_f_5_cdec_as_str(__pyx_t_5, NULL)); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 95; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(((PyObject *)__pyx_t_1));
+    __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
+    __pyx_v_input_str = __pyx_t_1;
+    __pyx_t_1 = 0;
+    goto __pyx_L3;
+  }
+
+  /* "_cdec.pyx":96
+ *         if isinstance(sentence, unicode) or isinstance(sentence, str):
+ *             input_str = as_str(sentence.strip())
+ *         elif isinstance(sentence, Lattice):             # <<<<<<<<<<<<<<
+ *             input_str = str(sentence) # PLF format
+ *         else:
+ */
+  __pyx_t_1 = ((PyObject *)((PyObject*)__pyx_ptype_5_cdec_Lattice));
+  __Pyx_INCREF(__pyx_t_1);
+  __pyx_t_4 = __Pyx_TypeCheck(__pyx_v_sentence, __pyx_t_1); 
+  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+  if (__pyx_t_4) {
+
+    /* "_cdec.pyx":97
+ *             input_str = as_str(sentence.strip())
+ *         elif isinstance(sentence, Lattice):
+ *             input_str = str(sentence) # PLF format             # <<<<<<<<<<<<<<
+ *         else:
+ *             raise TypeError('Cannot translate input type %s' % type(sentence))
+ */
+    __pyx_t_1 = PyTuple_New(1); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 97; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_1);
+    __Pyx_INCREF(__pyx_v_sentence);
+    PyTuple_SET_ITEM(__pyx_t_1, 0, __pyx_v_sentence);
+    __Pyx_GIVEREF(__pyx_v_sentence);
+    __pyx_t_5 = PyObject_Call(((PyObject *)((PyObject*)(&PyString_Type))), ((PyObject *)__pyx_t_1), NULL); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 97; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_5);
+    __Pyx_DECREF(((PyObject *)__pyx_t_1)); __pyx_t_1 = 0;
+    if (!(likely(PyBytes_CheckExact(__pyx_t_5))||((__pyx_t_5) == Py_None)||(PyErr_Format(PyExc_TypeError, "Expected bytes, got %.200s", Py_TYPE(__pyx_t_5)->tp_name), 0))) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 97; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_v_input_str = ((PyObject*)__pyx_t_5);
+    __pyx_t_5 = 0;
+    goto __pyx_L3;
+  }
+  /*else*/ {
+
+    /* "_cdec.pyx":99
+ *             input_str = str(sentence) # PLF format
+ *         else:
+ *             raise TypeError('Cannot translate input type %s' % type(sentence))             # <<<<<<<<<<<<<<
+ *         if grammar:
+ *             if isinstance(grammar, str) or isinstance(grammar, unicode):
+ */
+    __pyx_t_5 = PyNumber_Remainder(((PyObject *)__pyx_kp_s_51), ((PyObject *)Py_TYPE(__pyx_v_sentence))); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 99; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(((PyObject *)__pyx_t_5));
+    __pyx_t_1 = PyTuple_New(1); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 99; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_1);
+    PyTuple_SET_ITEM(__pyx_t_1, 0, ((PyObject *)__pyx_t_5));
+    __Pyx_GIVEREF(((PyObject *)__pyx_t_5));
+    __pyx_t_5 = 0;
+    __pyx_t_5 = PyObject_Call(__pyx_builtin_TypeError, ((PyObject *)__pyx_t_1), NULL); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 99; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_5);
+    __Pyx_DECREF(((PyObject *)__pyx_t_1)); __pyx_t_1 = 0;
+    __Pyx_Raise(__pyx_t_5, 0, 0, 0);
+    __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
+    {__pyx_filename = __pyx_f[0]; __pyx_lineno = 99; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  }
+  __pyx_L3:;
+
+  /* "_cdec.pyx":100
+ *         else:
+ *             raise TypeError('Cannot translate input type %s' % type(sentence))
+ *         if grammar:             # <<<<<<<<<<<<<<
+ *             if isinstance(grammar, str) or isinstance(grammar, unicode):
+ *                 self.dec.AddSupplementalGrammarFromString(string(as_str(grammar)))
+ */
+  __pyx_t_4 = __Pyx_PyObject_IsTrue(__pyx_v_grammar); if (unlikely(__pyx_t_4 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 100; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (__pyx_t_4) {
+
+    /* "_cdec.pyx":101
+ *             raise TypeError('Cannot translate input type %s' % type(sentence))
+ *         if grammar:
+ *             if isinstance(grammar, str) or isinstance(grammar, unicode):             # <<<<<<<<<<<<<<
+ *                 self.dec.AddSupplementalGrammarFromString(string(as_str(grammar)))
+ *             else:
+ */
+    __pyx_t_5 = ((PyObject *)((PyObject*)(&PyString_Type)));
+    __Pyx_INCREF(__pyx_t_5);
+    __pyx_t_4 = __Pyx_TypeCheck(__pyx_v_grammar, __pyx_t_5); 
+    __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
+    if (!__pyx_t_4) {
+      __pyx_t_5 = ((PyObject *)((PyObject*)(&PyUnicode_Type)));
+      __Pyx_INCREF(__pyx_t_5);
+      __pyx_t_2 = __Pyx_TypeCheck(__pyx_v_grammar, __pyx_t_5); 
+      __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
+      __pyx_t_3 = __pyx_t_2;
+    } else {
+      __pyx_t_3 = __pyx_t_4;
+    }
+    if (__pyx_t_3) {
+
+      /* "_cdec.pyx":102
+ *         if grammar:
+ *             if isinstance(grammar, str) or isinstance(grammar, unicode):
+ *                 self.dec.AddSupplementalGrammarFromString(string(as_str(grammar)))             # <<<<<<<<<<<<<<
+ *             else:
+ *                 self.dec.AddSupplementalGrammar(TextGrammar(grammar).grammar[0])
+ */
+      __pyx_v_self->dec->AddSupplementalGrammarFromString(std::string(__pyx_f_5_cdec_as_str(__pyx_v_grammar, NULL)));
+      goto __pyx_L5;
+    }
+    /*else*/ {
+
+      /* "_cdec.pyx":104
+ *                 self.dec.AddSupplementalGrammarFromString(string(as_str(grammar)))
+ *             else:
+ *                 self.dec.AddSupplementalGrammar(TextGrammar(grammar).grammar[0])             # <<<<<<<<<<<<<<
+ *         cdef decoder.BasicObserver observer = decoder.BasicObserver()
+ *         self.dec.Decode(string(input_str), &observer)
+ */
+      __pyx_t_5 = PyTuple_New(1); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 104; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __Pyx_GOTREF(__pyx_t_5);
+      __Pyx_INCREF(__pyx_v_grammar);
+      PyTuple_SET_ITEM(__pyx_t_5, 0, __pyx_v_grammar);
+      __Pyx_GIVEREF(__pyx_v_grammar);
+      __pyx_t_1 = PyObject_Call(((PyObject *)((PyObject*)__pyx_ptype_5_cdec_TextGrammar)), ((PyObject *)__pyx_t_5), NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 104; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __Pyx_GOTREF(__pyx_t_1);
+      __Pyx_DECREF(((PyObject *)__pyx_t_5)); __pyx_t_5 = 0;
+      __pyx_v_self->dec->AddSupplementalGrammar((((struct __pyx_obj_5_cdec_TextGrammar *)__pyx_t_1)->__pyx_base.grammar[0]));
+      __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+    }
+    __pyx_L5:;
+    goto __pyx_L4;
+  }
+  __pyx_L4:;
+
+  /* "_cdec.pyx":105
+ *             else:
+ *                 self.dec.AddSupplementalGrammar(TextGrammar(grammar).grammar[0])
+ *         cdef decoder.BasicObserver observer = decoder.BasicObserver()             # <<<<<<<<<<<<<<
+ *         self.dec.Decode(string(input_str), &observer)
+ *         if observer.hypergraph == NULL:
+ */
+  __pyx_v_observer = BasicObserver();
+
+  /* "_cdec.pyx":106
+ *                 self.dec.AddSupplementalGrammar(TextGrammar(grammar).grammar[0])
+ *         cdef decoder.BasicObserver observer = decoder.BasicObserver()
+ *         self.dec.Decode(string(input_str), &observer)             # <<<<<<<<<<<<<<
+ *         if observer.hypergraph == NULL:
+ *             raise ParseFailed()
+ */
+  __pyx_t_6 = PyBytes_AsString(((PyObject *)__pyx_v_input_str)); if (unlikely((!__pyx_t_6) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 106; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_v_self->dec->Decode(std::string(__pyx_t_6), (&__pyx_v_observer));
+
+  /* "_cdec.pyx":107
+ *         cdef decoder.BasicObserver observer = decoder.BasicObserver()
+ *         self.dec.Decode(string(input_str), &observer)
+ *         if observer.hypergraph == NULL:             # <<<<<<<<<<<<<<
+ *             raise ParseFailed()
+ *         cdef Hypergraph hg = Hypergraph()
+ */
+  __pyx_t_3 = (__pyx_v_observer.hypergraph == NULL);
+  if (__pyx_t_3) {
+
+    /* "_cdec.pyx":108
+ *         self.dec.Decode(string(input_str), &observer)
+ *         if observer.hypergraph == NULL:
+ *             raise ParseFailed()             # <<<<<<<<<<<<<<
+ *         cdef Hypergraph hg = Hypergraph()
+ *         hg.hg = new hypergraph.Hypergraph(observer.hypergraph[0])
+ */
+    __pyx_t_1 = __Pyx_GetName(__pyx_m, __pyx_n_s__ParseFailed); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 108; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_1);
+    __pyx_t_5 = PyObject_Call(__pyx_t_1, ((PyObject *)__pyx_empty_tuple), NULL); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 108; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_5);
+    __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+    __Pyx_Raise(__pyx_t_5, 0, 0, 0);
+    __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
+    {__pyx_filename = __pyx_f[0]; __pyx_lineno = 108; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    goto __pyx_L6;
+  }
+  __pyx_L6:;
+
+  /* "_cdec.pyx":109
+ *         if observer.hypergraph == NULL:
+ *             raise ParseFailed()
+ *         cdef Hypergraph hg = Hypergraph()             # <<<<<<<<<<<<<<
+ *         hg.hg = new hypergraph.Hypergraph(observer.hypergraph[0])
+ *         return hg
+ */
+  __pyx_t_5 = PyObject_Call(((PyObject *)((PyObject*)__pyx_ptype_5_cdec_Hypergraph)), ((PyObject *)__pyx_empty_tuple), NULL); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 109; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_5);
+  __pyx_v_hg = ((struct __pyx_obj_5_cdec_Hypergraph *)__pyx_t_5);
+  __pyx_t_5 = 0;
+
+  /* "_cdec.pyx":110
+ *             raise ParseFailed()
+ *         cdef Hypergraph hg = Hypergraph()
+ *         hg.hg = new hypergraph.Hypergraph(observer.hypergraph[0])             # <<<<<<<<<<<<<<
+ *         return hg
+ */
+  __pyx_v_hg->hg = new Hypergraph((__pyx_v_observer.hypergraph[0]));
+
+  /* "_cdec.pyx":111
+ *         cdef Hypergraph hg = Hypergraph()
+ *         hg.hg = new hypergraph.Hypergraph(observer.hypergraph[0])
+ *         return hg             # <<<<<<<<<<<<<<
+ */
+  __Pyx_XDECREF(__pyx_r);
+  __Pyx_INCREF(((PyObject *)__pyx_v_hg));
+  __pyx_r = ((PyObject *)__pyx_v_hg);
+  goto __pyx_L0;
+
+  __pyx_r = Py_None; __Pyx_INCREF(Py_None);
+  goto __pyx_L0;
+  __pyx_L1_error:;
+  __Pyx_XDECREF(__pyx_t_1);
+  __Pyx_XDECREF(__pyx_t_5);
+  __Pyx_AddTraceback("_cdec.Decoder.translate", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __pyx_r = NULL;
+  __pyx_L0:;
+  __Pyx_XDECREF(__pyx_v_input_str);
+  __Pyx_XDECREF((PyObject *)__pyx_v_hg);
+  __Pyx_XGIVEREF(__pyx_r);
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+static PyObject *__pyx_tp_new_5_cdec_DenseVector(PyTypeObject *t, PyObject *a, PyObject *k) {
+  PyObject *o = (*t->tp_alloc)(t, 0);
+  if (!o) return 0;
+  return o;
+}
+
+static void __pyx_tp_dealloc_5_cdec_DenseVector(PyObject *o) {
+  (*Py_TYPE(o)->tp_free)(o);
+}
+static PyObject *__pyx_sq_item_5_cdec_DenseVector(PyObject *o, Py_ssize_t i) {
+  PyObject *r;
+  PyObject *x = PyInt_FromSsize_t(i); if(!x) return 0;
+  r = Py_TYPE(o)->tp_as_mapping->mp_subscript(o, x);
+  Py_DECREF(x);
+  return r;
+}
+
+static int __pyx_mp_ass_subscript_5_cdec_DenseVector(PyObject *o, PyObject *i, PyObject *v) {
+  if (v) {
+    return __pyx_pw_5_cdec_11DenseVector_5__setitem__(o, i, v);
+  }
+  else {
+    PyErr_Format(PyExc_NotImplementedError,
+      "Subscript deletion not supported by %s", Py_TYPE(o)->tp_name);
+    return -1;
+  }
+}
+
+static PyMethodDef __pyx_methods_5_cdec_DenseVector[] = {
+  {__Pyx_NAMESTR("dot"), (PyCFunction)__pyx_pw_5_cdec_11DenseVector_10dot, METH_O, __Pyx_DOCSTR(0)},
+  {__Pyx_NAMESTR("tosparse"), (PyCFunction)__pyx_pw_5_cdec_11DenseVector_12tosparse, METH_NOARGS, __Pyx_DOCSTR(0)},
+  {0, 0, 0, 0}
+};
+
+static PyNumberMethods __pyx_tp_as_number_DenseVector = {
+  0, /*nb_add*/
+  0, /*nb_subtract*/
+  0, /*nb_multiply*/
+  #if PY_MAJOR_VERSION < 3
+  0, /*nb_divide*/
+  #endif
+  0, /*nb_remainder*/
+  0, /*nb_divmod*/
+  0, /*nb_power*/
+  0, /*nb_negative*/
+  0, /*nb_positive*/
+  0, /*nb_absolute*/
+  0, /*nb_nonzero*/
+  0, /*nb_invert*/
+  0, /*nb_lshift*/
+  0, /*nb_rshift*/
+  0, /*nb_and*/
+  0, /*nb_xor*/
+  0, /*nb_or*/
+  #if PY_MAJOR_VERSION < 3
+  0, /*nb_coerce*/
+  #endif
+  0, /*nb_int*/
+  #if PY_MAJOR_VERSION < 3
+  0, /*nb_long*/
+  #else
+  0, /*reserved*/
+  #endif
+  0, /*nb_float*/
+  #if PY_MAJOR_VERSION < 3
+  0, /*nb_oct*/
+  #endif
+  #if PY_MAJOR_VERSION < 3
+  0, /*nb_hex*/
+  #endif
+  0, /*nb_inplace_add*/
+  0, /*nb_inplace_subtract*/
+  0, /*nb_inplace_multiply*/
+  #if PY_MAJOR_VERSION < 3
+  0, /*nb_inplace_divide*/
+  #endif
+  0, /*nb_inplace_remainder*/
+  0, /*nb_inplace_power*/
+  0, /*nb_inplace_lshift*/
+  0, /*nb_inplace_rshift*/
+  0, /*nb_inplace_and*/
+  0, /*nb_inplace_xor*/
+  0, /*nb_inplace_or*/
+  0, /*nb_floor_divide*/
+  0, /*nb_true_divide*/
+  0, /*nb_inplace_floor_divide*/
+  0, /*nb_inplace_true_divide*/
+  #if PY_VERSION_HEX >= 0x02050000
+  0, /*nb_index*/
+  #endif
+};
+
+static PySequenceMethods __pyx_tp_as_sequence_DenseVector = {
+  __pyx_pw_5_cdec_11DenseVector_1__len__, /*sq_length*/
+  0, /*sq_concat*/
+  0, /*sq_repeat*/
+  __pyx_sq_item_5_cdec_DenseVector, /*sq_item*/
+  0, /*sq_slice*/
+  0, /*sq_ass_item*/
+  0, /*sq_ass_slice*/
+  0, /*sq_contains*/
+  0, /*sq_inplace_concat*/
+  0, /*sq_inplace_repeat*/
+};
+
+static PyMappingMethods __pyx_tp_as_mapping_DenseVector = {
+  __pyx_pw_5_cdec_11DenseVector_1__len__, /*mp_length*/
+  __pyx_pw_5_cdec_11DenseVector_3__getitem__, /*mp_subscript*/
+  __pyx_mp_ass_subscript_5_cdec_DenseVector, /*mp_ass_subscript*/
+};
+
+static PyBufferProcs __pyx_tp_as_buffer_DenseVector = {
+  #if PY_MAJOR_VERSION < 3
+  0, /*bf_getreadbuffer*/
+  #endif
+  #if PY_MAJOR_VERSION < 3
+  0, /*bf_getwritebuffer*/
+  #endif
+  #if PY_MAJOR_VERSION < 3
+  0, /*bf_getsegcount*/
+  #endif
+  #if PY_MAJOR_VERSION < 3
+  0, /*bf_getcharbuffer*/
+  #endif
+  #if PY_VERSION_HEX >= 0x02060000
+  0, /*bf_getbuffer*/
+  #endif
+  #if PY_VERSION_HEX >= 0x02060000
+  0, /*bf_releasebuffer*/
+  #endif
+};
+
+static PyTypeObject __pyx_type_5_cdec_DenseVector = {
+  PyVarObject_HEAD_INIT(0, 0)
+  __Pyx_NAMESTR("_cdec.DenseVector"), /*tp_name*/
+  sizeof(struct __pyx_obj_5_cdec_DenseVector), /*tp_basicsize*/
+  0, /*tp_itemsize*/
+  __pyx_tp_dealloc_5_cdec_DenseVector, /*tp_dealloc*/
+  0, /*tp_print*/
+  0, /*tp_getattr*/
+  0, /*tp_setattr*/
+  #if PY_MAJOR_VERSION < 3
+  0, /*tp_compare*/
+  #else
+  0, /*reserved*/
+  #endif
+  0, /*tp_repr*/
+  &__pyx_tp_as_number_DenseVector, /*tp_as_number*/
+  &__pyx_tp_as_sequence_DenseVector, /*tp_as_sequence*/
+  &__pyx_tp_as_mapping_DenseVector, /*tp_as_mapping*/
+  0, /*tp_hash*/
+  0, /*tp_call*/
+  0, /*tp_str*/
+  0, /*tp_getattro*/
+  0, /*tp_setattro*/
+  &__pyx_tp_as_buffer_DenseVector, /*tp_as_buffer*/
+  Py_TPFLAGS_DEFAULT|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_BASETYPE, /*tp_flags*/
+  0, /*tp_doc*/
+  0, /*tp_traverse*/
+  0, /*tp_clear*/
+  0, /*tp_richcompare*/
+  0, /*tp_weaklistoffset*/
+  __pyx_pw_5_cdec_11DenseVector_7__iter__, /*tp_iter*/
+  0, /*tp_iternext*/
+  __pyx_methods_5_cdec_DenseVector, /*tp_methods*/
+  0, /*tp_members*/
+  0, /*tp_getset*/
+  0, /*tp_base*/
+  0, /*tp_dict*/
+  0, /*tp_descr_get*/
+  0, /*tp_descr_set*/
+  0, /*tp_dictoffset*/
+  0, /*tp_init*/
+  0, /*tp_alloc*/
+  __pyx_tp_new_5_cdec_DenseVector, /*tp_new*/
+  0, /*tp_free*/
+  0, /*tp_is_gc*/
+  0, /*tp_bases*/
+  0, /*tp_mro*/
+  0, /*tp_cache*/
+  0, /*tp_subclasses*/
+  0, /*tp_weaklist*/
+  0, /*tp_del*/
+  #if PY_VERSION_HEX >= 0x02060000
+  0, /*tp_version_tag*/
+  #endif
+};
+
+static PyObject *__pyx_tp_new_5_cdec_SparseVector(PyTypeObject *t, PyObject *a, PyObject *k) {
+  PyObject *o = (*t->tp_alloc)(t, 0);
+  if (!o) return 0;
+  return o;
+}
+
+static void __pyx_tp_dealloc_5_cdec_SparseVector(PyObject *o) {
+  {
+    PyObject *etype, *eval, *etb;
+    PyErr_Fetch(&etype, &eval, &etb);
+    ++Py_REFCNT(o);
+    __pyx_pw_5_cdec_12SparseVector_1__dealloc__(o);
+    if (PyErr_Occurred()) PyErr_WriteUnraisable(o);
+    --Py_REFCNT(o);
+    PyErr_Restore(etype, eval, etb);
+  }
+  (*Py_TYPE(o)->tp_free)(o);
+}
+static PyObject *__pyx_sq_item_5_cdec_SparseVector(PyObject *o, Py_ssize_t i) {
+  PyObject *r;
+  PyObject *x = PyInt_FromSsize_t(i); if(!x) return 0;
+  r = Py_TYPE(o)->tp_as_mapping->mp_subscript(o, x);
+  Py_DECREF(x);
+  return r;
+}
+
+static int __pyx_mp_ass_subscript_5_cdec_SparseVector(PyObject *o, PyObject *i, PyObject *v) {
+  if (v) {
+    return __pyx_pw_5_cdec_12SparseVector_7__setitem__(o, i, v);
+  }
+  else {
+    PyErr_Format(PyExc_NotImplementedError,
+      "Subscript deletion not supported by %s", Py_TYPE(o)->tp_name);
+    return -1;
+  }
+}
+
+static PyMethodDef __pyx_methods_5_cdec_SparseVector[] = {
+  {__Pyx_NAMESTR("copy"), (PyCFunction)__pyx_pw_5_cdec_12SparseVector_3copy, METH_NOARGS, __Pyx_DOCSTR(0)},
+  {__Pyx_NAMESTR("dot"), (PyCFunction)__pyx_pw_5_cdec_12SparseVector_12dot, METH_O, __Pyx_DOCSTR(0)},
+  {0, 0, 0, 0}
+};
+
+static PyNumberMethods __pyx_tp_as_number_SparseVector = {
+  __pyx_pw_5_cdec_12SparseVector_30__add__, /*nb_add*/
+  __pyx_pw_5_cdec_12SparseVector_32__sub__, /*nb_subtract*/
+  __pyx_pw_5_cdec_12SparseVector_34__mul__, /*nb_multiply*/
+  #if PY_MAJOR_VERSION < 3
+  __pyx_pw_5_cdec_12SparseVector_36__div__, /*nb_divide*/
+  #endif
+  0, /*nb_remainder*/
+  0, /*nb_divmod*/
+  0, /*nb_power*/
+  __pyx_pw_5_cdec_12SparseVector_20__neg__, /*nb_negative*/
+  0, /*nb_positive*/
+  0, /*nb_absolute*/
+  0, /*nb_nonzero*/
+  0, /*nb_invert*/
+  0, /*nb_lshift*/
+  0, /*nb_rshift*/
+  0, /*nb_and*/
+  0, /*nb_xor*/
+  0, /*nb_or*/
+  #if PY_MAJOR_VERSION < 3
+  0, /*nb_coerce*/
+  #endif
+  0, /*nb_int*/
+  #if PY_MAJOR_VERSION < 3
+  0, /*nb_long*/
+  #else
+  0, /*reserved*/
+  #endif
+  0, /*nb_float*/
+  #if PY_MAJOR_VERSION < 3
+  0, /*nb_oct*/
+  #endif
+  #if PY_MAJOR_VERSION < 3
+  0, /*nb_hex*/
+  #endif
+  __pyx_pw_5_cdec_12SparseVector_22__iadd__, /*nb_inplace_add*/
+  __pyx_pw_5_cdec_12SparseVector_24__isub__, /*nb_inplace_subtract*/
+  __pyx_pw_5_cdec_12SparseVector_26__imul__, /*nb_inplace_multiply*/
+  #if PY_MAJOR_VERSION < 3
+  __pyx_pw_5_cdec_12SparseVector_28__idiv__, /*nb_inplace_divide*/
+  #endif
+  0, /*nb_inplace_remainder*/
+  0, /*nb_inplace_power*/
+  0, /*nb_inplace_lshift*/
+  0, /*nb_inplace_rshift*/
+  0, /*nb_inplace_and*/
+  0, /*nb_inplace_xor*/
+  0, /*nb_inplace_or*/
+  0, /*nb_floor_divide*/
+  0, /*nb_true_divide*/
+  0, /*nb_inplace_floor_divide*/
+  0, /*nb_inplace_true_divide*/
+  #if PY_VERSION_HEX >= 0x02050000
+  0, /*nb_index*/
+  #endif
+};
+
+static PySequenceMethods __pyx_tp_as_sequence_SparseVector = {
+  __pyx_pw_5_cdec_12SparseVector_16__len__, /*sq_length*/
+  0, /*sq_concat*/
+  0, /*sq_repeat*/
+  __pyx_sq_item_5_cdec_SparseVector, /*sq_item*/
+  0, /*sq_slice*/
+  0, /*sq_ass_item*/
+  0, /*sq_ass_slice*/
+  __pyx_pw_5_cdec_12SparseVector_18__contains__, /*sq_contains*/
+  0, /*sq_inplace_concat*/
+  0, /*sq_inplace_repeat*/
+};
+
+static PyMappingMethods __pyx_tp_as_mapping_SparseVector = {
+  __pyx_pw_5_cdec_12SparseVector_16__len__, /*mp_length*/
+  __pyx_pw_5_cdec_12SparseVector_5__getitem__, /*mp_subscript*/
+  __pyx_mp_ass_subscript_5_cdec_SparseVector, /*mp_ass_subscript*/
+};
+
+static PyBufferProcs __pyx_tp_as_buffer_SparseVector = {
+  #if PY_MAJOR_VERSION < 3
+  0, /*bf_getreadbuffer*/
+  #endif
+  #if PY_MAJOR_VERSION < 3
+  0, /*bf_getwritebuffer*/
+  #endif
+  #if PY_MAJOR_VERSION < 3
+  0, /*bf_getsegcount*/
+  #endif
+  #if PY_MAJOR_VERSION < 3
+  0, /*bf_getcharbuffer*/
+  #endif
+  #if PY_VERSION_HEX >= 0x02060000
+  0, /*bf_getbuffer*/
+  #endif
+  #if PY_VERSION_HEX >= 0x02060000
+  0, /*bf_releasebuffer*/
+  #endif
+};
+
+static PyTypeObject __pyx_type_5_cdec_SparseVector = {
+  PyVarObject_HEAD_INIT(0, 0)
+  __Pyx_NAMESTR("_cdec.SparseVector"), /*tp_name*/
+  sizeof(struct __pyx_obj_5_cdec_SparseVector), /*tp_basicsize*/
+  0, /*tp_itemsize*/
+  __pyx_tp_dealloc_5_cdec_SparseVector, /*tp_dealloc*/
+  0, /*tp_print*/
+  0, /*tp_getattr*/
+  0, /*tp_setattr*/
+  #if PY_MAJOR_VERSION < 3
+  0, /*tp_compare*/
+  #else
+  0, /*reserved*/
+  #endif
+  0, /*tp_repr*/
+  &__pyx_tp_as_number_SparseVector, /*tp_as_number*/
+  &__pyx_tp_as_sequence_SparseVector, /*tp_as_sequence*/
+  &__pyx_tp_as_mapping_SparseVector, /*tp_as_mapping*/
+  0, /*tp_hash*/
+  0, /*tp_call*/
+  0, /*tp_str*/
+  0, /*tp_getattro*/
+  0, /*tp_setattro*/
+  &__pyx_tp_as_buffer_SparseVector, /*tp_as_buffer*/
+  Py_TPFLAGS_DEFAULT|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_BASETYPE, /*tp_flags*/
+  0, /*tp_doc*/
+  0, /*tp_traverse*/
+  0, /*tp_clear*/
+  __pyx_pw_5_cdec_12SparseVector_14__richcmp__, /*tp_richcompare*/
+  0, /*tp_weaklistoffset*/
+  __pyx_pw_5_cdec_12SparseVector_9__iter__, /*tp_iter*/
+  0, /*tp_iternext*/
+  __pyx_methods_5_cdec_SparseVector, /*tp_methods*/
+  0, /*tp_members*/
+  0, /*tp_getset*/
+  0, /*tp_base*/
+  0, /*tp_dict*/
+  0, /*tp_descr_get*/
+  0, /*tp_descr_set*/
+  0, /*tp_dictoffset*/
+  0, /*tp_init*/
+  0, /*tp_alloc*/
+  __pyx_tp_new_5_cdec_SparseVector, /*tp_new*/
+  0, /*tp_free*/
+  0, /*tp_is_gc*/
+  0, /*tp_bases*/
+  0, /*tp_mro*/
+  0, /*tp_cache*/
+  0, /*tp_subclasses*/
+  0, /*tp_weaklist*/
+  0, /*tp_del*/
+  #if PY_VERSION_HEX >= 0x02060000
+  0, /*tp_version_tag*/
+  #endif
+};
+
+static PyObject *__pyx_tp_new_5_cdec_NT(PyTypeObject *t, PyObject *a, PyObject *k) {
+  PyObject *o = (*t->tp_alloc)(t, 0);
+  if (!o) return 0;
+  return o;
+}
+
+static void __pyx_tp_dealloc_5_cdec_NT(PyObject *o) {
+  (*Py_TYPE(o)->tp_free)(o);
+}
+
+static PyObject *__pyx_getprop_5_cdec_2NT_cat(PyObject *o, void *x) {
+  return __pyx_pw_5_cdec_2NT_3cat_1__get__(o);
+}
+
+static int __pyx_setprop_5_cdec_2NT_cat(PyObject *o, PyObject *v, void *x) {
+  if (v) {
+    return __pyx_pw_5_cdec_2NT_3cat_3__set__(o, v);
+  }
+  else {
+    PyErr_SetString(PyExc_NotImplementedError, "__del__");
+    return -1;
+  }
+}
+
+static PyObject *__pyx_getprop_5_cdec_2NT_ref(PyObject *o, void *x) {
+  return __pyx_pw_5_cdec_2NT_3ref_1__get__(o);
+}
+
+static int __pyx_setprop_5_cdec_2NT_ref(PyObject *o, PyObject *v, void *x) {
+  if (v) {
+    return __pyx_pw_5_cdec_2NT_3ref_3__set__(o, v);
+  }
+  else {
+    PyErr_SetString(PyExc_NotImplementedError, "__del__");
+    return -1;
+  }
+}
+
+static PyMethodDef __pyx_methods_5_cdec_NT[] = {
+  {0, 0, 0, 0}
+};
+
+static struct PyGetSetDef __pyx_getsets_5_cdec_NT[] = {
+  {(char *)"cat", __pyx_getprop_5_cdec_2NT_cat, __pyx_setprop_5_cdec_2NT_cat, 0, 0},
+  {(char *)"ref", __pyx_getprop_5_cdec_2NT_ref, __pyx_setprop_5_cdec_2NT_ref, 0, 0},
+  {0, 0, 0, 0, 0}
+};
+
+static PyNumberMethods __pyx_tp_as_number_NT = {
+  0, /*nb_add*/
+  0, /*nb_subtract*/
+  0, /*nb_multiply*/
+  #if PY_MAJOR_VERSION < 3
+  0, /*nb_divide*/
+  #endif
+  0, /*nb_remainder*/
+  0, /*nb_divmod*/
+  0, /*nb_power*/
+  0, /*nb_negative*/
+  0, /*nb_positive*/
+  0, /*nb_absolute*/
+  0, /*nb_nonzero*/
+  0, /*nb_invert*/
+  0, /*nb_lshift*/
+  0, /*nb_rshift*/
+  0, /*nb_and*/
+  0, /*nb_xor*/
+  0, /*nb_or*/
+  #if PY_MAJOR_VERSION < 3
+  0, /*nb_coerce*/
+  #endif
+  0, /*nb_int*/
+  #if PY_MAJOR_VERSION < 3
+  0, /*nb_long*/
+  #else
+  0, /*reserved*/
+  #endif
+  0, /*nb_float*/
+  #if PY_MAJOR_VERSION < 3
+  0, /*nb_oct*/
+  #endif
+  #if PY_MAJOR_VERSION < 3
+  0, /*nb_hex*/
+  #endif
+  0, /*nb_inplace_add*/
+  0, /*nb_inplace_subtract*/
+  0, /*nb_inplace_multiply*/
+  #if PY_MAJOR_VERSION < 3
+  0, /*nb_inplace_divide*/
+  #endif
+  0, /*nb_inplace_remainder*/
+  0, /*nb_inplace_power*/
+  0, /*nb_inplace_lshift*/
+  0, /*nb_inplace_rshift*/
+  0, /*nb_inplace_and*/
+  0, /*nb_inplace_xor*/
+  0, /*nb_inplace_or*/
+  0, /*nb_floor_divide*/
+  0, /*nb_true_divide*/
+  0, /*nb_inplace_floor_divide*/
+  0, /*nb_inplace_true_divide*/
+  #if PY_VERSION_HEX >= 0x02050000
+  0, /*nb_index*/
+  #endif
+};
+
+static PySequenceMethods __pyx_tp_as_sequence_NT = {
+  0, /*sq_length*/
+  0, /*sq_concat*/
+  0, /*sq_repeat*/
+  0, /*sq_item*/
+  0, /*sq_slice*/
+  0, /*sq_ass_item*/
+  0, /*sq_ass_slice*/
+  0, /*sq_contains*/
+  0, /*sq_inplace_concat*/
+  0, /*sq_inplace_repeat*/
+};
+
+static PyMappingMethods __pyx_tp_as_mapping_NT = {
+  0, /*mp_length*/
+  0, /*mp_subscript*/
+  0, /*mp_ass_subscript*/
+};
+
+static PyBufferProcs __pyx_tp_as_buffer_NT = {
+  #if PY_MAJOR_VERSION < 3
+  0, /*bf_getreadbuffer*/
+  #endif
+  #if PY_MAJOR_VERSION < 3
+  0, /*bf_getwritebuffer*/
+  #endif
+  #if PY_MAJOR_VERSION < 3
+  0, /*bf_getsegcount*/
+  #endif
+  #if PY_MAJOR_VERSION < 3
+  0, /*bf_getcharbuffer*/
+  #endif
+  #if PY_VERSION_HEX >= 0x02060000
+  0, /*bf_getbuffer*/
+  #endif
+  #if PY_VERSION_HEX >= 0x02060000
+  0, /*bf_releasebuffer*/
+  #endif
+};
+
+static PyTypeObject __pyx_type_5_cdec_NT = {
+  PyVarObject_HEAD_INIT(0, 0)
+  __Pyx_NAMESTR("_cdec.NT"), /*tp_name*/
+  sizeof(struct __pyx_obj_5_cdec_NT), /*tp_basicsize*/
+  0, /*tp_itemsize*/
+  __pyx_tp_dealloc_5_cdec_NT, /*tp_dealloc*/
+  0, /*tp_print*/
+  0, /*tp_getattr*/
+  0, /*tp_setattr*/
+  #if PY_MAJOR_VERSION < 3
+  0, /*tp_compare*/
+  #else
+  0, /*reserved*/
+  #endif
+  0, /*tp_repr*/
+  &__pyx_tp_as_number_NT, /*tp_as_number*/
+  &__pyx_tp_as_sequence_NT, /*tp_as_sequence*/
+  &__pyx_tp_as_mapping_NT, /*tp_as_mapping*/
+  0, /*tp_hash*/
+  0, /*tp_call*/
+  __pyx_pw_5_cdec_2NT_3__str__, /*tp_str*/
+  0, /*tp_getattro*/
+  0, /*tp_setattro*/
+  &__pyx_tp_as_buffer_NT, /*tp_as_buffer*/
+  Py_TPFLAGS_DEFAULT|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_BASETYPE, /*tp_flags*/
+  0, /*tp_doc*/
+  0, /*tp_traverse*/
+  0, /*tp_clear*/
+  0, /*tp_richcompare*/
+  0, /*tp_weaklistoffset*/
+  0, /*tp_iter*/
+  0, /*tp_iternext*/
+  __pyx_methods_5_cdec_NT, /*tp_methods*/
+  0, /*tp_members*/
+  __pyx_getsets_5_cdec_NT, /*tp_getset*/
+  0, /*tp_base*/
+  0, /*tp_dict*/
+  0, /*tp_descr_get*/
+  0, /*tp_descr_set*/
+  0, /*tp_dictoffset*/
+  __pyx_pw_5_cdec_2NT_1__init__, /*tp_init*/
+  0, /*tp_alloc*/
+  __pyx_tp_new_5_cdec_NT, /*tp_new*/
+  0, /*tp_free*/
+  0, /*tp_is_gc*/
+  0, /*tp_bases*/
+  0, /*tp_mro*/
+  0, /*tp_cache*/
+  0, /*tp_subclasses*/
+  0, /*tp_weaklist*/
+  0, /*tp_del*/
+  #if PY_VERSION_HEX >= 0x02060000
+  0, /*tp_version_tag*/
+  #endif
+};
+
+static PyObject *__pyx_tp_new_5_cdec_NTRef(PyTypeObject *t, PyObject *a, PyObject *k) {
+  PyObject *o = (*t->tp_alloc)(t, 0);
+  if (!o) return 0;
+  return o;
+}
+
+static void __pyx_tp_dealloc_5_cdec_NTRef(PyObject *o) {
+  (*Py_TYPE(o)->tp_free)(o);
+}
+
+static PyObject *__pyx_getprop_5_cdec_5NTRef_ref(PyObject *o, void *x) {
+  return __pyx_pw_5_cdec_5NTRef_3ref_1__get__(o);
+}
+
+static int __pyx_setprop_5_cdec_5NTRef_ref(PyObject *o, PyObject *v, void *x) {
+  if (v) {
+    return __pyx_pw_5_cdec_5NTRef_3ref_3__set__(o, v);
+  }
+  else {
+    PyErr_SetString(PyExc_NotImplementedError, "__del__");
+    return -1;
+  }
+}
+
+static PyMethodDef __pyx_methods_5_cdec_NTRef[] = {
+  {0, 0, 0, 0}
+};
+
+static struct PyGetSetDef __pyx_getsets_5_cdec_NTRef[] = {
+  {(char *)"ref", __pyx_getprop_5_cdec_5NTRef_ref, __pyx_setprop_5_cdec_5NTRef_ref, 0, 0},
+  {0, 0, 0, 0, 0}
+};
+
+static PyNumberMethods __pyx_tp_as_number_NTRef = {
+  0, /*nb_add*/
+  0, /*nb_subtract*/
+  0, /*nb_multiply*/
+  #if PY_MAJOR_VERSION < 3
+  0, /*nb_divide*/
+  #endif
+  0, /*nb_remainder*/
+  0, /*nb_divmod*/
+  0, /*nb_power*/
+  0, /*nb_negative*/
+  0, /*nb_positive*/
+  0, /*nb_absolute*/
+  0, /*nb_nonzero*/
+  0, /*nb_invert*/
+  0, /*nb_lshift*/
+  0, /*nb_rshift*/
+  0, /*nb_and*/
+  0, /*nb_xor*/
+  0, /*nb_or*/
+  #if PY_MAJOR_VERSION < 3
+  0, /*nb_coerce*/
+  #endif
+  0, /*nb_int*/
+  #if PY_MAJOR_VERSION < 3
+  0, /*nb_long*/
+  #else
+  0, /*reserved*/
+  #endif
+  0, /*nb_float*/
+  #if PY_MAJOR_VERSION < 3
+  0, /*nb_oct*/
+  #endif
+  #if PY_MAJOR_VERSION < 3
+  0, /*nb_hex*/
+  #endif
+  0, /*nb_inplace_add*/
+  0, /*nb_inplace_subtract*/
+  0, /*nb_inplace_multiply*/
+  #if PY_MAJOR_VERSION < 3
+  0, /*nb_inplace_divide*/
+  #endif
+  0, /*nb_inplace_remainder*/
+  0, /*nb_inplace_power*/
+  0, /*nb_inplace_lshift*/
+  0, /*nb_inplace_rshift*/
+  0, /*nb_inplace_and*/
+  0, /*nb_inplace_xor*/
+  0, /*nb_inplace_or*/
+  0, /*nb_floor_divide*/
+  0, /*nb_true_divide*/
+  0, /*nb_inplace_floor_divide*/
+  0, /*nb_inplace_true_divide*/
+  #if PY_VERSION_HEX >= 0x02050000
+  0, /*nb_index*/
+  #endif
+};
+
+static PySequenceMethods __pyx_tp_as_sequence_NTRef = {
+  0, /*sq_length*/
+  0, /*sq_concat*/
+  0, /*sq_repeat*/
+  0, /*sq_item*/
+  0, /*sq_slice*/
+  0, /*sq_ass_item*/
+  0, /*sq_ass_slice*/
+  0, /*sq_contains*/
+  0, /*sq_inplace_concat*/
+  0, /*sq_inplace_repeat*/
+};
+
+static PyMappingMethods __pyx_tp_as_mapping_NTRef = {
+  0, /*mp_length*/
+  0, /*mp_subscript*/
+  0, /*mp_ass_subscript*/
+};
+
+static PyBufferProcs __pyx_tp_as_buffer_NTRef = {
+  #if PY_MAJOR_VERSION < 3
+  0, /*bf_getreadbuffer*/
+  #endif
+  #if PY_MAJOR_VERSION < 3
+  0, /*bf_getwritebuffer*/
+  #endif
+  #if PY_MAJOR_VERSION < 3
+  0, /*bf_getsegcount*/
+  #endif
+  #if PY_MAJOR_VERSION < 3
+  0, /*bf_getcharbuffer*/
+  #endif
+  #if PY_VERSION_HEX >= 0x02060000
+  0, /*bf_getbuffer*/
+  #endif
+  #if PY_VERSION_HEX >= 0x02060000
+  0, /*bf_releasebuffer*/
+  #endif
+};
+
+static PyTypeObject __pyx_type_5_cdec_NTRef = {
+  PyVarObject_HEAD_INIT(0, 0)
+  __Pyx_NAMESTR("_cdec.NTRef"), /*tp_name*/
+  sizeof(struct __pyx_obj_5_cdec_NTRef), /*tp_basicsize*/
+  0, /*tp_itemsize*/
+  __pyx_tp_dealloc_5_cdec_NTRef, /*tp_dealloc*/
+  0, /*tp_print*/
+  0, /*tp_getattr*/
+  0, /*tp_setattr*/
+  #if PY_MAJOR_VERSION < 3
+  0, /*tp_compare*/
+  #else
+  0, /*reserved*/
+  #endif
+  0, /*tp_repr*/
+  &__pyx_tp_as_number_NTRef, /*tp_as_number*/
+  &__pyx_tp_as_sequence_NTRef, /*tp_as_sequence*/
+  &__pyx_tp_as_mapping_NTRef, /*tp_as_mapping*/
+  0, /*tp_hash*/
+  0, /*tp_call*/
+  __pyx_pw_5_cdec_5NTRef_3__str__, /*tp_str*/
+  0, /*tp_getattro*/
+  0, /*tp_setattro*/
+  &__pyx_tp_as_buffer_NTRef, /*tp_as_buffer*/
+  Py_TPFLAGS_DEFAULT|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_BASETYPE, /*tp_flags*/
+  0, /*tp_doc*/
+  0, /*tp_traverse*/
+  0, /*tp_clear*/
+  0, /*tp_richcompare*/
+  0, /*tp_weaklistoffset*/
+  0, /*tp_iter*/
+  0, /*tp_iternext*/
+  __pyx_methods_5_cdec_NTRef, /*tp_methods*/
+  0, /*tp_members*/
+  __pyx_getsets_5_cdec_NTRef, /*tp_getset*/
+  0, /*tp_base*/
+  0, /*tp_dict*/
+  0, /*tp_descr_get*/
+  0, /*tp_descr_set*/
+  0, /*tp_dictoffset*/
+  __pyx_pw_5_cdec_5NTRef_1__init__, /*tp_init*/
+  0, /*tp_alloc*/
+  __pyx_tp_new_5_cdec_NTRef, /*tp_new*/
+  0, /*tp_free*/
+  0, /*tp_is_gc*/
+  0, /*tp_bases*/
+  0, /*tp_mro*/
+  0, /*tp_cache*/
+  0, /*tp_subclasses*/
+  0, /*tp_weaklist*/
+  0, /*tp_del*/
+  #if PY_VERSION_HEX >= 0x02060000
+  0, /*tp_version_tag*/
+  #endif
+};
+
+static PyObject *__pyx_tp_new_5_cdec_BaseTRule(PyTypeObject *t, PyObject *a, PyObject *k) {
+  PyObject *o = (*t->tp_alloc)(t, 0);
+  if (!o) return 0;
+  return o;
+}
+
+static void __pyx_tp_dealloc_5_cdec_BaseTRule(PyObject *o) {
+  {
+    PyObject *etype, *eval, *etb;
+    PyErr_Fetch(&etype, &eval, &etb);
+    ++Py_REFCNT(o);
+    __pyx_pw_5_cdec_9BaseTRule_1__dealloc__(o);
+    if (PyErr_Occurred()) PyErr_WriteUnraisable(o);
+    --Py_REFCNT(o);
+    PyErr_Restore(etype, eval, etb);
+  }
+  (*Py_TYPE(o)->tp_free)(o);
+}
+
+static PyObject *__pyx_getprop_5_cdec_9BaseTRule_arity(PyObject *o, void *x) {
+  return __pyx_pw_5_cdec_9BaseTRule_5arity_1__get__(o);
+}
+
+static PyObject *__pyx_getprop_5_cdec_9BaseTRule_f(PyObject *o, void *x) {
+  return __pyx_pw_5_cdec_9BaseTRule_1f_1__get__(o);
+}
+
+static int __pyx_setprop_5_cdec_9BaseTRule_f(PyObject *o, PyObject *v, void *x) {
+  if (v) {
+    return __pyx_pw_5_cdec_9BaseTRule_1f_3__set__(o, v);
+  }
+  else {
+    PyErr_SetString(PyExc_NotImplementedError, "__del__");
+    return -1;
+  }
+}
+
+static PyObject *__pyx_getprop_5_cdec_9BaseTRule_e(PyObject *o, void *x) {
+  return __pyx_pw_5_cdec_9BaseTRule_1e_1__get__(o);
+}
+
+static int __pyx_setprop_5_cdec_9BaseTRule_e(PyObject *o, PyObject *v, void *x) {
+  if (v) {
+    return __pyx_pw_5_cdec_9BaseTRule_1e_3__set__(o, v);
+  }
+  else {
+    PyErr_SetString(PyExc_NotImplementedError, "__del__");
+    return -1;
+  }
+}
+
+static PyObject *__pyx_getprop_5_cdec_9BaseTRule_a(PyObject *o, void *x) {
+  return __pyx_pw_5_cdec_9BaseTRule_1a_1__get__(o);
+}
+
+static int __pyx_setprop_5_cdec_9BaseTRule_a(PyObject *o, PyObject *v, void *x) {
+  if (v) {
+    return __pyx_pw_5_cdec_9BaseTRule_1a_4__set__(o, v);
+  }
+  else {
+    PyErr_SetString(PyExc_NotImplementedError, "__del__");
+    return -1;
+  }
+}
+
+static PyObject *__pyx_getprop_5_cdec_9BaseTRule_scores(PyObject *o, void *x) {
+  return __pyx_pw_5_cdec_9BaseTRule_6scores_1__get__(o);
+}
+
+static int __pyx_setprop_5_cdec_9BaseTRule_scores(PyObject *o, PyObject *v, void *x) {
+  if (v) {
+    return __pyx_pw_5_cdec_9BaseTRule_6scores_3__set__(o, v);
+  }
+  else {
+    PyErr_SetString(PyExc_NotImplementedError, "__del__");
+    return -1;
+  }
+}
+
+static PyObject *__pyx_getprop_5_cdec_9BaseTRule_lhs(PyObject *o, void *x) {
+  return __pyx_pw_5_cdec_9BaseTRule_3lhs_1__get__(o);
+}
+
+static int __pyx_setprop_5_cdec_9BaseTRule_lhs(PyObject *o, PyObject *v, void *x) {
+  if (v) {
+    return __pyx_pw_5_cdec_9BaseTRule_3lhs_3__set__(o, v);
+  }
+  else {
+    PyErr_SetString(PyExc_NotImplementedError, "__del__");
+    return -1;
+  }
+}
+
+static PyMethodDef __pyx_methods_5_cdec_BaseTRule[] = {
+  {0, 0, 0, 0}
+};
+
+static struct PyGetSetDef __pyx_getsets_5_cdec_BaseTRule[] = {
+  {(char *)"arity", __pyx_getprop_5_cdec_9BaseTRule_arity, 0, 0, 0},
+  {(char *)"f", __pyx_getprop_5_cdec_9BaseTRule_f, __pyx_setprop_5_cdec_9BaseTRule_f, 0, 0},
+  {(char *)"e", __pyx_getprop_5_cdec_9BaseTRule_e, __pyx_setprop_5_cdec_9BaseTRule_e, 0, 0},
+  {(char *)"a", __pyx_getprop_5_cdec_9BaseTRule_a, __pyx_setprop_5_cdec_9BaseTRule_a, 0, 0},
+  {(char *)"scores", __pyx_getprop_5_cdec_9BaseTRule_scores, __pyx_setprop_5_cdec_9BaseTRule_scores, 0, 0},
+  {(char *)"lhs", __pyx_getprop_5_cdec_9BaseTRule_lhs, __pyx_setprop_5_cdec_9BaseTRule_lhs, 0, 0},
+  {0, 0, 0, 0, 0}
+};
+
+static PyNumberMethods __pyx_tp_as_number_BaseTRule = {
+  0, /*nb_add*/
+  0, /*nb_subtract*/
+  0, /*nb_multiply*/
+  #if PY_MAJOR_VERSION < 3
+  0, /*nb_divide*/
+  #endif
+  0, /*nb_remainder*/
+  0, /*nb_divmod*/
+  0, /*nb_power*/
+  0, /*nb_negative*/
+  0, /*nb_positive*/
+  0, /*nb_absolute*/
+  0, /*nb_nonzero*/
+  0, /*nb_invert*/
+  0, /*nb_lshift*/
+  0, /*nb_rshift*/
+  0, /*nb_and*/
+  0, /*nb_xor*/
+  0, /*nb_or*/
+  #if PY_MAJOR_VERSION < 3
+  0, /*nb_coerce*/
+  #endif
+  0, /*nb_int*/
+  #if PY_MAJOR_VERSION < 3
+  0, /*nb_long*/
+  #else
+  0, /*reserved*/
+  #endif
+  0, /*nb_float*/
+  #if PY_MAJOR_VERSION < 3
+  0, /*nb_oct*/
+  #endif
+  #if PY_MAJOR_VERSION < 3
+  0, /*nb_hex*/
+  #endif
+  0, /*nb_inplace_add*/
+  0, /*nb_inplace_subtract*/
+  0, /*nb_inplace_multiply*/
+  #if PY_MAJOR_VERSION < 3
+  0, /*nb_inplace_divide*/
+  #endif
+  0, /*nb_inplace_remainder*/
+  0, /*nb_inplace_power*/
+  0, /*nb_inplace_lshift*/
+  0, /*nb_inplace_rshift*/
+  0, /*nb_inplace_and*/
+  0, /*nb_inplace_xor*/
+  0, /*nb_inplace_or*/
+  0, /*nb_floor_divide*/
+  0, /*nb_true_divide*/
+  0, /*nb_inplace_floor_divide*/
+  0, /*nb_inplace_true_divide*/
+  #if PY_VERSION_HEX >= 0x02050000
+  0, /*nb_index*/
+  #endif
+};
+
+static PySequenceMethods __pyx_tp_as_sequence_BaseTRule = {
+  0, /*sq_length*/
+  0, /*sq_concat*/
+  0, /*sq_repeat*/
+  0, /*sq_item*/
+  0, /*sq_slice*/
+  0, /*sq_ass_item*/
+  0, /*sq_ass_slice*/
+  0, /*sq_contains*/
+  0, /*sq_inplace_concat*/
+  0, /*sq_inplace_repeat*/
+};
+
+static PyMappingMethods __pyx_tp_as_mapping_BaseTRule = {
+  0, /*mp_length*/
+  0, /*mp_subscript*/
+  0, /*mp_ass_subscript*/
+};
+
+static PyBufferProcs __pyx_tp_as_buffer_BaseTRule = {
+  #if PY_MAJOR_VERSION < 3
+  0, /*bf_getreadbuffer*/
+  #endif
+  #if PY_MAJOR_VERSION < 3
+  0, /*bf_getwritebuffer*/
+  #endif
+  #if PY_MAJOR_VERSION < 3
+  0, /*bf_getsegcount*/
+  #endif
+  #if PY_MAJOR_VERSION < 3
+  0, /*bf_getcharbuffer*/
+  #endif
+  #if PY_VERSION_HEX >= 0x02060000
+  0, /*bf_getbuffer*/
+  #endif
+  #if PY_VERSION_HEX >= 0x02060000
+  0, /*bf_releasebuffer*/
+  #endif
+};
+
+static PyTypeObject __pyx_type_5_cdec_BaseTRule = {
+  PyVarObject_HEAD_INIT(0, 0)
+  __Pyx_NAMESTR("_cdec.BaseTRule"), /*tp_name*/
+  sizeof(struct __pyx_obj_5_cdec_BaseTRule), /*tp_basicsize*/
+  0, /*tp_itemsize*/
+  __pyx_tp_dealloc_5_cdec_BaseTRule, /*tp_dealloc*/
+  0, /*tp_print*/
+  0, /*tp_getattr*/
+  0, /*tp_setattr*/
+  #if PY_MAJOR_VERSION < 3
+  0, /*tp_compare*/
+  #else
+  0, /*reserved*/
+  #endif
+  0, /*tp_repr*/
+  &__pyx_tp_as_number_BaseTRule, /*tp_as_number*/
+  &__pyx_tp_as_sequence_BaseTRule, /*tp_as_sequence*/
+  &__pyx_tp_as_mapping_BaseTRule, /*tp_as_mapping*/
+  0, /*tp_hash*/
+  0, /*tp_call*/
+  __pyx_pw_5_cdec_9BaseTRule_3__str__, /*tp_str*/
+  0, /*tp_getattro*/
+  0, /*tp_setattro*/
+  &__pyx_tp_as_buffer_BaseTRule, /*tp_as_buffer*/
+  Py_TPFLAGS_DEFAULT|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_BASETYPE, /*tp_flags*/
+  0, /*tp_doc*/
+  0, /*tp_traverse*/
+  0, /*tp_clear*/
+  0, /*tp_richcompare*/
+  0, /*tp_weaklistoffset*/
+  0, /*tp_iter*/
+  0, /*tp_iternext*/
+  __pyx_methods_5_cdec_BaseTRule, /*tp_methods*/
+  0, /*tp_members*/
+  __pyx_getsets_5_cdec_BaseTRule, /*tp_getset*/
+  0, /*tp_base*/
+  0, /*tp_dict*/
+  0, /*tp_descr_get*/
+  0, /*tp_descr_set*/
+  0, /*tp_dictoffset*/
+  0, /*tp_init*/
+  0, /*tp_alloc*/
+  __pyx_tp_new_5_cdec_BaseTRule, /*tp_new*/
+  0, /*tp_free*/
+  0, /*tp_is_gc*/
+  0, /*tp_bases*/
+  0, /*tp_mro*/
+  0, /*tp_cache*/
+  0, /*tp_subclasses*/
+  0, /*tp_weaklist*/
+  0, /*tp_del*/
+  #if PY_VERSION_HEX >= 0x02060000
+  0, /*tp_version_tag*/
+  #endif
+};
+
+static PyObject *__pyx_tp_new_5_cdec_TRule(PyTypeObject *t, PyObject *a, PyObject *k) {
+  PyObject *o = __pyx_tp_new_5_cdec_BaseTRule(t, a, k);
+  if (!o) return 0;
+  if (__pyx_pw_5_cdec_5TRule_1__cinit__(o, a, k) < 0) {
+    Py_DECREF(o); o = 0;
+  }
+  return o;
+}
+
+static PyMethodDef __pyx_methods_5_cdec_TRule[] = {
+  {0, 0, 0, 0}
+};
+
+static PyNumberMethods __pyx_tp_as_number_TRule = {
+  0, /*nb_add*/
+  0, /*nb_subtract*/
+  0, /*nb_multiply*/
+  #if PY_MAJOR_VERSION < 3
+  0, /*nb_divide*/
+  #endif
+  0, /*nb_remainder*/
+  0, /*nb_divmod*/
+  0, /*nb_power*/
+  0, /*nb_negative*/
+  0, /*nb_positive*/
+  0, /*nb_absolute*/
+  0, /*nb_nonzero*/
+  0, /*nb_invert*/
+  0, /*nb_lshift*/
+  0, /*nb_rshift*/
+  0, /*nb_and*/
+  0, /*nb_xor*/
+  0, /*nb_or*/
+  #if PY_MAJOR_VERSION < 3
+  0, /*nb_coerce*/
+  #endif
+  0, /*nb_int*/
+  #if PY_MAJOR_VERSION < 3
+  0, /*nb_long*/
+  #else
+  0, /*reserved*/
+  #endif
+  0, /*nb_float*/
+  #if PY_MAJOR_VERSION < 3
+  0, /*nb_oct*/
+  #endif
+  #if PY_MAJOR_VERSION < 3
+  0, /*nb_hex*/
+  #endif
+  0, /*nb_inplace_add*/
+  0, /*nb_inplace_subtract*/
+  0, /*nb_inplace_multiply*/
+  #if PY_MAJOR_VERSION < 3
+  0, /*nb_inplace_divide*/
+  #endif
+  0, /*nb_inplace_remainder*/
+  0, /*nb_inplace_power*/
+  0, /*nb_inplace_lshift*/
+  0, /*nb_inplace_rshift*/
+  0, /*nb_inplace_and*/
+  0, /*nb_inplace_xor*/
+  0, /*nb_inplace_or*/
+  0, /*nb_floor_divide*/
+  0, /*nb_true_divide*/
+  0, /*nb_inplace_floor_divide*/
+  0, /*nb_inplace_true_divide*/
+  #if PY_VERSION_HEX >= 0x02050000
+  0, /*nb_index*/
+  #endif
+};
+
+static PySequenceMethods __pyx_tp_as_sequence_TRule = {
+  0, /*sq_length*/
+  0, /*sq_concat*/
+  0, /*sq_repeat*/
+  0, /*sq_item*/
+  0, /*sq_slice*/
+  0, /*sq_ass_item*/
+  0, /*sq_ass_slice*/
+  0, /*sq_contains*/
+  0, /*sq_inplace_concat*/
+  0, /*sq_inplace_repeat*/
+};
+
+static PyMappingMethods __pyx_tp_as_mapping_TRule = {
+  0, /*mp_length*/
+  0, /*mp_subscript*/
+  0, /*mp_ass_subscript*/
+};
+
+static PyBufferProcs __pyx_tp_as_buffer_TRule = {
+  #if PY_MAJOR_VERSION < 3
+  0, /*bf_getreadbuffer*/
+  #endif
+  #if PY_MAJOR_VERSION < 3
+  0, /*bf_getwritebuffer*/
+  #endif
+  #if PY_MAJOR_VERSION < 3
+  0, /*bf_getsegcount*/
+  #endif
+  #if PY_MAJOR_VERSION < 3
+  0, /*bf_getcharbuffer*/
+  #endif
+  #if PY_VERSION_HEX >= 0x02060000
+  0, /*bf_getbuffer*/
+  #endif
+  #if PY_VERSION_HEX >= 0x02060000
+  0, /*bf_releasebuffer*/
+  #endif
+};
+
+static PyTypeObject __pyx_type_5_cdec_TRule = {
+  PyVarObject_HEAD_INIT(0, 0)
+  __Pyx_NAMESTR("_cdec.TRule"), /*tp_name*/
+  sizeof(struct __pyx_obj_5_cdec_TRule), /*tp_basicsize*/
+  0, /*tp_itemsize*/
+  __pyx_tp_dealloc_5_cdec_BaseTRule, /*tp_dealloc*/
+  0, /*tp_print*/
+  0, /*tp_getattr*/
+  0, /*tp_setattr*/
+  #if PY_MAJOR_VERSION < 3
+  0, /*tp_compare*/
+  #else
+  0, /*reserved*/
+  #endif
+  0, /*tp_repr*/
+  &__pyx_tp_as_number_TRule, /*tp_as_number*/
+  &__pyx_tp_as_sequence_TRule, /*tp_as_sequence*/
+  &__pyx_tp_as_mapping_TRule, /*tp_as_mapping*/
+  0, /*tp_hash*/
+  0, /*tp_call*/
+  0, /*tp_str*/
+  0, /*tp_getattro*/
+  0, /*tp_setattro*/
+  &__pyx_tp_as_buffer_TRule, /*tp_as_buffer*/
+  Py_TPFLAGS_DEFAULT|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_BASETYPE, /*tp_flags*/
+  0, /*tp_doc*/
+  0, /*tp_traverse*/
+  0, /*tp_clear*/
+  0, /*tp_richcompare*/
+  0, /*tp_weaklistoffset*/
+  0, /*tp_iter*/
+  0, /*tp_iternext*/
+  __pyx_methods_5_cdec_TRule, /*tp_methods*/
+  0, /*tp_members*/
+  0, /*tp_getset*/
+  0, /*tp_base*/
+  0, /*tp_dict*/
+  0, /*tp_descr_get*/
+  0, /*tp_descr_set*/
+  0, /*tp_dictoffset*/
+  0, /*tp_init*/
+  0, /*tp_alloc*/
+  __pyx_tp_new_5_cdec_TRule, /*tp_new*/
+  0, /*tp_free*/
+  0, /*tp_is_gc*/
+  0, /*tp_bases*/
+  0, /*tp_mro*/
+  0, /*tp_cache*/
+  0, /*tp_subclasses*/
+  0, /*tp_weaklist*/
+  0, /*tp_del*/
+  #if PY_VERSION_HEX >= 0x02060000
+  0, /*tp_version_tag*/
+  #endif
+};
 
-  /* "_cdec.pyx":94
- *         if isinstance(sentence, unicode):
- *             inp = sentence.strip().encode('utf8')
- *         elif isinstance(sentence, str):             # <<<<<<<<<<<<<<
- *             inp = sentence.strip()
- *         elif isinstance(sentence, Lattice):
- */
-  __pyx_t_3 = ((PyObject *)((PyObject*)(&PyString_Type)));
-  __Pyx_INCREF(__pyx_t_3);
-  __pyx_t_2 = __Pyx_TypeCheck(__pyx_v_sentence, __pyx_t_3); 
-  __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
-  if (__pyx_t_2) {
+static PyObject *__pyx_tp_new_5_cdec_Grammar(PyTypeObject *t, PyObject *a, PyObject *k) {
+  PyObject *o = (*t->tp_alloc)(t, 0);
+  if (!o) return 0;
+  return o;
+}
 
-    /* "_cdec.pyx":95
- *             inp = sentence.strip().encode('utf8')
- *         elif isinstance(sentence, str):
- *             inp = sentence.strip()             # <<<<<<<<<<<<<<
- *         elif isinstance(sentence, Lattice):
- *             inp = str(sentence) # PLF format
- */
-    __pyx_t_3 = PyObject_GetAttr(__pyx_v_sentence, __pyx_n_s__strip); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 95; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-    __Pyx_GOTREF(__pyx_t_3);
-    __pyx_t_1 = PyObject_Call(__pyx_t_3, ((PyObject *)__pyx_empty_tuple), NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 95; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-    __Pyx_GOTREF(__pyx_t_1);
-    __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
-    __pyx_v_inp = __pyx_t_1;
-    __pyx_t_1 = 0;
-    goto __pyx_L3;
+static void __pyx_tp_dealloc_5_cdec_Grammar(PyObject *o) {
+  {
+    PyObject *etype, *eval, *etb;
+    PyErr_Fetch(&etype, &eval, &etb);
+    ++Py_REFCNT(o);
+    __pyx_pw_5_cdec_7Grammar_1__dealloc__(o);
+    if (PyErr_Occurred()) PyErr_WriteUnraisable(o);
+    --Py_REFCNT(o);
+    PyErr_Restore(etype, eval, etb);
   }
+  (*Py_TYPE(o)->tp_free)(o);
+}
 
-  /* "_cdec.pyx":96
- *         elif isinstance(sentence, str):
- *             inp = sentence.strip()
- *         elif isinstance(sentence, Lattice):             # <<<<<<<<<<<<<<
- *             inp = str(sentence) # PLF format
- *         else:
- */
-  __pyx_t_1 = ((PyObject *)((PyObject*)__pyx_ptype_5_cdec_Lattice));
-  __Pyx_INCREF(__pyx_t_1);
-  __pyx_t_2 = __Pyx_TypeCheck(__pyx_v_sentence, __pyx_t_1); 
-  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
-  if (__pyx_t_2) {
-
-    /* "_cdec.pyx":97
- *             inp = sentence.strip()
- *         elif isinstance(sentence, Lattice):
- *             inp = str(sentence) # PLF format             # <<<<<<<<<<<<<<
- *         else:
- *             raise TypeError('Cannot translate input type %s' % type(sentence))
- */
-    __pyx_t_1 = PyTuple_New(1); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 97; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-    __Pyx_GOTREF(__pyx_t_1);
-    __Pyx_INCREF(__pyx_v_sentence);
-    PyTuple_SET_ITEM(__pyx_t_1, 0, __pyx_v_sentence);
-    __Pyx_GIVEREF(__pyx_v_sentence);
-    __pyx_t_3 = PyObject_Call(((PyObject *)((PyObject*)(&PyString_Type))), ((PyObject *)__pyx_t_1), NULL); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 97; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-    __Pyx_GOTREF(__pyx_t_3);
-    __Pyx_DECREF(((PyObject *)__pyx_t_1)); __pyx_t_1 = 0;
-    __pyx_v_inp = __pyx_t_3;
-    __pyx_t_3 = 0;
-    goto __pyx_L3;
-  }
-  /*else*/ {
+static PyObject *__pyx_getprop_5_cdec_7Grammar_name(PyObject *o, void *x) {
+  return __pyx_pw_5_cdec_7Grammar_4name_1__get__(o);
+}
 
-    /* "_cdec.pyx":99
- *             inp = str(sentence) # PLF format
- *         else:
- *             raise TypeError('Cannot translate input type %s' % type(sentence))             # <<<<<<<<<<<<<<
- *         if grammar:
- *             self.dec.SetSentenceGrammarFromString(string(<char *> grammar))
- */
-    __pyx_t_3 = PyNumber_Remainder(((PyObject *)__pyx_kp_s_48), ((PyObject *)Py_TYPE(__pyx_v_sentence))); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 99; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-    __Pyx_GOTREF(((PyObject *)__pyx_t_3));
-    __pyx_t_1 = PyTuple_New(1); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 99; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-    __Pyx_GOTREF(__pyx_t_1);
-    PyTuple_SET_ITEM(__pyx_t_1, 0, ((PyObject *)__pyx_t_3));
-    __Pyx_GIVEREF(((PyObject *)__pyx_t_3));
-    __pyx_t_3 = 0;
-    __pyx_t_3 = PyObject_Call(__pyx_builtin_TypeError, ((PyObject *)__pyx_t_1), NULL); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 99; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-    __Pyx_GOTREF(__pyx_t_3);
-    __Pyx_DECREF(((PyObject *)__pyx_t_1)); __pyx_t_1 = 0;
-    __Pyx_Raise(__pyx_t_3, 0, 0, 0);
-    __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
-    {__pyx_filename = __pyx_f[0]; __pyx_lineno = 99; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+static int __pyx_setprop_5_cdec_7Grammar_name(PyObject *o, PyObject *v, void *x) {
+  if (v) {
+    return __pyx_pw_5_cdec_7Grammar_4name_3__set__(o, v);
   }
-  __pyx_L3:;
-
-  /* "_cdec.pyx":100
- *         else:
- *             raise TypeError('Cannot translate input type %s' % type(sentence))
- *         if grammar:             # <<<<<<<<<<<<<<
- *             self.dec.SetSentenceGrammarFromString(string(<char *> grammar))
- *         cdef decoder.BasicObserver observer = decoder.BasicObserver()
- */
-  __pyx_t_2 = __Pyx_PyObject_IsTrue(__pyx_v_grammar); if (unlikely(__pyx_t_2 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 100; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  if (__pyx_t_2) {
-
-    /* "_cdec.pyx":101
- *             raise TypeError('Cannot translate input type %s' % type(sentence))
- *         if grammar:
- *             self.dec.SetSentenceGrammarFromString(string(<char *> grammar))             # <<<<<<<<<<<<<<
- *         cdef decoder.BasicObserver observer = decoder.BasicObserver()
- *         self.dec.Decode(string(<char *>inp), &observer)
- */
-    __pyx_t_4 = PyBytes_AsString(__pyx_v_grammar); if (unlikely((!__pyx_t_4) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 101; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-    __pyx_v_self->dec->SetSentenceGrammarFromString(std::string(((char *)__pyx_t_4)));
-    goto __pyx_L4;
+  else {
+    PyErr_SetString(PyExc_NotImplementedError, "__del__");
+    return -1;
   }
-  __pyx_L4:;
-
-  /* "_cdec.pyx":102
- *         if grammar:
- *             self.dec.SetSentenceGrammarFromString(string(<char *> grammar))
- *         cdef decoder.BasicObserver observer = decoder.BasicObserver()             # <<<<<<<<<<<<<<
- *         self.dec.Decode(string(<char *>inp), &observer)
- *         if observer.hypergraph == NULL:
- */
-  __pyx_v_observer = BasicObserver();
-
-  /* "_cdec.pyx":103
- *             self.dec.SetSentenceGrammarFromString(string(<char *> grammar))
- *         cdef decoder.BasicObserver observer = decoder.BasicObserver()
- *         self.dec.Decode(string(<char *>inp), &observer)             # <<<<<<<<<<<<<<
- *         if observer.hypergraph == NULL:
- *             raise ParseFailed()
- */
-  __pyx_t_4 = PyBytes_AsString(__pyx_v_inp); if (unlikely((!__pyx_t_4) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 103; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __pyx_v_self->dec->Decode(std::string(((char *)__pyx_t_4)), (&__pyx_v_observer));
-
-  /* "_cdec.pyx":104
- *         cdef decoder.BasicObserver observer = decoder.BasicObserver()
- *         self.dec.Decode(string(<char *>inp), &observer)
- *         if observer.hypergraph == NULL:             # <<<<<<<<<<<<<<
- *             raise ParseFailed()
- *         cdef Hypergraph hg = Hypergraph()
- */
-  __pyx_t_2 = (__pyx_v_observer.hypergraph == NULL);
-  if (__pyx_t_2) {
+}
 
-    /* "_cdec.pyx":105
- *         self.dec.Decode(string(<char *>inp), &observer)
- *         if observer.hypergraph == NULL:
- *             raise ParseFailed()             # <<<<<<<<<<<<<<
- *         cdef Hypergraph hg = Hypergraph()
- *         hg.hg = new hypergraph.Hypergraph(observer.hypergraph[0])
- */
-    __pyx_t_3 = __Pyx_GetName(__pyx_m, __pyx_n_s__ParseFailed); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 105; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-    __Pyx_GOTREF(__pyx_t_3);
-    __pyx_t_1 = PyObject_Call(__pyx_t_3, ((PyObject *)__pyx_empty_tuple), NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 105; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-    __Pyx_GOTREF(__pyx_t_1);
-    __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
-    __Pyx_Raise(__pyx_t_1, 0, 0, 0);
-    __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
-    {__pyx_filename = __pyx_f[0]; __pyx_lineno = 105; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-    goto __pyx_L5;
-  }
-  __pyx_L5:;
+static PyMethodDef __pyx_methods_5_cdec_Grammar[] = {
+  {0, 0, 0, 0}
+};
 
-  /* "_cdec.pyx":106
- *         if observer.hypergraph == NULL:
- *             raise ParseFailed()
- *         cdef Hypergraph hg = Hypergraph()             # <<<<<<<<<<<<<<
- *         hg.hg = new hypergraph.Hypergraph(observer.hypergraph[0])
- *         return hg
- */
-  __pyx_t_1 = PyObject_Call(((PyObject *)((PyObject*)__pyx_ptype_5_cdec_Hypergraph)), ((PyObject *)__pyx_empty_tuple), NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 106; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __Pyx_GOTREF(__pyx_t_1);
-  __pyx_v_hg = ((struct __pyx_obj_5_cdec_Hypergraph *)__pyx_t_1);
-  __pyx_t_1 = 0;
+static struct PyGetSetDef __pyx_getsets_5_cdec_Grammar[] = {
+  {(char *)"name", __pyx_getprop_5_cdec_7Grammar_name, __pyx_setprop_5_cdec_7Grammar_name, 0, 0},
+  {0, 0, 0, 0, 0}
+};
 
-  /* "_cdec.pyx":107
- *             raise ParseFailed()
- *         cdef Hypergraph hg = Hypergraph()
- *         hg.hg = new hypergraph.Hypergraph(observer.hypergraph[0])             # <<<<<<<<<<<<<<
- *         return hg
- */
-  __pyx_v_hg->hg = new Hypergraph((__pyx_v_observer.hypergraph[0]));
+static PyNumberMethods __pyx_tp_as_number_Grammar = {
+  0, /*nb_add*/
+  0, /*nb_subtract*/
+  0, /*nb_multiply*/
+  #if PY_MAJOR_VERSION < 3
+  0, /*nb_divide*/
+  #endif
+  0, /*nb_remainder*/
+  0, /*nb_divmod*/
+  0, /*nb_power*/
+  0, /*nb_negative*/
+  0, /*nb_positive*/
+  0, /*nb_absolute*/
+  0, /*nb_nonzero*/
+  0, /*nb_invert*/
+  0, /*nb_lshift*/
+  0, /*nb_rshift*/
+  0, /*nb_and*/
+  0, /*nb_xor*/
+  0, /*nb_or*/
+  #if PY_MAJOR_VERSION < 3
+  0, /*nb_coerce*/
+  #endif
+  0, /*nb_int*/
+  #if PY_MAJOR_VERSION < 3
+  0, /*nb_long*/
+  #else
+  0, /*reserved*/
+  #endif
+  0, /*nb_float*/
+  #if PY_MAJOR_VERSION < 3
+  0, /*nb_oct*/
+  #endif
+  #if PY_MAJOR_VERSION < 3
+  0, /*nb_hex*/
+  #endif
+  0, /*nb_inplace_add*/
+  0, /*nb_inplace_subtract*/
+  0, /*nb_inplace_multiply*/
+  #if PY_MAJOR_VERSION < 3
+  0, /*nb_inplace_divide*/
+  #endif
+  0, /*nb_inplace_remainder*/
+  0, /*nb_inplace_power*/
+  0, /*nb_inplace_lshift*/
+  0, /*nb_inplace_rshift*/
+  0, /*nb_inplace_and*/
+  0, /*nb_inplace_xor*/
+  0, /*nb_inplace_or*/
+  0, /*nb_floor_divide*/
+  0, /*nb_true_divide*/
+  0, /*nb_inplace_floor_divide*/
+  0, /*nb_inplace_true_divide*/
+  #if PY_VERSION_HEX >= 0x02050000
+  0, /*nb_index*/
+  #endif
+};
 
-  /* "_cdec.pyx":108
- *         cdef Hypergraph hg = Hypergraph()
- *         hg.hg = new hypergraph.Hypergraph(observer.hypergraph[0])
- *         return hg             # <<<<<<<<<<<<<<
- */
-  __Pyx_XDECREF(__pyx_r);
-  __Pyx_INCREF(((PyObject *)__pyx_v_hg));
-  __pyx_r = ((PyObject *)__pyx_v_hg);
-  goto __pyx_L0;
+static PySequenceMethods __pyx_tp_as_sequence_Grammar = {
+  0, /*sq_length*/
+  0, /*sq_concat*/
+  0, /*sq_repeat*/
+  0, /*sq_item*/
+  0, /*sq_slice*/
+  0, /*sq_ass_item*/
+  0, /*sq_ass_slice*/
+  0, /*sq_contains*/
+  0, /*sq_inplace_concat*/
+  0, /*sq_inplace_repeat*/
+};
 
-  __pyx_r = Py_None; __Pyx_INCREF(Py_None);
-  goto __pyx_L0;
-  __pyx_L1_error:;
-  __Pyx_XDECREF(__pyx_t_1);
-  __Pyx_XDECREF(__pyx_t_3);
-  __Pyx_AddTraceback("_cdec.Decoder.translate", __pyx_clineno, __pyx_lineno, __pyx_filename);
-  __pyx_r = NULL;
-  __pyx_L0:;
-  __Pyx_XDECREF(__pyx_v_inp);
-  __Pyx_XDECREF((PyObject *)__pyx_v_hg);
-  __Pyx_XGIVEREF(__pyx_r);
-  __Pyx_RefNannyFinishContext();
-  return __pyx_r;
-}
+static PyMappingMethods __pyx_tp_as_mapping_Grammar = {
+  0, /*mp_length*/
+  0, /*mp_subscript*/
+  0, /*mp_ass_subscript*/
+};
 
-static PyObject *__pyx_tp_new_5_cdec_DenseVector(PyTypeObject *t, PyObject *a, PyObject *k) {
-  PyObject *o = (*t->tp_alloc)(t, 0);
-  if (!o) return 0;
-  return o;
-}
+static PyBufferProcs __pyx_tp_as_buffer_Grammar = {
+  #if PY_MAJOR_VERSION < 3
+  0, /*bf_getreadbuffer*/
+  #endif
+  #if PY_MAJOR_VERSION < 3
+  0, /*bf_getwritebuffer*/
+  #endif
+  #if PY_MAJOR_VERSION < 3
+  0, /*bf_getsegcount*/
+  #endif
+  #if PY_MAJOR_VERSION < 3
+  0, /*bf_getcharbuffer*/
+  #endif
+  #if PY_VERSION_HEX >= 0x02060000
+  0, /*bf_getbuffer*/
+  #endif
+  #if PY_VERSION_HEX >= 0x02060000
+  0, /*bf_releasebuffer*/
+  #endif
+};
 
-static void __pyx_tp_dealloc_5_cdec_DenseVector(PyObject *o) {
-  (*Py_TYPE(o)->tp_free)(o);
-}
-static PyObject *__pyx_sq_item_5_cdec_DenseVector(PyObject *o, Py_ssize_t i) {
-  PyObject *r;
-  PyObject *x = PyInt_FromSsize_t(i); if(!x) return 0;
-  r = Py_TYPE(o)->tp_as_mapping->mp_subscript(o, x);
-  Py_DECREF(x);
-  return r;
-}
+static PyTypeObject __pyx_type_5_cdec_Grammar = {
+  PyVarObject_HEAD_INIT(0, 0)
+  __Pyx_NAMESTR("_cdec.Grammar"), /*tp_name*/
+  sizeof(struct __pyx_obj_5_cdec_Grammar), /*tp_basicsize*/
+  0, /*tp_itemsize*/
+  __pyx_tp_dealloc_5_cdec_Grammar, /*tp_dealloc*/
+  0, /*tp_print*/
+  0, /*tp_getattr*/
+  0, /*tp_setattr*/
+  #if PY_MAJOR_VERSION < 3
+  0, /*tp_compare*/
+  #else
+  0, /*reserved*/
+  #endif
+  0, /*tp_repr*/
+  &__pyx_tp_as_number_Grammar, /*tp_as_number*/
+  &__pyx_tp_as_sequence_Grammar, /*tp_as_sequence*/
+  &__pyx_tp_as_mapping_Grammar, /*tp_as_mapping*/
+  0, /*tp_hash*/
+  0, /*tp_call*/
+  0, /*tp_str*/
+  0, /*tp_getattro*/
+  0, /*tp_setattro*/
+  &__pyx_tp_as_buffer_Grammar, /*tp_as_buffer*/
+  Py_TPFLAGS_DEFAULT|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_BASETYPE, /*tp_flags*/
+  0, /*tp_doc*/
+  0, /*tp_traverse*/
+  0, /*tp_clear*/
+  0, /*tp_richcompare*/
+  0, /*tp_weaklistoffset*/
+  __pyx_pw_5_cdec_7Grammar_3__iter__, /*tp_iter*/
+  0, /*tp_iternext*/
+  __pyx_methods_5_cdec_Grammar, /*tp_methods*/
+  0, /*tp_members*/
+  __pyx_getsets_5_cdec_Grammar, /*tp_getset*/
+  0, /*tp_base*/
+  0, /*tp_dict*/
+  0, /*tp_descr_get*/
+  0, /*tp_descr_set*/
+  0, /*tp_dictoffset*/
+  0, /*tp_init*/
+  0, /*tp_alloc*/
+  __pyx_tp_new_5_cdec_Grammar, /*tp_new*/
+  0, /*tp_free*/
+  0, /*tp_is_gc*/
+  0, /*tp_bases*/
+  0, /*tp_mro*/
+  0, /*tp_cache*/
+  0, /*tp_subclasses*/
+  0, /*tp_weaklist*/
+  0, /*tp_del*/
+  #if PY_VERSION_HEX >= 0x02060000
+  0, /*tp_version_tag*/
+  #endif
+};
 
-static int __pyx_mp_ass_subscript_5_cdec_DenseVector(PyObject *o, PyObject *i, PyObject *v) {
-  if (v) {
-    return __pyx_pw_5_cdec_11DenseVector_5__setitem__(o, i, v);
-  }
-  else {
-    PyErr_Format(PyExc_NotImplementedError,
-      "Subscript deletion not supported by %s", Py_TYPE(o)->tp_name);
-    return -1;
+static PyObject *__pyx_tp_new_5_cdec_TextGrammar(PyTypeObject *t, PyObject *a, PyObject *k) {
+  PyObject *o = __pyx_tp_new_5_cdec_Grammar(t, a, k);
+  if (!o) return 0;
+  if (__pyx_pw_5_cdec_11TextGrammar_1__cinit__(o, a, k) < 0) {
+    Py_DECREF(o); o = 0;
   }
+  return o;
 }
 
-static PyMethodDef __pyx_methods_5_cdec_DenseVector[] = {
-  {__Pyx_NAMESTR("dot"), (PyCFunction)__pyx_pw_5_cdec_11DenseVector_10dot, METH_O, __Pyx_DOCSTR(0)},
-  {__Pyx_NAMESTR("tosparse"), (PyCFunction)__pyx_pw_5_cdec_11DenseVector_12tosparse, METH_NOARGS, __Pyx_DOCSTR(0)},
+static PyMethodDef __pyx_methods_5_cdec_TextGrammar[] = {
   {0, 0, 0, 0}
 };
 
-static PyNumberMethods __pyx_tp_as_number_DenseVector = {
+static PyNumberMethods __pyx_tp_as_number_TextGrammar = {
   0, /*nb_add*/
   0, /*nb_subtract*/
   0, /*nb_multiply*/
@@ -14101,11 +18057,11 @@ static PyNumberMethods __pyx_tp_as_number_DenseVector = {
   #endif
 };
 
-static PySequenceMethods __pyx_tp_as_sequence_DenseVector = {
-  __pyx_pw_5_cdec_11DenseVector_1__len__, /*sq_length*/
+static PySequenceMethods __pyx_tp_as_sequence_TextGrammar = {
+  0, /*sq_length*/
   0, /*sq_concat*/
   0, /*sq_repeat*/
-  __pyx_sq_item_5_cdec_DenseVector, /*sq_item*/
+  0, /*sq_item*/
   0, /*sq_slice*/
   0, /*sq_ass_item*/
   0, /*sq_ass_slice*/
@@ -14114,13 +18070,13 @@ static PySequenceMethods __pyx_tp_as_sequence_DenseVector = {
   0, /*sq_inplace_repeat*/
 };
 
-static PyMappingMethods __pyx_tp_as_mapping_DenseVector = {
-  __pyx_pw_5_cdec_11DenseVector_1__len__, /*mp_length*/
-  __pyx_pw_5_cdec_11DenseVector_3__getitem__, /*mp_subscript*/
-  __pyx_mp_ass_subscript_5_cdec_DenseVector, /*mp_ass_subscript*/
+static PyMappingMethods __pyx_tp_as_mapping_TextGrammar = {
+  0, /*mp_length*/
+  0, /*mp_subscript*/
+  0, /*mp_ass_subscript*/
 };
 
-static PyBufferProcs __pyx_tp_as_buffer_DenseVector = {
+static PyBufferProcs __pyx_tp_as_buffer_TextGrammar = {
   #if PY_MAJOR_VERSION < 3
   0, /*bf_getreadbuffer*/
   #endif
@@ -14141,12 +18097,12 @@ static PyBufferProcs __pyx_tp_as_buffer_DenseVector = {
   #endif
 };
 
-static PyTypeObject __pyx_type_5_cdec_DenseVector = {
+static PyTypeObject __pyx_type_5_cdec_TextGrammar = {
   PyVarObject_HEAD_INIT(0, 0)
-  __Pyx_NAMESTR("_cdec.DenseVector"), /*tp_name*/
-  sizeof(struct __pyx_obj_5_cdec_DenseVector), /*tp_basicsize*/
+  __Pyx_NAMESTR("_cdec.TextGrammar"), /*tp_name*/
+  sizeof(struct __pyx_obj_5_cdec_TextGrammar), /*tp_basicsize*/
   0, /*tp_itemsize*/
-  __pyx_tp_dealloc_5_cdec_DenseVector, /*tp_dealloc*/
+  __pyx_tp_dealloc_5_cdec_Grammar, /*tp_dealloc*/
   0, /*tp_print*/
   0, /*tp_getattr*/
   0, /*tp_setattr*/
@@ -14156,24 +18112,24 @@ static PyTypeObject __pyx_type_5_cdec_DenseVector = {
   0, /*reserved*/
   #endif
   0, /*tp_repr*/
-  &__pyx_tp_as_number_DenseVector, /*tp_as_number*/
-  &__pyx_tp_as_sequence_DenseVector, /*tp_as_sequence*/
-  &__pyx_tp_as_mapping_DenseVector, /*tp_as_mapping*/
+  &__pyx_tp_as_number_TextGrammar, /*tp_as_number*/
+  &__pyx_tp_as_sequence_TextGrammar, /*tp_as_sequence*/
+  &__pyx_tp_as_mapping_TextGrammar, /*tp_as_mapping*/
   0, /*tp_hash*/
   0, /*tp_call*/
   0, /*tp_str*/
   0, /*tp_getattro*/
   0, /*tp_setattro*/
-  &__pyx_tp_as_buffer_DenseVector, /*tp_as_buffer*/
+  &__pyx_tp_as_buffer_TextGrammar, /*tp_as_buffer*/
   Py_TPFLAGS_DEFAULT|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_BASETYPE, /*tp_flags*/
   0, /*tp_doc*/
   0, /*tp_traverse*/
   0, /*tp_clear*/
   0, /*tp_richcompare*/
   0, /*tp_weaklistoffset*/
-  __pyx_pw_5_cdec_11DenseVector_7__iter__, /*tp_iter*/
+  0, /*tp_iter*/
   0, /*tp_iternext*/
-  __pyx_methods_5_cdec_DenseVector, /*tp_methods*/
+  __pyx_methods_5_cdec_TextGrammar, /*tp_methods*/
   0, /*tp_members*/
   0, /*tp_getset*/
   0, /*tp_base*/
@@ -14183,7 +18139,7 @@ static PyTypeObject __pyx_type_5_cdec_DenseVector = {
   0, /*tp_dictoffset*/
   0, /*tp_init*/
   0, /*tp_alloc*/
-  __pyx_tp_new_5_cdec_DenseVector, /*tp_new*/
+  __pyx_tp_new_5_cdec_TextGrammar, /*tp_new*/
   0, /*tp_free*/
   0, /*tp_is_gc*/
   0, /*tp_bases*/
@@ -14197,60 +18153,77 @@ static PyTypeObject __pyx_type_5_cdec_DenseVector = {
   #endif
 };
 
-static PyObject *__pyx_tp_new_5_cdec_SparseVector(PyTypeObject *t, PyObject *a, PyObject *k) {
+static PyObject *__pyx_tp_new_5_cdec_Hypergraph(PyTypeObject *t, PyObject *a, PyObject *k) {
   PyObject *o = (*t->tp_alloc)(t, 0);
   if (!o) return 0;
   return o;
 }
 
-static void __pyx_tp_dealloc_5_cdec_SparseVector(PyObject *o) {
+static void __pyx_tp_dealloc_5_cdec_Hypergraph(PyObject *o) {
   {
     PyObject *etype, *eval, *etb;
     PyErr_Fetch(&etype, &eval, &etb);
     ++Py_REFCNT(o);
-    __pyx_pw_5_cdec_12SparseVector_1__dealloc__(o);
+    __pyx_pw_5_cdec_10Hypergraph_1__dealloc__(o);
     if (PyErr_Occurred()) PyErr_WriteUnraisable(o);
     --Py_REFCNT(o);
     PyErr_Restore(etype, eval, etb);
   }
   (*Py_TYPE(o)->tp_free)(o);
 }
-static PyObject *__pyx_sq_item_5_cdec_SparseVector(PyObject *o, Py_ssize_t i) {
-  PyObject *r;
-  PyObject *x = PyInt_FromSsize_t(i); if(!x) return 0;
-  r = Py_TYPE(o)->tp_as_mapping->mp_subscript(o, x);
-  Py_DECREF(x);
-  return r;
+
+static PyObject *__pyx_getprop_5_cdec_10Hypergraph_edges(PyObject *o, void *x) {
+  return __pyx_pw_5_cdec_10Hypergraph_5edges_1__get__(o);
 }
 
-static int __pyx_mp_ass_subscript_5_cdec_SparseVector(PyObject *o, PyObject *i, PyObject *v) {
-  if (v) {
-    return __pyx_pw_5_cdec_12SparseVector_7__setitem__(o, i, v);
-  }
-  else {
-    PyErr_Format(PyExc_NotImplementedError,
-      "Subscript deletion not supported by %s", Py_TYPE(o)->tp_name);
-    return -1;
-  }
+static PyObject *__pyx_getprop_5_cdec_10Hypergraph_nodes(PyObject *o, void *x) {
+  return __pyx_pw_5_cdec_10Hypergraph_5nodes_1__get__(o);
 }
 
-static PyMethodDef __pyx_methods_5_cdec_SparseVector[] = {
-  {__Pyx_NAMESTR("copy"), (PyCFunction)__pyx_pw_5_cdec_12SparseVector_3copy, METH_NOARGS, __Pyx_DOCSTR(0)},
-  {__Pyx_NAMESTR("dot"), (PyCFunction)__pyx_pw_5_cdec_12SparseVector_12dot, METH_O, __Pyx_DOCSTR(0)},
+static PyObject *__pyx_getprop_5_cdec_10Hypergraph_goal(PyObject *o, void *x) {
+  return __pyx_pw_5_cdec_10Hypergraph_4goal_1__get__(o);
+}
+
+static PyObject *__pyx_getprop_5_cdec_10Hypergraph_npaths(PyObject *o, void *x) {
+  return __pyx_pw_5_cdec_10Hypergraph_6npaths_1__get__(o);
+}
+
+static PyMethodDef __pyx_methods_5_cdec_Hypergraph[] = {
+  {__Pyx_NAMESTR("viterbi"), (PyCFunction)__pyx_pw_5_cdec_10Hypergraph_3viterbi, METH_NOARGS, __Pyx_DOCSTR(0)},
+  {__Pyx_NAMESTR("viterbi_trees"), (PyCFunction)__pyx_pw_5_cdec_10Hypergraph_5viterbi_trees, METH_NOARGS, __Pyx_DOCSTR(0)},
+  {__Pyx_NAMESTR("viterbi_features"), (PyCFunction)__pyx_pw_5_cdec_10Hypergraph_7viterbi_features, METH_NOARGS, __Pyx_DOCSTR(0)},
+  {__Pyx_NAMESTR("viterbi_joshua"), (PyCFunction)__pyx_pw_5_cdec_10Hypergraph_9viterbi_joshua, METH_NOARGS, __Pyx_DOCSTR(0)},
+  {__Pyx_NAMESTR("kbest"), (PyCFunction)__pyx_pw_5_cdec_10Hypergraph_11kbest, METH_O, __Pyx_DOCSTR(0)},
+  {__Pyx_NAMESTR("kbest_trees"), (PyCFunction)__pyx_pw_5_cdec_10Hypergraph_14kbest_trees, METH_O, __Pyx_DOCSTR(0)},
+  {__Pyx_NAMESTR("kbest_features"), (PyCFunction)__pyx_pw_5_cdec_10Hypergraph_17kbest_features, METH_O, __Pyx_DOCSTR(0)},
+  {__Pyx_NAMESTR("sample"), (PyCFunction)__pyx_pw_5_cdec_10Hypergraph_20sample, METH_O, __Pyx_DOCSTR(0)},
+  {__Pyx_NAMESTR("intersect"), (PyCFunction)__pyx_pw_5_cdec_10Hypergraph_23intersect, METH_O, __Pyx_DOCSTR(0)},
+  {__Pyx_NAMESTR("prune"), (PyCFunction)__pyx_pw_5_cdec_10Hypergraph_25prune, METH_VARARGS|METH_KEYWORDS, __Pyx_DOCSTR(0)},
+  {__Pyx_NAMESTR("lattice"), (PyCFunction)__pyx_pw_5_cdec_10Hypergraph_27lattice, METH_NOARGS, __Pyx_DOCSTR(0)},
+  {__Pyx_NAMESTR("reweight"), (PyCFunction)__pyx_pw_5_cdec_10Hypergraph_29reweight, METH_O, __Pyx_DOCSTR(0)},
+  {__Pyx_NAMESTR("inside_outside"), (PyCFunction)__pyx_pw_5_cdec_10Hypergraph_31inside_outside, METH_NOARGS, __Pyx_DOCSTR(0)},
   {0, 0, 0, 0}
 };
 
-static PyNumberMethods __pyx_tp_as_number_SparseVector = {
-  __pyx_pw_5_cdec_12SparseVector_30__add__, /*nb_add*/
-  __pyx_pw_5_cdec_12SparseVector_32__sub__, /*nb_subtract*/
-  __pyx_pw_5_cdec_12SparseVector_34__mul__, /*nb_multiply*/
+static struct PyGetSetDef __pyx_getsets_5_cdec_Hypergraph[] = {
+  {(char *)"edges", __pyx_getprop_5_cdec_10Hypergraph_edges, 0, 0, 0},
+  {(char *)"nodes", __pyx_getprop_5_cdec_10Hypergraph_nodes, 0, 0, 0},
+  {(char *)"goal", __pyx_getprop_5_cdec_10Hypergraph_goal, 0, 0, 0},
+  {(char *)"npaths", __pyx_getprop_5_cdec_10Hypergraph_npaths, 0, 0, 0},
+  {0, 0, 0, 0, 0}
+};
+
+static PyNumberMethods __pyx_tp_as_number_Hypergraph = {
+  0, /*nb_add*/
+  0, /*nb_subtract*/
+  0, /*nb_multiply*/
   #if PY_MAJOR_VERSION < 3
-  __pyx_pw_5_cdec_12SparseVector_36__div__, /*nb_divide*/
+  0, /*nb_divide*/
   #endif
   0, /*nb_remainder*/
   0, /*nb_divmod*/
   0, /*nb_power*/
-  __pyx_pw_5_cdec_12SparseVector_20__neg__, /*nb_negative*/
+  0, /*nb_negative*/
   0, /*nb_positive*/
   0, /*nb_absolute*/
   0, /*nb_nonzero*/
@@ -14276,11 +18249,11 @@ static PyNumberMethods __pyx_tp_as_number_SparseVector = {
   #if PY_MAJOR_VERSION < 3
   0, /*nb_hex*/
   #endif
-  __pyx_pw_5_cdec_12SparseVector_22__iadd__, /*nb_inplace_add*/
-  __pyx_pw_5_cdec_12SparseVector_24__isub__, /*nb_inplace_subtract*/
-  __pyx_pw_5_cdec_12SparseVector_26__imul__, /*nb_inplace_multiply*/
+  0, /*nb_inplace_add*/
+  0, /*nb_inplace_subtract*/
+  0, /*nb_inplace_multiply*/
   #if PY_MAJOR_VERSION < 3
-  __pyx_pw_5_cdec_12SparseVector_28__idiv__, /*nb_inplace_divide*/
+  0, /*nb_inplace_divide*/
   #endif
   0, /*nb_inplace_remainder*/
   0, /*nb_inplace_power*/
@@ -14298,26 +18271,26 @@ static PyNumberMethods __pyx_tp_as_number_SparseVector = {
   #endif
 };
 
-static PySequenceMethods __pyx_tp_as_sequence_SparseVector = {
-  __pyx_pw_5_cdec_12SparseVector_16__len__, /*sq_length*/
+static PySequenceMethods __pyx_tp_as_sequence_Hypergraph = {
+  0, /*sq_length*/
   0, /*sq_concat*/
   0, /*sq_repeat*/
-  __pyx_sq_item_5_cdec_SparseVector, /*sq_item*/
+  0, /*sq_item*/
   0, /*sq_slice*/
   0, /*sq_ass_item*/
   0, /*sq_ass_slice*/
-  __pyx_pw_5_cdec_12SparseVector_18__contains__, /*sq_contains*/
+  0, /*sq_contains*/
   0, /*sq_inplace_concat*/
   0, /*sq_inplace_repeat*/
 };
 
-static PyMappingMethods __pyx_tp_as_mapping_SparseVector = {
-  __pyx_pw_5_cdec_12SparseVector_16__len__, /*mp_length*/
-  __pyx_pw_5_cdec_12SparseVector_5__getitem__, /*mp_subscript*/
-  __pyx_mp_ass_subscript_5_cdec_SparseVector, /*mp_ass_subscript*/
+static PyMappingMethods __pyx_tp_as_mapping_Hypergraph = {
+  0, /*mp_length*/
+  0, /*mp_subscript*/
+  0, /*mp_ass_subscript*/
 };
 
-static PyBufferProcs __pyx_tp_as_buffer_SparseVector = {
+static PyBufferProcs __pyx_tp_as_buffer_Hypergraph = {
   #if PY_MAJOR_VERSION < 3
   0, /*bf_getreadbuffer*/
   #endif
@@ -14338,12 +18311,12 @@ static PyBufferProcs __pyx_tp_as_buffer_SparseVector = {
   #endif
 };
 
-static PyTypeObject __pyx_type_5_cdec_SparseVector = {
+static PyTypeObject __pyx_type_5_cdec_Hypergraph = {
   PyVarObject_HEAD_INIT(0, 0)
-  __Pyx_NAMESTR("_cdec.SparseVector"), /*tp_name*/
-  sizeof(struct __pyx_obj_5_cdec_SparseVector), /*tp_basicsize*/
+  __Pyx_NAMESTR("_cdec.Hypergraph"), /*tp_name*/
+  sizeof(struct __pyx_obj_5_cdec_Hypergraph), /*tp_basicsize*/
   0, /*tp_itemsize*/
-  __pyx_tp_dealloc_5_cdec_SparseVector, /*tp_dealloc*/
+  __pyx_tp_dealloc_5_cdec_Hypergraph, /*tp_dealloc*/
   0, /*tp_print*/
   0, /*tp_getattr*/
   0, /*tp_setattr*/
@@ -14353,26 +18326,26 @@ static PyTypeObject __pyx_type_5_cdec_SparseVector = {
   0, /*reserved*/
   #endif
   0, /*tp_repr*/
-  &__pyx_tp_as_number_SparseVector, /*tp_as_number*/
-  &__pyx_tp_as_sequence_SparseVector, /*tp_as_sequence*/
-  &__pyx_tp_as_mapping_SparseVector, /*tp_as_mapping*/
+  &__pyx_tp_as_number_Hypergraph, /*tp_as_number*/
+  &__pyx_tp_as_sequence_Hypergraph, /*tp_as_sequence*/
+  &__pyx_tp_as_mapping_Hypergraph, /*tp_as_mapping*/
   0, /*tp_hash*/
   0, /*tp_call*/
   0, /*tp_str*/
   0, /*tp_getattro*/
   0, /*tp_setattro*/
-  &__pyx_tp_as_buffer_SparseVector, /*tp_as_buffer*/
+  &__pyx_tp_as_buffer_Hypergraph, /*tp_as_buffer*/
   Py_TPFLAGS_DEFAULT|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_BASETYPE, /*tp_flags*/
   0, /*tp_doc*/
   0, /*tp_traverse*/
   0, /*tp_clear*/
-  __pyx_pw_5_cdec_12SparseVector_14__richcmp__, /*tp_richcompare*/
+  0, /*tp_richcompare*/
   0, /*tp_weaklistoffset*/
-  __pyx_pw_5_cdec_12SparseVector_9__iter__, /*tp_iter*/
+  0, /*tp_iter*/
   0, /*tp_iternext*/
-  __pyx_methods_5_cdec_SparseVector, /*tp_methods*/
+  __pyx_methods_5_cdec_Hypergraph, /*tp_methods*/
   0, /*tp_members*/
-  0, /*tp_getset*/
+  __pyx_getsets_5_cdec_Hypergraph, /*tp_getset*/
   0, /*tp_base*/
   0, /*tp_dict*/
   0, /*tp_descr_get*/
@@ -14380,7 +18353,7 @@ static PyTypeObject __pyx_type_5_cdec_SparseVector = {
   0, /*tp_dictoffset*/
   0, /*tp_init*/
   0, /*tp_alloc*/
-  __pyx_tp_new_5_cdec_SparseVector, /*tp_new*/
+  __pyx_tp_new_5_cdec_Hypergraph, /*tp_new*/
   0, /*tp_free*/
   0, /*tp_is_gc*/
   0, /*tp_bases*/
@@ -14393,62 +18366,90 @@ static PyTypeObject __pyx_type_5_cdec_SparseVector = {
   0, /*tp_version_tag*/
   #endif
 };
+static struct __pyx_vtabstruct_5_cdec_HypergraphEdge __pyx_vtable_5_cdec_HypergraphEdge;
+
+static PyObject *__pyx_tp_new_5_cdec_HypergraphEdge(PyTypeObject *t, PyObject *a, PyObject *k) {
+  struct __pyx_obj_5_cdec_HypergraphEdge *p;
+  PyObject *o = (*t->tp_alloc)(t, 0);
+  if (!o) return 0;
+  p = ((struct __pyx_obj_5_cdec_HypergraphEdge *)o);
+  p->__pyx_vtab = __pyx_vtabptr_5_cdec_HypergraphEdge;
+  p->trule = ((struct __pyx_obj_5_cdec_BaseTRule *)Py_None); Py_INCREF(Py_None);
+  return o;
+}
+
+static void __pyx_tp_dealloc_5_cdec_HypergraphEdge(PyObject *o) {
+  struct __pyx_obj_5_cdec_HypergraphEdge *p = (struct __pyx_obj_5_cdec_HypergraphEdge *)o;
+  Py_XDECREF(((PyObject *)p->trule));
+  (*Py_TYPE(o)->tp_free)(o);
+}
+
+static int __pyx_tp_traverse_5_cdec_HypergraphEdge(PyObject *o, visitproc v, void *a) {
+  int e;
+  struct __pyx_obj_5_cdec_HypergraphEdge *p = (struct __pyx_obj_5_cdec_HypergraphEdge *)o;
+  if (p->trule) {
+    e = (*v)(((PyObject*)p->trule), a); if (e) return e;
+  }
+  return 0;
+}
+
+static int __pyx_tp_clear_5_cdec_HypergraphEdge(PyObject *o) {
+  struct __pyx_obj_5_cdec_HypergraphEdge *p = (struct __pyx_obj_5_cdec_HypergraphEdge *)o;
+  PyObject* tmp;
+  tmp = ((PyObject*)p->trule);
+  p->trule = ((struct __pyx_obj_5_cdec_BaseTRule *)Py_None); Py_INCREF(Py_None);
+  Py_XDECREF(tmp);
+  return 0;
+}
 
-static PyObject *__pyx_tp_new_5_cdec_Hypergraph(PyTypeObject *t, PyObject *a, PyObject *k) {
-  PyObject *o = (*t->tp_alloc)(t, 0);
-  if (!o) return 0;
-  return o;
+static PyObject *__pyx_getprop_5_cdec_14HypergraphEdge_head_node(PyObject *o, void *x) {
+  return __pyx_pw_5_cdec_14HypergraphEdge_9head_node_1__get__(o);
 }
 
-static void __pyx_tp_dealloc_5_cdec_Hypergraph(PyObject *o) {
-  {
-    PyObject *etype, *eval, *etb;
-    PyErr_Fetch(&etype, &eval, &etb);
-    ++Py_REFCNT(o);
-    __pyx_pw_5_cdec_10Hypergraph_1__dealloc__(o);
-    if (PyErr_Occurred()) PyErr_WriteUnraisable(o);
-    --Py_REFCNT(o);
-    PyErr_Restore(etype, eval, etb);
-  }
-  (*Py_TYPE(o)->tp_free)(o);
+static PyObject *__pyx_getprop_5_cdec_14HypergraphEdge_tail_nodes(PyObject *o, void *x) {
+  return __pyx_pw_5_cdec_14HypergraphEdge_10tail_nodes_1__get__(o);
 }
 
-static PyObject *__pyx_getprop_5_cdec_10Hypergraph_edges(PyObject *o, void *x) {
-  return __pyx_pw_5_cdec_10Hypergraph_5edges_1__get__(o);
+static PyObject *__pyx_getprop_5_cdec_14HypergraphEdge_span(PyObject *o, void *x) {
+  return __pyx_pw_5_cdec_14HypergraphEdge_4span_1__get__(o);
 }
 
-static PyObject *__pyx_getprop_5_cdec_10Hypergraph_nodes(PyObject *o, void *x) {
-  return __pyx_pw_5_cdec_10Hypergraph_5nodes_1__get__(o);
+static PyObject *__pyx_getprop_5_cdec_14HypergraphEdge_feature_values(PyObject *o, void *x) {
+  return __pyx_pw_5_cdec_14HypergraphEdge_14feature_values_1__get__(o);
 }
 
-static PyObject *__pyx_getprop_5_cdec_10Hypergraph_goal(PyObject *o, void *x) {
-  return __pyx_pw_5_cdec_10Hypergraph_4goal_1__get__(o);
+static PyObject *__pyx_getprop_5_cdec_14HypergraphEdge_prob(PyObject *o, void *x) {
+  return __pyx_pw_5_cdec_14HypergraphEdge_4prob_1__get__(o);
 }
 
-static PyMethodDef __pyx_methods_5_cdec_Hypergraph[] = {
-  {__Pyx_NAMESTR("viterbi"), (PyCFunction)__pyx_pw_5_cdec_10Hypergraph_3viterbi, METH_NOARGS, __Pyx_DOCSTR(0)},
-  {__Pyx_NAMESTR("viterbi_trees"), (PyCFunction)__pyx_pw_5_cdec_10Hypergraph_5viterbi_trees, METH_NOARGS, __Pyx_DOCSTR(0)},
-  {__Pyx_NAMESTR("viterbi_features"), (PyCFunction)__pyx_pw_5_cdec_10Hypergraph_7viterbi_features, METH_NOARGS, __Pyx_DOCSTR(0)},
-  {__Pyx_NAMESTR("viterbi_joshua"), (PyCFunction)__pyx_pw_5_cdec_10Hypergraph_9viterbi_joshua, METH_NOARGS, __Pyx_DOCSTR(0)},
-  {__Pyx_NAMESTR("kbest"), (PyCFunction)__pyx_pw_5_cdec_10Hypergraph_11kbest, METH_O, __Pyx_DOCSTR(0)},
-  {__Pyx_NAMESTR("kbest_trees"), (PyCFunction)__pyx_pw_5_cdec_10Hypergraph_14kbest_trees, METH_O, __Pyx_DOCSTR(0)},
-  {__Pyx_NAMESTR("kbest_features"), (PyCFunction)__pyx_pw_5_cdec_10Hypergraph_17kbest_features, METH_O, __Pyx_DOCSTR(0)},
-  {__Pyx_NAMESTR("sample"), (PyCFunction)__pyx_pw_5_cdec_10Hypergraph_20sample, METH_O, __Pyx_DOCSTR(0)},
-  {__Pyx_NAMESTR("intersect"), (PyCFunction)__pyx_pw_5_cdec_10Hypergraph_23intersect, METH_O, __Pyx_DOCSTR(0)},
-  {__Pyx_NAMESTR("prune"), (PyCFunction)__pyx_pw_5_cdec_10Hypergraph_25prune, METH_VARARGS|METH_KEYWORDS, __Pyx_DOCSTR(0)},
-  {__Pyx_NAMESTR("lattice"), (PyCFunction)__pyx_pw_5_cdec_10Hypergraph_27lattice, METH_NOARGS, __Pyx_DOCSTR(0)},
-  {__Pyx_NAMESTR("reweight"), (PyCFunction)__pyx_pw_5_cdec_10Hypergraph_29reweight, METH_O, __Pyx_DOCSTR(0)},
+static PyObject *__pyx_getprop_5_cdec_14HypergraphEdge_trule(PyObject *o, void *x) {
+  return __pyx_pw_5_cdec_14HypergraphEdge_5trule_1__get__(o);
+}
+
+static int __pyx_setprop_5_cdec_14HypergraphEdge_trule(PyObject *o, PyObject *v, void *x) {
+  if (v) {
+    return __pyx_pw_5_cdec_14HypergraphEdge_5trule_3__set__(o, v);
+  }
+  else {
+    return __pyx_pw_5_cdec_14HypergraphEdge_5trule_5__del__(o);
+  }
+}
+
+static PyMethodDef __pyx_methods_5_cdec_HypergraphEdge[] = {
   {0, 0, 0, 0}
 };
 
-static struct PyGetSetDef __pyx_getsets_5_cdec_Hypergraph[] = {
-  {(char *)"edges", __pyx_getprop_5_cdec_10Hypergraph_edges, 0, 0, 0},
-  {(char *)"nodes", __pyx_getprop_5_cdec_10Hypergraph_nodes, 0, 0, 0},
-  {(char *)"goal", __pyx_getprop_5_cdec_10Hypergraph_goal, 0, 0, 0},
+static struct PyGetSetDef __pyx_getsets_5_cdec_HypergraphEdge[] = {
+  {(char *)"head_node", __pyx_getprop_5_cdec_14HypergraphEdge_head_node, 0, 0, 0},
+  {(char *)"tail_nodes", __pyx_getprop_5_cdec_14HypergraphEdge_tail_nodes, 0, 0, 0},
+  {(char *)"span", __pyx_getprop_5_cdec_14HypergraphEdge_span, 0, 0, 0},
+  {(char *)"feature_values", __pyx_getprop_5_cdec_14HypergraphEdge_feature_values, 0, 0, 0},
+  {(char *)"prob", __pyx_getprop_5_cdec_14HypergraphEdge_prob, 0, 0, 0},
+  {(char *)"trule", __pyx_getprop_5_cdec_14HypergraphEdge_trule, __pyx_setprop_5_cdec_14HypergraphEdge_trule, 0, 0},
   {0, 0, 0, 0, 0}
 };
 
-static PyNumberMethods __pyx_tp_as_number_Hypergraph = {
+static PyNumberMethods __pyx_tp_as_number_HypergraphEdge = {
   0, /*nb_add*/
   0, /*nb_subtract*/
   0, /*nb_multiply*/
@@ -14506,8 +18507,8 @@ static PyNumberMethods __pyx_tp_as_number_Hypergraph = {
   #endif
 };
 
-static PySequenceMethods __pyx_tp_as_sequence_Hypergraph = {
-  0, /*sq_length*/
+static PySequenceMethods __pyx_tp_as_sequence_HypergraphEdge = {
+  __pyx_pw_5_cdec_14HypergraphEdge_1__len__, /*sq_length*/
   0, /*sq_concat*/
   0, /*sq_repeat*/
   0, /*sq_item*/
@@ -14519,13 +18520,13 @@ static PySequenceMethods __pyx_tp_as_sequence_Hypergraph = {
   0, /*sq_inplace_repeat*/
 };
 
-static PyMappingMethods __pyx_tp_as_mapping_Hypergraph = {
-  0, /*mp_length*/
+static PyMappingMethods __pyx_tp_as_mapping_HypergraphEdge = {
+  __pyx_pw_5_cdec_14HypergraphEdge_1__len__, /*mp_length*/
   0, /*mp_subscript*/
   0, /*mp_ass_subscript*/
 };
 
-static PyBufferProcs __pyx_tp_as_buffer_Hypergraph = {
+static PyBufferProcs __pyx_tp_as_buffer_HypergraphEdge = {
   #if PY_MAJOR_VERSION < 3
   0, /*bf_getreadbuffer*/
   #endif
@@ -14546,12 +18547,12 @@ static PyBufferProcs __pyx_tp_as_buffer_Hypergraph = {
   #endif
 };
 
-static PyTypeObject __pyx_type_5_cdec_Hypergraph = {
+static PyTypeObject __pyx_type_5_cdec_HypergraphEdge = {
   PyVarObject_HEAD_INIT(0, 0)
-  __Pyx_NAMESTR("_cdec.Hypergraph"), /*tp_name*/
-  sizeof(struct __pyx_obj_5_cdec_Hypergraph), /*tp_basicsize*/
+  __Pyx_NAMESTR("_cdec.HypergraphEdge"), /*tp_name*/
+  sizeof(struct __pyx_obj_5_cdec_HypergraphEdge), /*tp_basicsize*/
   0, /*tp_itemsize*/
-  __pyx_tp_dealloc_5_cdec_Hypergraph, /*tp_dealloc*/
+  __pyx_tp_dealloc_5_cdec_HypergraphEdge, /*tp_dealloc*/
   0, /*tp_print*/
   0, /*tp_getattr*/
   0, /*tp_setattr*/
@@ -14561,26 +18562,26 @@ static PyTypeObject __pyx_type_5_cdec_Hypergraph = {
   0, /*reserved*/
   #endif
   0, /*tp_repr*/
-  &__pyx_tp_as_number_Hypergraph, /*tp_as_number*/
-  &__pyx_tp_as_sequence_Hypergraph, /*tp_as_sequence*/
-  &__pyx_tp_as_mapping_Hypergraph, /*tp_as_mapping*/
+  &__pyx_tp_as_number_HypergraphEdge, /*tp_as_number*/
+  &__pyx_tp_as_sequence_HypergraphEdge, /*tp_as_sequence*/
+  &__pyx_tp_as_mapping_HypergraphEdge, /*tp_as_mapping*/
   0, /*tp_hash*/
   0, /*tp_call*/
   0, /*tp_str*/
   0, /*tp_getattro*/
   0, /*tp_setattro*/
-  &__pyx_tp_as_buffer_Hypergraph, /*tp_as_buffer*/
-  Py_TPFLAGS_DEFAULT|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_BASETYPE, /*tp_flags*/
+  &__pyx_tp_as_buffer_HypergraphEdge, /*tp_as_buffer*/
+  Py_TPFLAGS_DEFAULT|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_HAVE_GC, /*tp_flags*/
   0, /*tp_doc*/
-  0, /*tp_traverse*/
-  0, /*tp_clear*/
-  0, /*tp_richcompare*/
+  __pyx_tp_traverse_5_cdec_HypergraphEdge, /*tp_traverse*/
+  __pyx_tp_clear_5_cdec_HypergraphEdge, /*tp_clear*/
+  __pyx_pw_5_cdec_14HypergraphEdge_3__richcmp__, /*tp_richcompare*/
   0, /*tp_weaklistoffset*/
   0, /*tp_iter*/
   0, /*tp_iternext*/
-  __pyx_methods_5_cdec_Hypergraph, /*tp_methods*/
+  __pyx_methods_5_cdec_HypergraphEdge, /*tp_methods*/
   0, /*tp_members*/
-  __pyx_getsets_5_cdec_Hypergraph, /*tp_getset*/
+  __pyx_getsets_5_cdec_HypergraphEdge, /*tp_getset*/
   0, /*tp_base*/
   0, /*tp_dict*/
   0, /*tp_descr_get*/
@@ -14588,7 +18589,7 @@ static PyTypeObject __pyx_type_5_cdec_Hypergraph = {
   0, /*tp_dictoffset*/
   0, /*tp_init*/
   0, /*tp_alloc*/
-  __pyx_tp_new_5_cdec_Hypergraph, /*tp_new*/
+  __pyx_tp_new_5_cdec_HypergraphEdge, /*tp_new*/
   0, /*tp_free*/
   0, /*tp_is_gc*/
   0, /*tp_bases*/
@@ -14601,51 +18602,50 @@ static PyTypeObject __pyx_type_5_cdec_Hypergraph = {
   0, /*tp_version_tag*/
   #endif
 };
+static struct __pyx_vtabstruct_5_cdec_HypergraphNode __pyx_vtable_5_cdec_HypergraphNode;
 
-static PyObject *__pyx_tp_new_5_cdec_TRule(PyTypeObject *t, PyObject *a, PyObject *k) {
+static PyObject *__pyx_tp_new_5_cdec_HypergraphNode(PyTypeObject *t, PyObject *a, PyObject *k) {
+  struct __pyx_obj_5_cdec_HypergraphNode *p;
   PyObject *o = (*t->tp_alloc)(t, 0);
   if (!o) return 0;
+  p = ((struct __pyx_obj_5_cdec_HypergraphNode *)o);
+  p->__pyx_vtab = __pyx_vtabptr_5_cdec_HypergraphNode;
   return o;
 }
 
-static void __pyx_tp_dealloc_5_cdec_TRule(PyObject *o) {
+static void __pyx_tp_dealloc_5_cdec_HypergraphNode(PyObject *o) {
   (*Py_TYPE(o)->tp_free)(o);
 }
 
-static PyObject *__pyx_getprop_5_cdec_5TRule_arity(PyObject *o, void *x) {
-  return __pyx_pw_5_cdec_5TRule_5arity_1__get__(o);
-}
-
-static PyObject *__pyx_getprop_5_cdec_5TRule_f(PyObject *o, void *x) {
-  return __pyx_pw_5_cdec_5TRule_1f_1__get__(o);
+static PyObject *__pyx_getprop_5_cdec_14HypergraphNode_in_edges(PyObject *o, void *x) {
+  return __pyx_pw_5_cdec_14HypergraphNode_8in_edges_1__get__(o);
 }
 
-static PyObject *__pyx_getprop_5_cdec_5TRule_e(PyObject *o, void *x) {
-  return __pyx_pw_5_cdec_5TRule_1e_1__get__(o);
+static PyObject *__pyx_getprop_5_cdec_14HypergraphNode_out_edges(PyObject *o, void *x) {
+  return __pyx_pw_5_cdec_14HypergraphNode_9out_edges_1__get__(o);
 }
 
-static PyObject *__pyx_getprop_5_cdec_5TRule_scores(PyObject *o, void *x) {
-  return __pyx_pw_5_cdec_5TRule_6scores_1__get__(o);
+static PyObject *__pyx_getprop_5_cdec_14HypergraphNode_span(PyObject *o, void *x) {
+  return __pyx_pw_5_cdec_14HypergraphNode_4span_1__get__(o);
 }
 
-static PyObject *__pyx_getprop_5_cdec_5TRule_lhs(PyObject *o, void *x) {
-  return __pyx_pw_5_cdec_5TRule_3lhs_1__get__(o);
+static PyObject *__pyx_getprop_5_cdec_14HypergraphNode_cat(PyObject *o, void *x) {
+  return __pyx_pw_5_cdec_14HypergraphNode_3cat_1__get__(o);
 }
 
-static PyMethodDef __pyx_methods_5_cdec_TRule[] = {
+static PyMethodDef __pyx_methods_5_cdec_HypergraphNode[] = {
   {0, 0, 0, 0}
 };
 
-static struct PyGetSetDef __pyx_getsets_5_cdec_TRule[] = {
-  {(char *)"arity", __pyx_getprop_5_cdec_5TRule_arity, 0, 0, 0},
-  {(char *)"f", __pyx_getprop_5_cdec_5TRule_f, 0, 0, 0},
-  {(char *)"e", __pyx_getprop_5_cdec_5TRule_e, 0, 0, 0},
-  {(char *)"scores", __pyx_getprop_5_cdec_5TRule_scores, 0, 0, 0},
-  {(char *)"lhs", __pyx_getprop_5_cdec_5TRule_lhs, 0, 0, 0},
+static struct PyGetSetDef __pyx_getsets_5_cdec_HypergraphNode[] = {
+  {(char *)"in_edges", __pyx_getprop_5_cdec_14HypergraphNode_in_edges, 0, 0, 0},
+  {(char *)"out_edges", __pyx_getprop_5_cdec_14HypergraphNode_out_edges, 0, 0, 0},
+  {(char *)"span", __pyx_getprop_5_cdec_14HypergraphNode_span, 0, 0, 0},
+  {(char *)"cat", __pyx_getprop_5_cdec_14HypergraphNode_cat, 0, 0, 0},
   {0, 0, 0, 0, 0}
 };
 
-static PyNumberMethods __pyx_tp_as_number_TRule = {
+static PyNumberMethods __pyx_tp_as_number_HypergraphNode = {
   0, /*nb_add*/
   0, /*nb_subtract*/
   0, /*nb_multiply*/
@@ -14703,7 +18703,7 @@ static PyNumberMethods __pyx_tp_as_number_TRule = {
   #endif
 };
 
-static PySequenceMethods __pyx_tp_as_sequence_TRule = {
+static PySequenceMethods __pyx_tp_as_sequence_HypergraphNode = {
   0, /*sq_length*/
   0, /*sq_concat*/
   0, /*sq_repeat*/
@@ -14716,13 +18716,13 @@ static PySequenceMethods __pyx_tp_as_sequence_TRule = {
   0, /*sq_inplace_repeat*/
 };
 
-static PyMappingMethods __pyx_tp_as_mapping_TRule = {
+static PyMappingMethods __pyx_tp_as_mapping_HypergraphNode = {
   0, /*mp_length*/
   0, /*mp_subscript*/
   0, /*mp_ass_subscript*/
 };
 
-static PyBufferProcs __pyx_tp_as_buffer_TRule = {
+static PyBufferProcs __pyx_tp_as_buffer_HypergraphNode = {
   #if PY_MAJOR_VERSION < 3
   0, /*bf_getreadbuffer*/
   #endif
@@ -14743,12 +18743,12 @@ static PyBufferProcs __pyx_tp_as_buffer_TRule = {
   #endif
 };
 
-static PyTypeObject __pyx_type_5_cdec_TRule = {
+static PyTypeObject __pyx_type_5_cdec_HypergraphNode = {
   PyVarObject_HEAD_INIT(0, 0)
-  __Pyx_NAMESTR("_cdec.TRule"), /*tp_name*/
-  sizeof(struct __pyx_obj_5_cdec_TRule), /*tp_basicsize*/
+  __Pyx_NAMESTR("_cdec.HypergraphNode"), /*tp_name*/
+  sizeof(struct __pyx_obj_5_cdec_HypergraphNode), /*tp_basicsize*/
   0, /*tp_itemsize*/
-  __pyx_tp_dealloc_5_cdec_TRule, /*tp_dealloc*/
+  __pyx_tp_dealloc_5_cdec_HypergraphNode, /*tp_dealloc*/
   0, /*tp_print*/
   0, /*tp_getattr*/
   0, /*tp_setattr*/
@@ -14758,26 +18758,26 @@ static PyTypeObject __pyx_type_5_cdec_TRule = {
   0, /*reserved*/
   #endif
   0, /*tp_repr*/
-  &__pyx_tp_as_number_TRule, /*tp_as_number*/
-  &__pyx_tp_as_sequence_TRule, /*tp_as_sequence*/
-  &__pyx_tp_as_mapping_TRule, /*tp_as_mapping*/
+  &__pyx_tp_as_number_HypergraphNode, /*tp_as_number*/
+  &__pyx_tp_as_sequence_HypergraphNode, /*tp_as_sequence*/
+  &__pyx_tp_as_mapping_HypergraphNode, /*tp_as_mapping*/
   0, /*tp_hash*/
   0, /*tp_call*/
-  __pyx_pw_5_cdec_5TRule_1__str__, /*tp_str*/
+  0, /*tp_str*/
   0, /*tp_getattro*/
   0, /*tp_setattro*/
-  &__pyx_tp_as_buffer_TRule, /*tp_as_buffer*/
+  &__pyx_tp_as_buffer_HypergraphNode, /*tp_as_buffer*/
   Py_TPFLAGS_DEFAULT|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_BASETYPE, /*tp_flags*/
   0, /*tp_doc*/
   0, /*tp_traverse*/
   0, /*tp_clear*/
-  0, /*tp_richcompare*/
+  __pyx_pw_5_cdec_14HypergraphNode_1__richcmp__, /*tp_richcompare*/
   0, /*tp_weaklistoffset*/
   0, /*tp_iter*/
   0, /*tp_iternext*/
-  __pyx_methods_5_cdec_TRule, /*tp_methods*/
+  __pyx_methods_5_cdec_HypergraphNode, /*tp_methods*/
   0, /*tp_members*/
-  __pyx_getsets_5_cdec_TRule, /*tp_getset*/
+  __pyx_getsets_5_cdec_HypergraphNode, /*tp_getset*/
   0, /*tp_base*/
   0, /*tp_dict*/
   0, /*tp_descr_get*/
@@ -14785,7 +18785,7 @@ static PyTypeObject __pyx_type_5_cdec_TRule = {
   0, /*tp_dictoffset*/
   0, /*tp_init*/
   0, /*tp_alloc*/
-  __pyx_tp_new_5_cdec_TRule, /*tp_new*/
+  __pyx_tp_new_5_cdec_HypergraphNode, /*tp_new*/
   0, /*tp_free*/
   0, /*tp_is_gc*/
   0, /*tp_bases*/
@@ -14798,90 +18798,53 @@ static PyTypeObject __pyx_type_5_cdec_TRule = {
   0, /*tp_version_tag*/
   #endif
 };
-static struct __pyx_vtabstruct_5_cdec_HypergraphEdge __pyx_vtable_5_cdec_HypergraphEdge;
 
-static PyObject *__pyx_tp_new_5_cdec_HypergraphEdge(PyTypeObject *t, PyObject *a, PyObject *k) {
-  struct __pyx_obj_5_cdec_HypergraphEdge *p;
+static PyObject *__pyx_tp_new_5_cdec_Lattice(PyTypeObject *t, PyObject *a, PyObject *k) {
   PyObject *o = (*t->tp_alloc)(t, 0);
   if (!o) return 0;
-  p = ((struct __pyx_obj_5_cdec_HypergraphEdge *)o);
-  p->__pyx_vtab = __pyx_vtabptr_5_cdec_HypergraphEdge;
-  p->trule = ((struct __pyx_obj_5_cdec_TRule *)Py_None); Py_INCREF(Py_None);
+  if (__pyx_pw_5_cdec_7Lattice_1__cinit__(o, a, k) < 0) {
+    Py_DECREF(o); o = 0;
+  }
   return o;
 }
 
-static void __pyx_tp_dealloc_5_cdec_HypergraphEdge(PyObject *o) {
-  struct __pyx_obj_5_cdec_HypergraphEdge *p = (struct __pyx_obj_5_cdec_HypergraphEdge *)o;
-  Py_XDECREF(((PyObject *)p->trule));
-  (*Py_TYPE(o)->tp_free)(o);
-}
-
-static int __pyx_tp_traverse_5_cdec_HypergraphEdge(PyObject *o, visitproc v, void *a) {
-  int e;
-  struct __pyx_obj_5_cdec_HypergraphEdge *p = (struct __pyx_obj_5_cdec_HypergraphEdge *)o;
-  if (p->trule) {
-    e = (*v)(((PyObject*)p->trule), a); if (e) return e;
+static void __pyx_tp_dealloc_5_cdec_Lattice(PyObject *o) {
+  {
+    PyObject *etype, *eval, *etb;
+    PyErr_Fetch(&etype, &eval, &etb);
+    ++Py_REFCNT(o);
+    __pyx_pw_5_cdec_7Lattice_14__dealloc__(o);
+    if (PyErr_Occurred()) PyErr_WriteUnraisable(o);
+    --Py_REFCNT(o);
+    PyErr_Restore(etype, eval, etb);
   }
-  return 0;
-}
-
-static int __pyx_tp_clear_5_cdec_HypergraphEdge(PyObject *o) {
-  struct __pyx_obj_5_cdec_HypergraphEdge *p = (struct __pyx_obj_5_cdec_HypergraphEdge *)o;
-  PyObject* tmp;
-  tmp = ((PyObject*)p->trule);
-  p->trule = ((struct __pyx_obj_5_cdec_TRule *)Py_None); Py_INCREF(Py_None);
-  Py_XDECREF(tmp);
-  return 0;
-}
-
-static PyObject *__pyx_getprop_5_cdec_14HypergraphEdge_head_node(PyObject *o, void *x) {
-  return __pyx_pw_5_cdec_14HypergraphEdge_9head_node_1__get__(o);
-}
-
-static PyObject *__pyx_getprop_5_cdec_14HypergraphEdge_tail_nodes(PyObject *o, void *x) {
-  return __pyx_pw_5_cdec_14HypergraphEdge_10tail_nodes_1__get__(o);
-}
-
-static PyObject *__pyx_getprop_5_cdec_14HypergraphEdge_span(PyObject *o, void *x) {
-  return __pyx_pw_5_cdec_14HypergraphEdge_4span_1__get__(o);
-}
-
-static PyObject *__pyx_getprop_5_cdec_14HypergraphEdge_feature_values(PyObject *o, void *x) {
-  return __pyx_pw_5_cdec_14HypergraphEdge_14feature_values_1__get__(o);
-}
-
-static PyObject *__pyx_getprop_5_cdec_14HypergraphEdge_prob(PyObject *o, void *x) {
-  return __pyx_pw_5_cdec_14HypergraphEdge_4prob_1__get__(o);
+  (*Py_TYPE(o)->tp_free)(o);
 }
-
-static PyObject *__pyx_getprop_5_cdec_14HypergraphEdge_trule(PyObject *o, void *x) {
-  return __pyx_pw_5_cdec_14HypergraphEdge_5trule_1__get__(o);
+static PyObject *__pyx_sq_item_5_cdec_Lattice(PyObject *o, Py_ssize_t i) {
+  PyObject *r;
+  PyObject *x = PyInt_FromSsize_t(i); if(!x) return 0;
+  r = Py_TYPE(o)->tp_as_mapping->mp_subscript(o, x);
+  Py_DECREF(x);
+  return r;
 }
 
-static int __pyx_setprop_5_cdec_14HypergraphEdge_trule(PyObject *o, PyObject *v, void *x) {
+static int __pyx_mp_ass_subscript_5_cdec_Lattice(PyObject *o, PyObject *i, PyObject *v) {
   if (v) {
-    return __pyx_pw_5_cdec_14HypergraphEdge_5trule_3__set__(o, v);
+    return __pyx_pw_5_cdec_7Lattice_5__setitem__(o, i, v);
   }
   else {
-    return __pyx_pw_5_cdec_14HypergraphEdge_5trule_5__del__(o);
+    PyErr_Format(PyExc_NotImplementedError,
+      "Subscript deletion not supported by %s", Py_TYPE(o)->tp_name);
+    return -1;
   }
 }
-
-static PyMethodDef __pyx_methods_5_cdec_HypergraphEdge[] = {
-  {0, 0, 0, 0}
-};
-
-static struct PyGetSetDef __pyx_getsets_5_cdec_HypergraphEdge[] = {
-  {(char *)"head_node", __pyx_getprop_5_cdec_14HypergraphEdge_head_node, 0, 0, 0},
-  {(char *)"tail_nodes", __pyx_getprop_5_cdec_14HypergraphEdge_tail_nodes, 0, 0, 0},
-  {(char *)"span", __pyx_getprop_5_cdec_14HypergraphEdge_span, 0, 0, 0},
-  {(char *)"feature_values", __pyx_getprop_5_cdec_14HypergraphEdge_feature_values, 0, 0, 0},
-  {(char *)"prob", __pyx_getprop_5_cdec_14HypergraphEdge_prob, 0, 0, 0},
-  {(char *)"trule", __pyx_getprop_5_cdec_14HypergraphEdge_trule, __pyx_setprop_5_cdec_14HypergraphEdge_trule, 0, 0},
-  {0, 0, 0, 0, 0}
+
+static PyMethodDef __pyx_methods_5_cdec_Lattice[] = {
+  {__Pyx_NAMESTR("todot"), (PyCFunction)__pyx_pw_5_cdec_7Lattice_16todot, METH_NOARGS, __Pyx_DOCSTR(0)},
+  {0, 0, 0, 0}
 };
 
-static PyNumberMethods __pyx_tp_as_number_HypergraphEdge = {
+static PyNumberMethods __pyx_tp_as_number_Lattice = {
   0, /*nb_add*/
   0, /*nb_subtract*/
   0, /*nb_multiply*/
@@ -14939,11 +18902,11 @@ static PyNumberMethods __pyx_tp_as_number_HypergraphEdge = {
   #endif
 };
 
-static PySequenceMethods __pyx_tp_as_sequence_HypergraphEdge = {
-  __pyx_pw_5_cdec_14HypergraphEdge_1__len__, /*sq_length*/
+static PySequenceMethods __pyx_tp_as_sequence_Lattice = {
+  __pyx_pw_5_cdec_7Lattice_7__len__, /*sq_length*/
   0, /*sq_concat*/
   0, /*sq_repeat*/
-  0, /*sq_item*/
+  __pyx_sq_item_5_cdec_Lattice, /*sq_item*/
   0, /*sq_slice*/
   0, /*sq_ass_item*/
   0, /*sq_ass_slice*/
@@ -14952,13 +18915,13 @@ static PySequenceMethods __pyx_tp_as_sequence_HypergraphEdge = {
   0, /*sq_inplace_repeat*/
 };
 
-static PyMappingMethods __pyx_tp_as_mapping_HypergraphEdge = {
-  __pyx_pw_5_cdec_14HypergraphEdge_1__len__, /*mp_length*/
-  0, /*mp_subscript*/
-  0, /*mp_ass_subscript*/
+static PyMappingMethods __pyx_tp_as_mapping_Lattice = {
+  __pyx_pw_5_cdec_7Lattice_7__len__, /*mp_length*/
+  __pyx_pw_5_cdec_7Lattice_3__getitem__, /*mp_subscript*/
+  __pyx_mp_ass_subscript_5_cdec_Lattice, /*mp_ass_subscript*/
 };
 
-static PyBufferProcs __pyx_tp_as_buffer_HypergraphEdge = {
+static PyBufferProcs __pyx_tp_as_buffer_Lattice = {
   #if PY_MAJOR_VERSION < 3
   0, /*bf_getreadbuffer*/
   #endif
@@ -14979,12 +18942,12 @@ static PyBufferProcs __pyx_tp_as_buffer_HypergraphEdge = {
   #endif
 };
 
-static PyTypeObject __pyx_type_5_cdec_HypergraphEdge = {
+static PyTypeObject __pyx_type_5_cdec_Lattice = {
   PyVarObject_HEAD_INIT(0, 0)
-  __Pyx_NAMESTR("_cdec.HypergraphEdge"), /*tp_name*/
-  sizeof(struct __pyx_obj_5_cdec_HypergraphEdge), /*tp_basicsize*/
+  __Pyx_NAMESTR("_cdec.Lattice"), /*tp_name*/
+  sizeof(struct __pyx_obj_5_cdec_Lattice), /*tp_basicsize*/
   0, /*tp_itemsize*/
-  __pyx_tp_dealloc_5_cdec_HypergraphEdge, /*tp_dealloc*/
+  __pyx_tp_dealloc_5_cdec_Lattice, /*tp_dealloc*/
   0, /*tp_print*/
   0, /*tp_getattr*/
   0, /*tp_setattr*/
@@ -14994,26 +18957,26 @@ static PyTypeObject __pyx_type_5_cdec_HypergraphEdge = {
   0, /*reserved*/
   #endif
   0, /*tp_repr*/
-  &__pyx_tp_as_number_HypergraphEdge, /*tp_as_number*/
-  &__pyx_tp_as_sequence_HypergraphEdge, /*tp_as_sequence*/
-  &__pyx_tp_as_mapping_HypergraphEdge, /*tp_as_mapping*/
+  &__pyx_tp_as_number_Lattice, /*tp_as_number*/
+  &__pyx_tp_as_sequence_Lattice, /*tp_as_sequence*/
+  &__pyx_tp_as_mapping_Lattice, /*tp_as_mapping*/
   0, /*tp_hash*/
   0, /*tp_call*/
-  0, /*tp_str*/
+  __pyx_pw_5_cdec_7Lattice_9__str__, /*tp_str*/
   0, /*tp_getattro*/
   0, /*tp_setattro*/
-  &__pyx_tp_as_buffer_HypergraphEdge, /*tp_as_buffer*/
-  Py_TPFLAGS_DEFAULT|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_HAVE_GC, /*tp_flags*/
+  &__pyx_tp_as_buffer_Lattice, /*tp_as_buffer*/
+  Py_TPFLAGS_DEFAULT|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_BASETYPE, /*tp_flags*/
   0, /*tp_doc*/
-  __pyx_tp_traverse_5_cdec_HypergraphEdge, /*tp_traverse*/
-  __pyx_tp_clear_5_cdec_HypergraphEdge, /*tp_clear*/
-  __pyx_pw_5_cdec_14HypergraphEdge_3__richcmp__, /*tp_richcompare*/
+  0, /*tp_traverse*/
+  0, /*tp_clear*/
+  0, /*tp_richcompare*/
   0, /*tp_weaklistoffset*/
-  0, /*tp_iter*/
+  __pyx_pw_5_cdec_7Lattice_11__iter__, /*tp_iter*/
   0, /*tp_iternext*/
-  __pyx_methods_5_cdec_HypergraphEdge, /*tp_methods*/
+  __pyx_methods_5_cdec_Lattice, /*tp_methods*/
   0, /*tp_members*/
-  __pyx_getsets_5_cdec_HypergraphEdge, /*tp_getset*/
+  0, /*tp_getset*/
   0, /*tp_base*/
   0, /*tp_dict*/
   0, /*tp_descr_get*/
@@ -15021,7 +18984,7 @@ static PyTypeObject __pyx_type_5_cdec_HypergraphEdge = {
   0, /*tp_dictoffset*/
   0, /*tp_init*/
   0, /*tp_alloc*/
-  __pyx_tp_new_5_cdec_HypergraphEdge, /*tp_new*/
+  __pyx_tp_new_5_cdec_Lattice, /*tp_new*/
   0, /*tp_free*/
   0, /*tp_is_gc*/
   0, /*tp_bases*/
@@ -15034,50 +18997,51 @@ static PyTypeObject __pyx_type_5_cdec_HypergraphEdge = {
   0, /*tp_version_tag*/
   #endif
 };
-static struct __pyx_vtabstruct_5_cdec_HypergraphNode __pyx_vtable_5_cdec_HypergraphNode;
 
-static PyObject *__pyx_tp_new_5_cdec_HypergraphNode(PyTypeObject *t, PyObject *a, PyObject *k) {
-  struct __pyx_obj_5_cdec_HypergraphNode *p;
+static PyObject *__pyx_tp_new_5_cdec_Candidate(PyTypeObject *t, PyObject *a, PyObject *k) {
   PyObject *o = (*t->tp_alloc)(t, 0);
   if (!o) return 0;
-  p = ((struct __pyx_obj_5_cdec_HypergraphNode *)o);
-  p->__pyx_vtab = __pyx_vtabptr_5_cdec_HypergraphNode;
   return o;
 }
 
-static void __pyx_tp_dealloc_5_cdec_HypergraphNode(PyObject *o) {
+static void __pyx_tp_dealloc_5_cdec_Candidate(PyObject *o) {
   (*Py_TYPE(o)->tp_free)(o);
 }
 
-static PyObject *__pyx_getprop_5_cdec_14HypergraphNode_in_edges(PyObject *o, void *x) {
-  return __pyx_pw_5_cdec_14HypergraphNode_8in_edges_1__get__(o);
+static PyObject *__pyx_getprop_5_cdec_9Candidate_words(PyObject *o, void *x) {
+  return __pyx_pw_5_cdec_9Candidate_5words_1__get__(o);
 }
 
-static PyObject *__pyx_getprop_5_cdec_14HypergraphNode_out_edges(PyObject *o, void *x) {
-  return __pyx_pw_5_cdec_14HypergraphNode_9out_edges_1__get__(o);
+static PyObject *__pyx_getprop_5_cdec_9Candidate_fmap(PyObject *o, void *x) {
+  return __pyx_pw_5_cdec_9Candidate_4fmap_1__get__(o);
 }
 
-static PyObject *__pyx_getprop_5_cdec_14HypergraphNode_span(PyObject *o, void *x) {
-  return __pyx_pw_5_cdec_14HypergraphNode_4span_1__get__(o);
+static PyObject *__pyx_getprop_5_cdec_9Candidate_score(PyObject *o, void *x) {
+  return __pyx_pw_5_cdec_9Candidate_5score_1__get__(o);
 }
 
-static PyObject *__pyx_getprop_5_cdec_14HypergraphNode_cat(PyObject *o, void *x) {
-  return __pyx_pw_5_cdec_14HypergraphNode_3cat_1__get__(o);
+static int __pyx_setprop_5_cdec_9Candidate_score(PyObject *o, PyObject *v, void *x) {
+  if (v) {
+    return __pyx_pw_5_cdec_9Candidate_5score_3__set__(o, v);
+  }
+  else {
+    PyErr_SetString(PyExc_NotImplementedError, "__del__");
+    return -1;
+  }
 }
 
-static PyMethodDef __pyx_methods_5_cdec_HypergraphNode[] = {
+static PyMethodDef __pyx_methods_5_cdec_Candidate[] = {
   {0, 0, 0, 0}
 };
 
-static struct PyGetSetDef __pyx_getsets_5_cdec_HypergraphNode[] = {
-  {(char *)"in_edges", __pyx_getprop_5_cdec_14HypergraphNode_in_edges, 0, 0, 0},
-  {(char *)"out_edges", __pyx_getprop_5_cdec_14HypergraphNode_out_edges, 0, 0, 0},
-  {(char *)"span", __pyx_getprop_5_cdec_14HypergraphNode_span, 0, 0, 0},
-  {(char *)"cat", __pyx_getprop_5_cdec_14HypergraphNode_cat, 0, 0, 0},
+static struct PyGetSetDef __pyx_getsets_5_cdec_Candidate[] = {
+  {(char *)"words", __pyx_getprop_5_cdec_9Candidate_words, 0, 0, 0},
+  {(char *)"fmap", __pyx_getprop_5_cdec_9Candidate_fmap, 0, 0, 0},
+  {(char *)"score", __pyx_getprop_5_cdec_9Candidate_score, __pyx_setprop_5_cdec_9Candidate_score, 0, 0},
   {0, 0, 0, 0, 0}
 };
 
-static PyNumberMethods __pyx_tp_as_number_HypergraphNode = {
+static PyNumberMethods __pyx_tp_as_number_Candidate = {
   0, /*nb_add*/
   0, /*nb_subtract*/
   0, /*nb_multiply*/
@@ -15135,7 +19099,7 @@ static PyNumberMethods __pyx_tp_as_number_HypergraphNode = {
   #endif
 };
 
-static PySequenceMethods __pyx_tp_as_sequence_HypergraphNode = {
+static PySequenceMethods __pyx_tp_as_sequence_Candidate = {
   0, /*sq_length*/
   0, /*sq_concat*/
   0, /*sq_repeat*/
@@ -15148,13 +19112,13 @@ static PySequenceMethods __pyx_tp_as_sequence_HypergraphNode = {
   0, /*sq_inplace_repeat*/
 };
 
-static PyMappingMethods __pyx_tp_as_mapping_HypergraphNode = {
+static PyMappingMethods __pyx_tp_as_mapping_Candidate = {
   0, /*mp_length*/
   0, /*mp_subscript*/
   0, /*mp_ass_subscript*/
 };
 
-static PyBufferProcs __pyx_tp_as_buffer_HypergraphNode = {
+static PyBufferProcs __pyx_tp_as_buffer_Candidate = {
   #if PY_MAJOR_VERSION < 3
   0, /*bf_getreadbuffer*/
   #endif
@@ -15175,12 +19139,12 @@ static PyBufferProcs __pyx_tp_as_buffer_HypergraphNode = {
   #endif
 };
 
-static PyTypeObject __pyx_type_5_cdec_HypergraphNode = {
+static PyTypeObject __pyx_type_5_cdec_Candidate = {
   PyVarObject_HEAD_INIT(0, 0)
-  __Pyx_NAMESTR("_cdec.HypergraphNode"), /*tp_name*/
-  sizeof(struct __pyx_obj_5_cdec_HypergraphNode), /*tp_basicsize*/
+  __Pyx_NAMESTR("_cdec.Candidate"), /*tp_name*/
+  sizeof(struct __pyx_obj_5_cdec_Candidate), /*tp_basicsize*/
   0, /*tp_itemsize*/
-  __pyx_tp_dealloc_5_cdec_HypergraphNode, /*tp_dealloc*/
+  __pyx_tp_dealloc_5_cdec_Candidate, /*tp_dealloc*/
   0, /*tp_print*/
   0, /*tp_getattr*/
   0, /*tp_setattr*/
@@ -15190,26 +19154,26 @@ static PyTypeObject __pyx_type_5_cdec_HypergraphNode = {
   0, /*reserved*/
   #endif
   0, /*tp_repr*/
-  &__pyx_tp_as_number_HypergraphNode, /*tp_as_number*/
-  &__pyx_tp_as_sequence_HypergraphNode, /*tp_as_sequence*/
-  &__pyx_tp_as_mapping_HypergraphNode, /*tp_as_mapping*/
+  &__pyx_tp_as_number_Candidate, /*tp_as_number*/
+  &__pyx_tp_as_sequence_Candidate, /*tp_as_sequence*/
+  &__pyx_tp_as_mapping_Candidate, /*tp_as_mapping*/
   0, /*tp_hash*/
   0, /*tp_call*/
   0, /*tp_str*/
   0, /*tp_getattro*/
   0, /*tp_setattro*/
-  &__pyx_tp_as_buffer_HypergraphNode, /*tp_as_buffer*/
+  &__pyx_tp_as_buffer_Candidate, /*tp_as_buffer*/
   Py_TPFLAGS_DEFAULT|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_BASETYPE, /*tp_flags*/
   0, /*tp_doc*/
   0, /*tp_traverse*/
   0, /*tp_clear*/
-  __pyx_pw_5_cdec_14HypergraphNode_1__richcmp__, /*tp_richcompare*/
+  0, /*tp_richcompare*/
   0, /*tp_weaklistoffset*/
   0, /*tp_iter*/
   0, /*tp_iternext*/
-  __pyx_methods_5_cdec_HypergraphNode, /*tp_methods*/
+  __pyx_methods_5_cdec_Candidate, /*tp_methods*/
   0, /*tp_members*/
-  __pyx_getsets_5_cdec_HypergraphNode, /*tp_getset*/
+  __pyx_getsets_5_cdec_Candidate, /*tp_getset*/
   0, /*tp_base*/
   0, /*tp_dict*/
   0, /*tp_descr_get*/
@@ -15217,7 +19181,7 @@ static PyTypeObject __pyx_type_5_cdec_HypergraphNode = {
   0, /*tp_dictoffset*/
   0, /*tp_init*/
   0, /*tp_alloc*/
-  __pyx_tp_new_5_cdec_HypergraphNode, /*tp_new*/
+  __pyx_tp_new_5_cdec_Candidate, /*tp_new*/
   0, /*tp_free*/
   0, /*tp_is_gc*/
   0, /*tp_bases*/
@@ -15231,50 +19195,45 @@ static PyTypeObject __pyx_type_5_cdec_HypergraphNode = {
   #endif
 };
 
-static PyObject *__pyx_tp_new_5_cdec_Lattice(PyTypeObject *t, PyObject *a, PyObject *k) {
+static PyObject *__pyx_tp_new_5_cdec_SufficientStats(PyTypeObject *t, PyObject *a, PyObject *k) {
   PyObject *o = (*t->tp_alloc)(t, 0);
   if (!o) return 0;
   return o;
 }
 
-static void __pyx_tp_dealloc_5_cdec_Lattice(PyObject *o) {
+static void __pyx_tp_dealloc_5_cdec_SufficientStats(PyObject *o) {
   {
     PyObject *etype, *eval, *etb;
     PyErr_Fetch(&etype, &eval, &etb);
     ++Py_REFCNT(o);
-    __pyx_pw_5_cdec_7Lattice_14__dealloc__(o);
+    __pyx_pw_5_cdec_15SufficientStats_1__dealloc__(o);
     if (PyErr_Occurred()) PyErr_WriteUnraisable(o);
     --Py_REFCNT(o);
     PyErr_Restore(etype, eval, etb);
   }
   (*Py_TYPE(o)->tp_free)(o);
 }
-static PyObject *__pyx_sq_item_5_cdec_Lattice(PyObject *o, Py_ssize_t i) {
-  PyObject *r;
-  PyObject *x = PyInt_FromSsize_t(i); if(!x) return 0;
-  r = Py_TYPE(o)->tp_as_mapping->mp_subscript(o, x);
-  Py_DECREF(x);
-  return r;
+
+static PyObject *__pyx_getprop_5_cdec_15SufficientStats_score(PyObject *o, void *x) {
+  return __pyx_pw_5_cdec_15SufficientStats_5score_1__get__(o);
 }
 
-static int __pyx_mp_ass_subscript_5_cdec_Lattice(PyObject *o, PyObject *i, PyObject *v) {
-  if (v) {
-    return __pyx_pw_5_cdec_7Lattice_5__setitem__(o, i, v);
-  }
-  else {
-    PyErr_Format(PyExc_NotImplementedError,
-      "Subscript deletion not supported by %s", Py_TYPE(o)->tp_name);
-    return -1;
-  }
+static PyObject *__pyx_getprop_5_cdec_15SufficientStats_detail(PyObject *o, void *x) {
+  return __pyx_pw_5_cdec_15SufficientStats_6detail_1__get__(o);
 }
 
-static PyMethodDef __pyx_methods_5_cdec_Lattice[] = {
-  {__Pyx_NAMESTR("todot"), (PyCFunction)__pyx_pw_5_cdec_7Lattice_16todot, METH_NOARGS, __Pyx_DOCSTR(0)},
+static PyMethodDef __pyx_methods_5_cdec_SufficientStats[] = {
   {0, 0, 0, 0}
 };
 
-static PyNumberMethods __pyx_tp_as_number_Lattice = {
-  0, /*nb_add*/
+static struct PyGetSetDef __pyx_getsets_5_cdec_SufficientStats[] = {
+  {(char *)"score", __pyx_getprop_5_cdec_15SufficientStats_score, 0, 0, 0},
+  {(char *)"detail", __pyx_getprop_5_cdec_15SufficientStats_detail, 0, 0, 0},
+  {0, 0, 0, 0, 0}
+};
+
+static PyNumberMethods __pyx_tp_as_number_SufficientStats = {
+  __pyx_pw_5_cdec_15SufficientStats_10__add__, /*nb_add*/
   0, /*nb_subtract*/
   0, /*nb_multiply*/
   #if PY_MAJOR_VERSION < 3
@@ -15309,7 +19268,7 @@ static PyNumberMethods __pyx_tp_as_number_Lattice = {
   #if PY_MAJOR_VERSION < 3
   0, /*nb_hex*/
   #endif
-  0, /*nb_inplace_add*/
+  __pyx_pw_5_cdec_15SufficientStats_8__iadd__, /*nb_inplace_add*/
   0, /*nb_inplace_subtract*/
   0, /*nb_inplace_multiply*/
   #if PY_MAJOR_VERSION < 3
@@ -15331,11 +19290,11 @@ static PyNumberMethods __pyx_tp_as_number_Lattice = {
   #endif
 };
 
-static PySequenceMethods __pyx_tp_as_sequence_Lattice = {
-  __pyx_pw_5_cdec_7Lattice_7__len__, /*sq_length*/
+static PySequenceMethods __pyx_tp_as_sequence_SufficientStats = {
+  __pyx_pw_5_cdec_15SufficientStats_3__len__, /*sq_length*/
   0, /*sq_concat*/
   0, /*sq_repeat*/
-  __pyx_sq_item_5_cdec_Lattice, /*sq_item*/
+  0, /*sq_item*/
   0, /*sq_slice*/
   0, /*sq_ass_item*/
   0, /*sq_ass_slice*/
@@ -15344,13 +19303,13 @@ static PySequenceMethods __pyx_tp_as_sequence_Lattice = {
   0, /*sq_inplace_repeat*/
 };
 
-static PyMappingMethods __pyx_tp_as_mapping_Lattice = {
-  __pyx_pw_5_cdec_7Lattice_7__len__, /*mp_length*/
-  __pyx_pw_5_cdec_7Lattice_3__getitem__, /*mp_subscript*/
-  __pyx_mp_ass_subscript_5_cdec_Lattice, /*mp_ass_subscript*/
+static PyMappingMethods __pyx_tp_as_mapping_SufficientStats = {
+  __pyx_pw_5_cdec_15SufficientStats_3__len__, /*mp_length*/
+  0, /*mp_subscript*/
+  0, /*mp_ass_subscript*/
 };
 
-static PyBufferProcs __pyx_tp_as_buffer_Lattice = {
+static PyBufferProcs __pyx_tp_as_buffer_SufficientStats = {
   #if PY_MAJOR_VERSION < 3
   0, /*bf_getreadbuffer*/
   #endif
@@ -15371,12 +19330,12 @@ static PyBufferProcs __pyx_tp_as_buffer_Lattice = {
   #endif
 };
 
-static PyTypeObject __pyx_type_5_cdec_Lattice = {
+static PyTypeObject __pyx_type_5_cdec_SufficientStats = {
   PyVarObject_HEAD_INIT(0, 0)
-  __Pyx_NAMESTR("_cdec.Lattice"), /*tp_name*/
-  sizeof(struct __pyx_obj_5_cdec_Lattice), /*tp_basicsize*/
+  __Pyx_NAMESTR("_cdec.SufficientStats"), /*tp_name*/
+  sizeof(struct __pyx_obj_5_cdec_SufficientStats), /*tp_basicsize*/
   0, /*tp_itemsize*/
-  __pyx_tp_dealloc_5_cdec_Lattice, /*tp_dealloc*/
+  __pyx_tp_dealloc_5_cdec_SufficientStats, /*tp_dealloc*/
   0, /*tp_print*/
   0, /*tp_getattr*/
   0, /*tp_setattr*/
@@ -15386,34 +19345,34 @@ static PyTypeObject __pyx_type_5_cdec_Lattice = {
   0, /*reserved*/
   #endif
   0, /*tp_repr*/
-  &__pyx_tp_as_number_Lattice, /*tp_as_number*/
-  &__pyx_tp_as_sequence_Lattice, /*tp_as_sequence*/
-  &__pyx_tp_as_mapping_Lattice, /*tp_as_mapping*/
+  &__pyx_tp_as_number_SufficientStats, /*tp_as_number*/
+  &__pyx_tp_as_sequence_SufficientStats, /*tp_as_sequence*/
+  &__pyx_tp_as_mapping_SufficientStats, /*tp_as_mapping*/
   0, /*tp_hash*/
   0, /*tp_call*/
-  __pyx_pw_5_cdec_7Lattice_9__str__, /*tp_str*/
+  0, /*tp_str*/
   0, /*tp_getattro*/
   0, /*tp_setattro*/
-  &__pyx_tp_as_buffer_Lattice, /*tp_as_buffer*/
+  &__pyx_tp_as_buffer_SufficientStats, /*tp_as_buffer*/
   Py_TPFLAGS_DEFAULT|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_BASETYPE, /*tp_flags*/
   0, /*tp_doc*/
   0, /*tp_traverse*/
   0, /*tp_clear*/
   0, /*tp_richcompare*/
   0, /*tp_weaklistoffset*/
-  __pyx_pw_5_cdec_7Lattice_11__iter__, /*tp_iter*/
+  __pyx_pw_5_cdec_15SufficientStats_5__iter__, /*tp_iter*/
   0, /*tp_iternext*/
-  __pyx_methods_5_cdec_Lattice, /*tp_methods*/
+  __pyx_methods_5_cdec_SufficientStats, /*tp_methods*/
   0, /*tp_members*/
-  0, /*tp_getset*/
+  __pyx_getsets_5_cdec_SufficientStats, /*tp_getset*/
   0, /*tp_base*/
   0, /*tp_dict*/
   0, /*tp_descr_get*/
   0, /*tp_descr_set*/
   0, /*tp_dictoffset*/
-  __pyx_pw_5_cdec_7Lattice_1__init__, /*tp_init*/
+  0, /*tp_init*/
   0, /*tp_alloc*/
-  __pyx_tp_new_5_cdec_Lattice, /*tp_new*/
+  __pyx_tp_new_5_cdec_SufficientStats, /*tp_new*/
   0, /*tp_free*/
   0, /*tp_is_gc*/
   0, /*tp_bases*/
@@ -15427,50 +19386,41 @@ static PyTypeObject __pyx_type_5_cdec_Lattice = {
   #endif
 };
 
-static PyObject *__pyx_tp_new_5_cdec_Candidate(PyTypeObject *t, PyObject *a, PyObject *k) {
+static PyObject *__pyx_tp_new_5_cdec_CandidateSet(PyTypeObject *t, PyObject *a, PyObject *k) {
   PyObject *o = (*t->tp_alloc)(t, 0);
   if (!o) return 0;
+  if (__pyx_pw_5_cdec_12CandidateSet_1__cinit__(o, a, k) < 0) {
+    Py_DECREF(o); o = 0;
+  }
   return o;
 }
 
-static void __pyx_tp_dealloc_5_cdec_Candidate(PyObject *o) {
+static void __pyx_tp_dealloc_5_cdec_CandidateSet(PyObject *o) {
+  {
+    PyObject *etype, *eval, *etb;
+    PyErr_Fetch(&etype, &eval, &etb);
+    ++Py_REFCNT(o);
+    __pyx_pw_5_cdec_12CandidateSet_3__dealloc__(o);
+    if (PyErr_Occurred()) PyErr_WriteUnraisable(o);
+    --Py_REFCNT(o);
+    PyErr_Restore(etype, eval, etb);
+  }
   (*Py_TYPE(o)->tp_free)(o);
 }
-
-static PyObject *__pyx_getprop_5_cdec_9Candidate_words(PyObject *o, void *x) {
-  return __pyx_pw_5_cdec_9Candidate_5words_1__get__(o);
-}
-
-static PyObject *__pyx_getprop_5_cdec_9Candidate_fmap(PyObject *o, void *x) {
-  return __pyx_pw_5_cdec_9Candidate_4fmap_1__get__(o);
-}
-
-static PyObject *__pyx_getprop_5_cdec_9Candidate_score(PyObject *o, void *x) {
-  return __pyx_pw_5_cdec_9Candidate_5score_1__get__(o);
-}
-
-static int __pyx_setprop_5_cdec_9Candidate_score(PyObject *o, PyObject *v, void *x) {
-  if (v) {
-    return __pyx_pw_5_cdec_9Candidate_5score_3__set__(o, v);
-  }
-  else {
-    PyErr_SetString(PyExc_NotImplementedError, "__del__");
-    return -1;
-  }
+static PyObject *__pyx_sq_item_5_cdec_CandidateSet(PyObject *o, Py_ssize_t i) {
+  PyObject *r;
+  PyObject *x = PyInt_FromSsize_t(i); if(!x) return 0;
+  r = Py_TYPE(o)->tp_as_mapping->mp_subscript(o, x);
+  Py_DECREF(x);
+  return r;
 }
 
-static PyMethodDef __pyx_methods_5_cdec_Candidate[] = {
+static PyMethodDef __pyx_methods_5_cdec_CandidateSet[] = {
+  {__Pyx_NAMESTR("add_kbest"), (PyCFunction)__pyx_pw_5_cdec_12CandidateSet_12add_kbest, METH_VARARGS|METH_KEYWORDS, __Pyx_DOCSTR(0)},
   {0, 0, 0, 0}
 };
 
-static struct PyGetSetDef __pyx_getsets_5_cdec_Candidate[] = {
-  {(char *)"words", __pyx_getprop_5_cdec_9Candidate_words, 0, 0, 0},
-  {(char *)"fmap", __pyx_getprop_5_cdec_9Candidate_fmap, 0, 0, 0},
-  {(char *)"score", __pyx_getprop_5_cdec_9Candidate_score, __pyx_setprop_5_cdec_9Candidate_score, 0, 0},
-  {0, 0, 0, 0, 0}
-};
-
-static PyNumberMethods __pyx_tp_as_number_Candidate = {
+static PyNumberMethods __pyx_tp_as_number_CandidateSet = {
   0, /*nb_add*/
   0, /*nb_subtract*/
   0, /*nb_multiply*/
@@ -15528,11 +19478,11 @@ static PyNumberMethods __pyx_tp_as_number_Candidate = {
   #endif
 };
 
-static PySequenceMethods __pyx_tp_as_sequence_Candidate = {
-  0, /*sq_length*/
+static PySequenceMethods __pyx_tp_as_sequence_CandidateSet = {
+  __pyx_pw_5_cdec_12CandidateSet_5__len__, /*sq_length*/
   0, /*sq_concat*/
   0, /*sq_repeat*/
-  0, /*sq_item*/
+  __pyx_sq_item_5_cdec_CandidateSet, /*sq_item*/
   0, /*sq_slice*/
   0, /*sq_ass_item*/
   0, /*sq_ass_slice*/
@@ -15541,13 +19491,13 @@ static PySequenceMethods __pyx_tp_as_sequence_Candidate = {
   0, /*sq_inplace_repeat*/
 };
 
-static PyMappingMethods __pyx_tp_as_mapping_Candidate = {
-  0, /*mp_length*/
-  0, /*mp_subscript*/
+static PyMappingMethods __pyx_tp_as_mapping_CandidateSet = {
+  __pyx_pw_5_cdec_12CandidateSet_5__len__, /*mp_length*/
+  __pyx_pw_5_cdec_12CandidateSet_7__getitem__, /*mp_subscript*/
   0, /*mp_ass_subscript*/
 };
 
-static PyBufferProcs __pyx_tp_as_buffer_Candidate = {
+static PyBufferProcs __pyx_tp_as_buffer_CandidateSet = {
   #if PY_MAJOR_VERSION < 3
   0, /*bf_getreadbuffer*/
   #endif
@@ -15568,12 +19518,12 @@ static PyBufferProcs __pyx_tp_as_buffer_Candidate = {
   #endif
 };
 
-static PyTypeObject __pyx_type_5_cdec_Candidate = {
+static PyTypeObject __pyx_type_5_cdec_CandidateSet = {
   PyVarObject_HEAD_INIT(0, 0)
-  __Pyx_NAMESTR("_cdec.Candidate"), /*tp_name*/
-  sizeof(struct __pyx_obj_5_cdec_Candidate), /*tp_basicsize*/
+  __Pyx_NAMESTR("_cdec.CandidateSet"), /*tp_name*/
+  sizeof(struct __pyx_obj_5_cdec_CandidateSet), /*tp_basicsize*/
   0, /*tp_itemsize*/
-  __pyx_tp_dealloc_5_cdec_Candidate, /*tp_dealloc*/
+  __pyx_tp_dealloc_5_cdec_CandidateSet, /*tp_dealloc*/
   0, /*tp_print*/
   0, /*tp_getattr*/
   0, /*tp_setattr*/
@@ -15583,26 +19533,26 @@ static PyTypeObject __pyx_type_5_cdec_Candidate = {
   0, /*reserved*/
   #endif
   0, /*tp_repr*/
-  &__pyx_tp_as_number_Candidate, /*tp_as_number*/
-  &__pyx_tp_as_sequence_Candidate, /*tp_as_sequence*/
-  &__pyx_tp_as_mapping_Candidate, /*tp_as_mapping*/
+  &__pyx_tp_as_number_CandidateSet, /*tp_as_number*/
+  &__pyx_tp_as_sequence_CandidateSet, /*tp_as_sequence*/
+  &__pyx_tp_as_mapping_CandidateSet, /*tp_as_mapping*/
   0, /*tp_hash*/
   0, /*tp_call*/
   0, /*tp_str*/
   0, /*tp_getattro*/
   0, /*tp_setattro*/
-  &__pyx_tp_as_buffer_Candidate, /*tp_as_buffer*/
+  &__pyx_tp_as_buffer_CandidateSet, /*tp_as_buffer*/
   Py_TPFLAGS_DEFAULT|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_BASETYPE, /*tp_flags*/
   0, /*tp_doc*/
   0, /*tp_traverse*/
   0, /*tp_clear*/
   0, /*tp_richcompare*/
   0, /*tp_weaklistoffset*/
-  0, /*tp_iter*/
+  __pyx_pw_5_cdec_12CandidateSet_9__iter__, /*tp_iter*/
   0, /*tp_iternext*/
-  __pyx_methods_5_cdec_Candidate, /*tp_methods*/
+  __pyx_methods_5_cdec_CandidateSet, /*tp_methods*/
   0, /*tp_members*/
-  __pyx_getsets_5_cdec_Candidate, /*tp_getset*/
+  0, /*tp_getset*/
   0, /*tp_base*/
   0, /*tp_dict*/
   0, /*tp_descr_get*/
@@ -15610,7 +19560,7 @@ static PyTypeObject __pyx_type_5_cdec_Candidate = {
   0, /*tp_dictoffset*/
   0, /*tp_init*/
   0, /*tp_alloc*/
-  __pyx_tp_new_5_cdec_Candidate, /*tp_new*/
+  __pyx_tp_new_5_cdec_CandidateSet, /*tp_new*/
   0, /*tp_free*/
   0, /*tp_is_gc*/
   0, /*tp_bases*/
@@ -15624,18 +19574,18 @@ static PyTypeObject __pyx_type_5_cdec_Candidate = {
   #endif
 };
 
-static PyObject *__pyx_tp_new_5_cdec_SufficientStats(PyTypeObject *t, PyObject *a, PyObject *k) {
+static PyObject *__pyx_tp_new_5_cdec_SegmentEvaluator(PyTypeObject *t, PyObject *a, PyObject *k) {
   PyObject *o = (*t->tp_alloc)(t, 0);
   if (!o) return 0;
   return o;
 }
 
-static void __pyx_tp_dealloc_5_cdec_SufficientStats(PyObject *o) {
+static void __pyx_tp_dealloc_5_cdec_SegmentEvaluator(PyObject *o) {
   {
     PyObject *etype, *eval, *etb;
     PyErr_Fetch(&etype, &eval, &etb);
     ++Py_REFCNT(o);
-    __pyx_pw_5_cdec_15SufficientStats_1__dealloc__(o);
+    __pyx_pw_5_cdec_16SegmentEvaluator_1__dealloc__(o);
     if (PyErr_Occurred()) PyErr_WriteUnraisable(o);
     --Py_REFCNT(o);
     PyErr_Restore(etype, eval, etb);
@@ -15643,26 +19593,14 @@ static void __pyx_tp_dealloc_5_cdec_SufficientStats(PyObject *o) {
   (*Py_TYPE(o)->tp_free)(o);
 }
 
-static PyObject *__pyx_getprop_5_cdec_15SufficientStats_score(PyObject *o, void *x) {
-  return __pyx_pw_5_cdec_15SufficientStats_5score_1__get__(o);
-}
-
-static PyObject *__pyx_getprop_5_cdec_15SufficientStats_detail(PyObject *o, void *x) {
-  return __pyx_pw_5_cdec_15SufficientStats_6detail_1__get__(o);
-}
-
-static PyMethodDef __pyx_methods_5_cdec_SufficientStats[] = {
+static PyMethodDef __pyx_methods_5_cdec_SegmentEvaluator[] = {
+  {__Pyx_NAMESTR("evaluate"), (PyCFunction)__pyx_pw_5_cdec_16SegmentEvaluator_3evaluate, METH_O, __Pyx_DOCSTR(0)},
+  {__Pyx_NAMESTR("candidate_set"), (PyCFunction)__pyx_pw_5_cdec_16SegmentEvaluator_5candidate_set, METH_NOARGS, __Pyx_DOCSTR(0)},
   {0, 0, 0, 0}
 };
 
-static struct PyGetSetDef __pyx_getsets_5_cdec_SufficientStats[] = {
-  {(char *)"score", __pyx_getprop_5_cdec_15SufficientStats_score, 0, 0, 0},
-  {(char *)"detail", __pyx_getprop_5_cdec_15SufficientStats_detail, 0, 0, 0},
-  {0, 0, 0, 0, 0}
-};
-
-static PyNumberMethods __pyx_tp_as_number_SufficientStats = {
-  __pyx_pw_5_cdec_15SufficientStats_10__add__, /*nb_add*/
+static PyNumberMethods __pyx_tp_as_number_SegmentEvaluator = {
+  0, /*nb_add*/
   0, /*nb_subtract*/
   0, /*nb_multiply*/
   #if PY_MAJOR_VERSION < 3
@@ -15697,7 +19635,7 @@ static PyNumberMethods __pyx_tp_as_number_SufficientStats = {
   #if PY_MAJOR_VERSION < 3
   0, /*nb_hex*/
   #endif
-  __pyx_pw_5_cdec_15SufficientStats_8__iadd__, /*nb_inplace_add*/
+  0, /*nb_inplace_add*/
   0, /*nb_inplace_subtract*/
   0, /*nb_inplace_multiply*/
   #if PY_MAJOR_VERSION < 3
@@ -15719,8 +19657,8 @@ static PyNumberMethods __pyx_tp_as_number_SufficientStats = {
   #endif
 };
 
-static PySequenceMethods __pyx_tp_as_sequence_SufficientStats = {
-  __pyx_pw_5_cdec_15SufficientStats_3__len__, /*sq_length*/
+static PySequenceMethods __pyx_tp_as_sequence_SegmentEvaluator = {
+  0, /*sq_length*/
   0, /*sq_concat*/
   0, /*sq_repeat*/
   0, /*sq_item*/
@@ -15732,13 +19670,13 @@ static PySequenceMethods __pyx_tp_as_sequence_SufficientStats = {
   0, /*sq_inplace_repeat*/
 };
 
-static PyMappingMethods __pyx_tp_as_mapping_SufficientStats = {
-  __pyx_pw_5_cdec_15SufficientStats_3__len__, /*mp_length*/
+static PyMappingMethods __pyx_tp_as_mapping_SegmentEvaluator = {
+  0, /*mp_length*/
   0, /*mp_subscript*/
   0, /*mp_ass_subscript*/
 };
 
-static PyBufferProcs __pyx_tp_as_buffer_SufficientStats = {
+static PyBufferProcs __pyx_tp_as_buffer_SegmentEvaluator = {
   #if PY_MAJOR_VERSION < 3
   0, /*bf_getreadbuffer*/
   #endif
@@ -15759,12 +19697,12 @@ static PyBufferProcs __pyx_tp_as_buffer_SufficientStats = {
   #endif
 };
 
-static PyTypeObject __pyx_type_5_cdec_SufficientStats = {
+static PyTypeObject __pyx_type_5_cdec_SegmentEvaluator = {
   PyVarObject_HEAD_INIT(0, 0)
-  __Pyx_NAMESTR("_cdec.SufficientStats"), /*tp_name*/
-  sizeof(struct __pyx_obj_5_cdec_SufficientStats), /*tp_basicsize*/
+  __Pyx_NAMESTR("_cdec.SegmentEvaluator"), /*tp_name*/
+  sizeof(struct __pyx_obj_5_cdec_SegmentEvaluator), /*tp_basicsize*/
   0, /*tp_itemsize*/
-  __pyx_tp_dealloc_5_cdec_SufficientStats, /*tp_dealloc*/
+  __pyx_tp_dealloc_5_cdec_SegmentEvaluator, /*tp_dealloc*/
   0, /*tp_print*/
   0, /*tp_getattr*/
   0, /*tp_setattr*/
@@ -15774,26 +19712,26 @@ static PyTypeObject __pyx_type_5_cdec_SufficientStats = {
   0, /*reserved*/
   #endif
   0, /*tp_repr*/
-  &__pyx_tp_as_number_SufficientStats, /*tp_as_number*/
-  &__pyx_tp_as_sequence_SufficientStats, /*tp_as_sequence*/
-  &__pyx_tp_as_mapping_SufficientStats, /*tp_as_mapping*/
+  &__pyx_tp_as_number_SegmentEvaluator, /*tp_as_number*/
+  &__pyx_tp_as_sequence_SegmentEvaluator, /*tp_as_sequence*/
+  &__pyx_tp_as_mapping_SegmentEvaluator, /*tp_as_mapping*/
   0, /*tp_hash*/
   0, /*tp_call*/
   0, /*tp_str*/
   0, /*tp_getattro*/
   0, /*tp_setattro*/
-  &__pyx_tp_as_buffer_SufficientStats, /*tp_as_buffer*/
+  &__pyx_tp_as_buffer_SegmentEvaluator, /*tp_as_buffer*/
   Py_TPFLAGS_DEFAULT|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_BASETYPE, /*tp_flags*/
   0, /*tp_doc*/
   0, /*tp_traverse*/
   0, /*tp_clear*/
   0, /*tp_richcompare*/
   0, /*tp_weaklistoffset*/
-  __pyx_pw_5_cdec_15SufficientStats_5__iter__, /*tp_iter*/
+  0, /*tp_iter*/
   0, /*tp_iternext*/
-  __pyx_methods_5_cdec_SufficientStats, /*tp_methods*/
+  __pyx_methods_5_cdec_SegmentEvaluator, /*tp_methods*/
   0, /*tp_members*/
-  __pyx_getsets_5_cdec_SufficientStats, /*tp_getset*/
+  0, /*tp_getset*/
   0, /*tp_base*/
   0, /*tp_dict*/
   0, /*tp_descr_get*/
@@ -15801,7 +19739,7 @@ static PyTypeObject __pyx_type_5_cdec_SufficientStats = {
   0, /*tp_dictoffset*/
   0, /*tp_init*/
   0, /*tp_alloc*/
-  __pyx_tp_new_5_cdec_SufficientStats, /*tp_new*/
+  __pyx_tp_new_5_cdec_SegmentEvaluator, /*tp_new*/
   0, /*tp_free*/
   0, /*tp_is_gc*/
   0, /*tp_bases*/
@@ -15815,41 +19753,33 @@ static PyTypeObject __pyx_type_5_cdec_SufficientStats = {
   #endif
 };
 
-static PyObject *__pyx_tp_new_5_cdec_CandidateSet(PyTypeObject *t, PyObject *a, PyObject *k) {
+static PyObject *__pyx_tp_new_5_cdec_Scorer(PyTypeObject *t, PyObject *a, PyObject *k) {
   PyObject *o = (*t->tp_alloc)(t, 0);
   if (!o) return 0;
-  if (__pyx_pw_5_cdec_12CandidateSet_1__cinit__(o, a, k) < 0) {
+  if (__pyx_pw_5_cdec_6Scorer_1__cinit__(o, a, k) < 0) {
     Py_DECREF(o); o = 0;
   }
   return o;
 }
 
-static void __pyx_tp_dealloc_5_cdec_CandidateSet(PyObject *o) {
+static void __pyx_tp_dealloc_5_cdec_Scorer(PyObject *o) {
   {
     PyObject *etype, *eval, *etb;
     PyErr_Fetch(&etype, &eval, &etb);
     ++Py_REFCNT(o);
-    __pyx_pw_5_cdec_12CandidateSet_3__dealloc__(o);
+    __pyx_pw_5_cdec_6Scorer_3__dealloc__(o);
     if (PyErr_Occurred()) PyErr_WriteUnraisable(o);
     --Py_REFCNT(o);
     PyErr_Restore(etype, eval, etb);
   }
   (*Py_TYPE(o)->tp_free)(o);
 }
-static PyObject *__pyx_sq_item_5_cdec_CandidateSet(PyObject *o, Py_ssize_t i) {
-  PyObject *r;
-  PyObject *x = PyInt_FromSsize_t(i); if(!x) return 0;
-  r = Py_TYPE(o)->tp_as_mapping->mp_subscript(o, x);
-  Py_DECREF(x);
-  return r;
-}
 
-static PyMethodDef __pyx_methods_5_cdec_CandidateSet[] = {
-  {__Pyx_NAMESTR("add_kbest"), (PyCFunction)__pyx_pw_5_cdec_12CandidateSet_12add_kbest, METH_VARARGS|METH_KEYWORDS, __Pyx_DOCSTR(0)},
+static PyMethodDef __pyx_methods_5_cdec_Scorer[] = {
   {0, 0, 0, 0}
 };
 
-static PyNumberMethods __pyx_tp_as_number_CandidateSet = {
+static PyNumberMethods __pyx_tp_as_number_Scorer = {
   0, /*nb_add*/
   0, /*nb_subtract*/
   0, /*nb_multiply*/
@@ -15907,11 +19837,11 @@ static PyNumberMethods __pyx_tp_as_number_CandidateSet = {
   #endif
 };
 
-static PySequenceMethods __pyx_tp_as_sequence_CandidateSet = {
-  __pyx_pw_5_cdec_12CandidateSet_5__len__, /*sq_length*/
+static PySequenceMethods __pyx_tp_as_sequence_Scorer = {
+  0, /*sq_length*/
   0, /*sq_concat*/
   0, /*sq_repeat*/
-  __pyx_sq_item_5_cdec_CandidateSet, /*sq_item*/
+  0, /*sq_item*/
   0, /*sq_slice*/
   0, /*sq_ass_item*/
   0, /*sq_ass_slice*/
@@ -15920,13 +19850,13 @@ static PySequenceMethods __pyx_tp_as_sequence_CandidateSet = {
   0, /*sq_inplace_repeat*/
 };
 
-static PyMappingMethods __pyx_tp_as_mapping_CandidateSet = {
-  __pyx_pw_5_cdec_12CandidateSet_5__len__, /*mp_length*/
-  __pyx_pw_5_cdec_12CandidateSet_7__getitem__, /*mp_subscript*/
+static PyMappingMethods __pyx_tp_as_mapping_Scorer = {
+  0, /*mp_length*/
+  0, /*mp_subscript*/
   0, /*mp_ass_subscript*/
 };
 
-static PyBufferProcs __pyx_tp_as_buffer_CandidateSet = {
+static PyBufferProcs __pyx_tp_as_buffer_Scorer = {
   #if PY_MAJOR_VERSION < 3
   0, /*bf_getreadbuffer*/
   #endif
@@ -15947,12 +19877,12 @@ static PyBufferProcs __pyx_tp_as_buffer_CandidateSet = {
   #endif
 };
 
-static PyTypeObject __pyx_type_5_cdec_CandidateSet = {
+static PyTypeObject __pyx_type_5_cdec_Scorer = {
   PyVarObject_HEAD_INIT(0, 0)
-  __Pyx_NAMESTR("_cdec.CandidateSet"), /*tp_name*/
-  sizeof(struct __pyx_obj_5_cdec_CandidateSet), /*tp_basicsize*/
+  __Pyx_NAMESTR("_cdec.Scorer"), /*tp_name*/
+  sizeof(struct __pyx_obj_5_cdec_Scorer), /*tp_basicsize*/
   0, /*tp_itemsize*/
-  __pyx_tp_dealloc_5_cdec_CandidateSet, /*tp_dealloc*/
+  __pyx_tp_dealloc_5_cdec_Scorer, /*tp_dealloc*/
   0, /*tp_print*/
   0, /*tp_getattr*/
   0, /*tp_setattr*/
@@ -15962,24 +19892,24 @@ static PyTypeObject __pyx_type_5_cdec_CandidateSet = {
   0, /*reserved*/
   #endif
   0, /*tp_repr*/
-  &__pyx_tp_as_number_CandidateSet, /*tp_as_number*/
-  &__pyx_tp_as_sequence_CandidateSet, /*tp_as_sequence*/
-  &__pyx_tp_as_mapping_CandidateSet, /*tp_as_mapping*/
+  &__pyx_tp_as_number_Scorer, /*tp_as_number*/
+  &__pyx_tp_as_sequence_Scorer, /*tp_as_sequence*/
+  &__pyx_tp_as_mapping_Scorer, /*tp_as_mapping*/
   0, /*tp_hash*/
-  0, /*tp_call*/
-  0, /*tp_str*/
+  __pyx_pw_5_cdec_6Scorer_5__call__, /*tp_call*/
+  __pyx_pw_5_cdec_6Scorer_7__str__, /*tp_str*/
   0, /*tp_getattro*/
   0, /*tp_setattro*/
-  &__pyx_tp_as_buffer_CandidateSet, /*tp_as_buffer*/
+  &__pyx_tp_as_buffer_Scorer, /*tp_as_buffer*/
   Py_TPFLAGS_DEFAULT|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_BASETYPE, /*tp_flags*/
   0, /*tp_doc*/
   0, /*tp_traverse*/
   0, /*tp_clear*/
   0, /*tp_richcompare*/
   0, /*tp_weaklistoffset*/
-  __pyx_pw_5_cdec_12CandidateSet_9__iter__, /*tp_iter*/
+  0, /*tp_iter*/
   0, /*tp_iternext*/
-  __pyx_methods_5_cdec_CandidateSet, /*tp_methods*/
+  __pyx_methods_5_cdec_Scorer, /*tp_methods*/
   0, /*tp_members*/
   0, /*tp_getset*/
   0, /*tp_base*/
@@ -15989,7 +19919,7 @@ static PyTypeObject __pyx_type_5_cdec_CandidateSet = {
   0, /*tp_dictoffset*/
   0, /*tp_init*/
   0, /*tp_alloc*/
-  __pyx_tp_new_5_cdec_CandidateSet, /*tp_new*/
+  __pyx_tp_new_5_cdec_Scorer, /*tp_new*/
   0, /*tp_free*/
   0, /*tp_is_gc*/
   0, /*tp_bases*/
@@ -16003,32 +19933,82 @@ static PyTypeObject __pyx_type_5_cdec_CandidateSet = {
   #endif
 };
 
-static PyObject *__pyx_tp_new_5_cdec_SegmentEvaluator(PyTypeObject *t, PyObject *a, PyObject *k) {
+static PyObject *__pyx_tp_new_5_cdec_Decoder(PyTypeObject *t, PyObject *a, PyObject *k) {
+  struct __pyx_obj_5_cdec_Decoder *p;
   PyObject *o = (*t->tp_alloc)(t, 0);
   if (!o) return 0;
+  p = ((struct __pyx_obj_5_cdec_Decoder *)o);
+  p->weights = ((struct __pyx_obj_5_cdec_DenseVector *)Py_None); Py_INCREF(Py_None);
+  if (__pyx_pw_5_cdec_7Decoder_1__cinit__(o, a, k) < 0) {
+    Py_DECREF(o); o = 0;
+  }
   return o;
 }
 
-static void __pyx_tp_dealloc_5_cdec_SegmentEvaluator(PyObject *o) {
+static void __pyx_tp_dealloc_5_cdec_Decoder(PyObject *o) {
+  struct __pyx_obj_5_cdec_Decoder *p = (struct __pyx_obj_5_cdec_Decoder *)o;
   {
     PyObject *etype, *eval, *etb;
     PyErr_Fetch(&etype, &eval, &etb);
     ++Py_REFCNT(o);
-    __pyx_pw_5_cdec_16SegmentEvaluator_1__dealloc__(o);
+    __pyx_pw_5_cdec_7Decoder_3__dealloc__(o);
     if (PyErr_Occurred()) PyErr_WriteUnraisable(o);
     --Py_REFCNT(o);
     PyErr_Restore(etype, eval, etb);
   }
+  Py_XDECREF(((PyObject *)p->weights));
   (*Py_TYPE(o)->tp_free)(o);
 }
 
-static PyMethodDef __pyx_methods_5_cdec_SegmentEvaluator[] = {
-  {__Pyx_NAMESTR("evaluate"), (PyCFunction)__pyx_pw_5_cdec_16SegmentEvaluator_3evaluate, METH_O, __Pyx_DOCSTR(0)},
-  {__Pyx_NAMESTR("candidate_set"), (PyCFunction)__pyx_pw_5_cdec_16SegmentEvaluator_5candidate_set, METH_NOARGS, __Pyx_DOCSTR(0)},
+static int __pyx_tp_traverse_5_cdec_Decoder(PyObject *o, visitproc v, void *a) {
+  int e;
+  struct __pyx_obj_5_cdec_Decoder *p = (struct __pyx_obj_5_cdec_Decoder *)o;
+  if (p->weights) {
+    e = (*v)(((PyObject*)p->weights), a); if (e) return e;
+  }
+  return 0;
+}
+
+static int __pyx_tp_clear_5_cdec_Decoder(PyObject *o) {
+  struct __pyx_obj_5_cdec_Decoder *p = (struct __pyx_obj_5_cdec_Decoder *)o;
+  PyObject* tmp;
+  tmp = ((PyObject*)p->weights);
+  p->weights = ((struct __pyx_obj_5_cdec_DenseVector *)Py_None); Py_INCREF(Py_None);
+  Py_XDECREF(tmp);
+  return 0;
+}
+
+static PyObject *__pyx_getprop_5_cdec_7Decoder_weights(PyObject *o, void *x) {
+  return __pyx_pw_5_cdec_7Decoder_7weights_1__get__(o);
+}
+
+static int __pyx_setprop_5_cdec_7Decoder_weights(PyObject *o, PyObject *v, void *x) {
+  if (v) {
+    return __pyx_pw_5_cdec_7Decoder_7weights_3__set__(o, v);
+  }
+  else {
+    PyErr_SetString(PyExc_NotImplementedError, "__del__");
+    return -1;
+  }
+}
+
+static PyObject *__pyx_getprop_5_cdec_7Decoder_formalism(PyObject *o, void *x) {
+  return __pyx_pw_5_cdec_7Decoder_9formalism_1__get__(o);
+}
+
+static PyMethodDef __pyx_methods_5_cdec_Decoder[] = {
+  {__Pyx_NAMESTR("read_weights"), (PyCFunction)__pyx_pw_5_cdec_7Decoder_5read_weights, METH_O, __Pyx_DOCSTR(0)},
+  {__Pyx_NAMESTR("translate"), (PyCFunction)__pyx_pw_5_cdec_7Decoder_7translate, METH_VARARGS|METH_KEYWORDS, __Pyx_DOCSTR(0)},
   {0, 0, 0, 0}
 };
 
-static PyNumberMethods __pyx_tp_as_number_SegmentEvaluator = {
+static struct PyGetSetDef __pyx_getsets_5_cdec_Decoder[] = {
+  {(char *)"weights", __pyx_getprop_5_cdec_7Decoder_weights, __pyx_setprop_5_cdec_7Decoder_weights, 0, 0},
+  {(char *)"formalism", __pyx_getprop_5_cdec_7Decoder_formalism, 0, 0, 0},
+  {0, 0, 0, 0, 0}
+};
+
+static PyNumberMethods __pyx_tp_as_number_Decoder = {
   0, /*nb_add*/
   0, /*nb_subtract*/
   0, /*nb_multiply*/
@@ -16086,7 +20066,7 @@ static PyNumberMethods __pyx_tp_as_number_SegmentEvaluator = {
   #endif
 };
 
-static PySequenceMethods __pyx_tp_as_sequence_SegmentEvaluator = {
+static PySequenceMethods __pyx_tp_as_sequence_Decoder = {
   0, /*sq_length*/
   0, /*sq_concat*/
   0, /*sq_repeat*/
@@ -16099,13 +20079,13 @@ static PySequenceMethods __pyx_tp_as_sequence_SegmentEvaluator = {
   0, /*sq_inplace_repeat*/
 };
 
-static PyMappingMethods __pyx_tp_as_mapping_SegmentEvaluator = {
+static PyMappingMethods __pyx_tp_as_mapping_Decoder = {
   0, /*mp_length*/
   0, /*mp_subscript*/
   0, /*mp_ass_subscript*/
 };
 
-static PyBufferProcs __pyx_tp_as_buffer_SegmentEvaluator = {
+static PyBufferProcs __pyx_tp_as_buffer_Decoder = {
   #if PY_MAJOR_VERSION < 3
   0, /*bf_getreadbuffer*/
   #endif
@@ -16126,12 +20106,12 @@ static PyBufferProcs __pyx_tp_as_buffer_SegmentEvaluator = {
   #endif
 };
 
-static PyTypeObject __pyx_type_5_cdec_SegmentEvaluator = {
+static PyTypeObject __pyx_type_5_cdec_Decoder = {
   PyVarObject_HEAD_INIT(0, 0)
-  __Pyx_NAMESTR("_cdec.SegmentEvaluator"), /*tp_name*/
-  sizeof(struct __pyx_obj_5_cdec_SegmentEvaluator), /*tp_basicsize*/
+  __Pyx_NAMESTR("_cdec.Decoder"), /*tp_name*/
+  sizeof(struct __pyx_obj_5_cdec_Decoder), /*tp_basicsize*/
   0, /*tp_itemsize*/
-  __pyx_tp_dealloc_5_cdec_SegmentEvaluator, /*tp_dealloc*/
+  __pyx_tp_dealloc_5_cdec_Decoder, /*tp_dealloc*/
   0, /*tp_print*/
   0, /*tp_getattr*/
   0, /*tp_setattr*/
@@ -16141,26 +20121,26 @@ static PyTypeObject __pyx_type_5_cdec_SegmentEvaluator = {
   0, /*reserved*/
   #endif
   0, /*tp_repr*/
-  &__pyx_tp_as_number_SegmentEvaluator, /*tp_as_number*/
-  &__pyx_tp_as_sequence_SegmentEvaluator, /*tp_as_sequence*/
-  &__pyx_tp_as_mapping_SegmentEvaluator, /*tp_as_mapping*/
+  &__pyx_tp_as_number_Decoder, /*tp_as_number*/
+  &__pyx_tp_as_sequence_Decoder, /*tp_as_sequence*/
+  &__pyx_tp_as_mapping_Decoder, /*tp_as_mapping*/
   0, /*tp_hash*/
   0, /*tp_call*/
   0, /*tp_str*/
   0, /*tp_getattro*/
   0, /*tp_setattro*/
-  &__pyx_tp_as_buffer_SegmentEvaluator, /*tp_as_buffer*/
-  Py_TPFLAGS_DEFAULT|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_BASETYPE, /*tp_flags*/
+  &__pyx_tp_as_buffer_Decoder, /*tp_as_buffer*/
+  Py_TPFLAGS_DEFAULT|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_HAVE_GC, /*tp_flags*/
   0, /*tp_doc*/
-  0, /*tp_traverse*/
-  0, /*tp_clear*/
+  __pyx_tp_traverse_5_cdec_Decoder, /*tp_traverse*/
+  __pyx_tp_clear_5_cdec_Decoder, /*tp_clear*/
   0, /*tp_richcompare*/
   0, /*tp_weaklistoffset*/
   0, /*tp_iter*/
   0, /*tp_iternext*/
-  __pyx_methods_5_cdec_SegmentEvaluator, /*tp_methods*/
+  __pyx_methods_5_cdec_Decoder, /*tp_methods*/
   0, /*tp_members*/
-  0, /*tp_getset*/
+  __pyx_getsets_5_cdec_Decoder, /*tp_getset*/
   0, /*tp_base*/
   0, /*tp_dict*/
   0, /*tp_descr_get*/
@@ -16168,7 +20148,7 @@ static PyTypeObject __pyx_type_5_cdec_SegmentEvaluator = {
   0, /*tp_dictoffset*/
   0, /*tp_init*/
   0, /*tp_alloc*/
-  __pyx_tp_new_5_cdec_SegmentEvaluator, /*tp_new*/
+  __pyx_tp_new_5_cdec_Decoder, /*tp_new*/
   0, /*tp_free*/
   0, /*tp_is_gc*/
   0, /*tp_bases*/
@@ -16182,33 +20162,44 @@ static PyTypeObject __pyx_type_5_cdec_SegmentEvaluator = {
   #endif
 };
 
-static PyObject *__pyx_tp_new_5_cdec_Scorer(PyTypeObject *t, PyObject *a, PyObject *k) {
+static PyObject *__pyx_tp_new_5_cdec___pyx_scope_struct____iter__(PyTypeObject *t, PyObject *a, PyObject *k) {
+  struct __pyx_obj_5_cdec___pyx_scope_struct____iter__ *p;
   PyObject *o = (*t->tp_alloc)(t, 0);
   if (!o) return 0;
-  if (__pyx_pw_5_cdec_6Scorer_1__cinit__(o, a, k) < 0) {
-    Py_DECREF(o); o = 0;
-  }
+  p = ((struct __pyx_obj_5_cdec___pyx_scope_struct____iter__ *)o);
+  p->__pyx_v_self = 0;
   return o;
 }
 
-static void __pyx_tp_dealloc_5_cdec_Scorer(PyObject *o) {
-  {
-    PyObject *etype, *eval, *etb;
-    PyErr_Fetch(&etype, &eval, &etb);
-    ++Py_REFCNT(o);
-    __pyx_pw_5_cdec_6Scorer_3__dealloc__(o);
-    if (PyErr_Occurred()) PyErr_WriteUnraisable(o);
-    --Py_REFCNT(o);
-    PyErr_Restore(etype, eval, etb);
-  }
+static void __pyx_tp_dealloc_5_cdec___pyx_scope_struct____iter__(PyObject *o) {
+  struct __pyx_obj_5_cdec___pyx_scope_struct____iter__ *p = (struct __pyx_obj_5_cdec___pyx_scope_struct____iter__ *)o;
+  Py_XDECREF(((PyObject *)p->__pyx_v_self));
   (*Py_TYPE(o)->tp_free)(o);
 }
 
-static PyMethodDef __pyx_methods_5_cdec_Scorer[] = {
+static int __pyx_tp_traverse_5_cdec___pyx_scope_struct____iter__(PyObject *o, visitproc v, void *a) {
+  int e;
+  struct __pyx_obj_5_cdec___pyx_scope_struct____iter__ *p = (struct __pyx_obj_5_cdec___pyx_scope_struct____iter__ *)o;
+  if (p->__pyx_v_self) {
+    e = (*v)(((PyObject*)p->__pyx_v_self), a); if (e) return e;
+  }
+  return 0;
+}
+
+static int __pyx_tp_clear_5_cdec___pyx_scope_struct____iter__(PyObject *o) {
+  struct __pyx_obj_5_cdec___pyx_scope_struct____iter__ *p = (struct __pyx_obj_5_cdec___pyx_scope_struct____iter__ *)o;
+  PyObject* tmp;
+  tmp = ((PyObject*)p->__pyx_v_self);
+  p->__pyx_v_self = ((struct __pyx_obj_5_cdec_DenseVector *)Py_None); Py_INCREF(Py_None);
+  Py_XDECREF(tmp);
+  return 0;
+}
+
+static PyMethodDef __pyx_methods_5_cdec___pyx_scope_struct____iter__[] = {
   {0, 0, 0, 0}
 };
 
-static PyNumberMethods __pyx_tp_as_number_Scorer = {
+static PyNumberMethods __pyx_tp_as_number___pyx_scope_struct____iter__ = {
   0, /*nb_add*/
   0, /*nb_subtract*/
   0, /*nb_multiply*/
@@ -16266,7 +20257,7 @@ static PyNumberMethods __pyx_tp_as_number_Scorer = {
   #endif
 };
 
-static PySequenceMethods __pyx_tp_as_sequence_Scorer = {
+static PySequenceMethods __pyx_tp_as_sequence___pyx_scope_struct____iter__ = {
   0, /*sq_length*/
   0, /*sq_concat*/
   0, /*sq_repeat*/
@@ -16279,13 +20270,13 @@ static PySequenceMethods __pyx_tp_as_sequence_Scorer = {
   0, /*sq_inplace_repeat*/
 };
 
-static PyMappingMethods __pyx_tp_as_mapping_Scorer = {
+static PyMappingMethods __pyx_tp_as_mapping___pyx_scope_struct____iter__ = {
   0, /*mp_length*/
   0, /*mp_subscript*/
   0, /*mp_ass_subscript*/
 };
 
-static PyBufferProcs __pyx_tp_as_buffer_Scorer = {
+static PyBufferProcs __pyx_tp_as_buffer___pyx_scope_struct____iter__ = {
   #if PY_MAJOR_VERSION < 3
   0, /*bf_getreadbuffer*/
   #endif
@@ -16306,12 +20297,12 @@ static PyBufferProcs __pyx_tp_as_buffer_Scorer = {
   #endif
 };
 
-static PyTypeObject __pyx_type_5_cdec_Scorer = {
+static PyTypeObject __pyx_type_5_cdec___pyx_scope_struct____iter__ = {
   PyVarObject_HEAD_INIT(0, 0)
-  __Pyx_NAMESTR("_cdec.Scorer"), /*tp_name*/
-  sizeof(struct __pyx_obj_5_cdec_Scorer), /*tp_basicsize*/
+  __Pyx_NAMESTR("_cdec.__pyx_scope_struct____iter__"), /*tp_name*/
+  sizeof(struct __pyx_obj_5_cdec___pyx_scope_struct____iter__), /*tp_basicsize*/
   0, /*tp_itemsize*/
-  __pyx_tp_dealloc_5_cdec_Scorer, /*tp_dealloc*/
+  __pyx_tp_dealloc_5_cdec___pyx_scope_struct____iter__, /*tp_dealloc*/
   0, /*tp_print*/
   0, /*tp_getattr*/
   0, /*tp_setattr*/
@@ -16321,24 +20312,24 @@ static PyTypeObject __pyx_type_5_cdec_Scorer = {
   0, /*reserved*/
   #endif
   0, /*tp_repr*/
-  &__pyx_tp_as_number_Scorer, /*tp_as_number*/
-  &__pyx_tp_as_sequence_Scorer, /*tp_as_sequence*/
-  &__pyx_tp_as_mapping_Scorer, /*tp_as_mapping*/
+  &__pyx_tp_as_number___pyx_scope_struct____iter__, /*tp_as_number*/
+  &__pyx_tp_as_sequence___pyx_scope_struct____iter__, /*tp_as_sequence*/
+  &__pyx_tp_as_mapping___pyx_scope_struct____iter__, /*tp_as_mapping*/
   0, /*tp_hash*/
-  __pyx_pw_5_cdec_6Scorer_5__call__, /*tp_call*/
-  __pyx_pw_5_cdec_6Scorer_7__str__, /*tp_str*/
+  0, /*tp_call*/
+  0, /*tp_str*/
   0, /*tp_getattro*/
   0, /*tp_setattro*/
-  &__pyx_tp_as_buffer_Scorer, /*tp_as_buffer*/
-  Py_TPFLAGS_DEFAULT|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_BASETYPE, /*tp_flags*/
+  &__pyx_tp_as_buffer___pyx_scope_struct____iter__, /*tp_as_buffer*/
+  Py_TPFLAGS_DEFAULT|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_HAVE_GC, /*tp_flags*/
   0, /*tp_doc*/
-  0, /*tp_traverse*/
-  0, /*tp_clear*/
+  __pyx_tp_traverse_5_cdec___pyx_scope_struct____iter__, /*tp_traverse*/
+  __pyx_tp_clear_5_cdec___pyx_scope_struct____iter__, /*tp_clear*/
   0, /*tp_richcompare*/
   0, /*tp_weaklistoffset*/
   0, /*tp_iter*/
   0, /*tp_iternext*/
-  __pyx_methods_5_cdec_Scorer, /*tp_methods*/
+  __pyx_methods_5_cdec___pyx_scope_struct____iter__, /*tp_methods*/
   0, /*tp_members*/
   0, /*tp_getset*/
   0, /*tp_base*/
@@ -16348,7 +20339,7 @@ static PyTypeObject __pyx_type_5_cdec_Scorer = {
   0, /*tp_dictoffset*/
   0, /*tp_init*/
   0, /*tp_alloc*/
-  __pyx_tp_new_5_cdec_Scorer, /*tp_new*/
+  __pyx_tp_new_5_cdec___pyx_scope_struct____iter__, /*tp_new*/
   0, /*tp_free*/
   0, /*tp_is_gc*/
   0, /*tp_bases*/
@@ -16362,82 +20353,44 @@ static PyTypeObject __pyx_type_5_cdec_Scorer = {
   #endif
 };
 
-static PyObject *__pyx_tp_new_5_cdec_Decoder(PyTypeObject *t, PyObject *a, PyObject *k) {
-  struct __pyx_obj_5_cdec_Decoder *p;
+static PyObject *__pyx_tp_new_5_cdec___pyx_scope_struct_1___iter__(PyTypeObject *t, PyObject *a, PyObject *k) {
+  struct __pyx_obj_5_cdec___pyx_scope_struct_1___iter__ *p;
   PyObject *o = (*t->tp_alloc)(t, 0);
   if (!o) return 0;
-  p = ((struct __pyx_obj_5_cdec_Decoder *)o);
-  p->weights = ((struct __pyx_obj_5_cdec_DenseVector *)Py_None); Py_INCREF(Py_None);
-  if (__pyx_pw_5_cdec_7Decoder_1__cinit__(o, a, k) < 0) {
-    Py_DECREF(o); o = 0;
-  }
+  p = ((struct __pyx_obj_5_cdec___pyx_scope_struct_1___iter__ *)o);
+  p->__pyx_v_self = 0;
   return o;
 }
 
-static void __pyx_tp_dealloc_5_cdec_Decoder(PyObject *o) {
-  struct __pyx_obj_5_cdec_Decoder *p = (struct __pyx_obj_5_cdec_Decoder *)o;
-  {
-    PyObject *etype, *eval, *etb;
-    PyErr_Fetch(&etype, &eval, &etb);
-    ++Py_REFCNT(o);
-    __pyx_pw_5_cdec_7Decoder_3__dealloc__(o);
-    if (PyErr_Occurred()) PyErr_WriteUnraisable(o);
-    --Py_REFCNT(o);
-    PyErr_Restore(etype, eval, etb);
-  }
-  Py_XDECREF(((PyObject *)p->weights));
+static void __pyx_tp_dealloc_5_cdec___pyx_scope_struct_1___iter__(PyObject *o) {
+  struct __pyx_obj_5_cdec___pyx_scope_struct_1___iter__ *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_1___iter__ *)o;
+  Py_XDECREF(((PyObject *)p->__pyx_v_self));
   (*Py_TYPE(o)->tp_free)(o);
 }
 
-static int __pyx_tp_traverse_5_cdec_Decoder(PyObject *o, visitproc v, void *a) {
+static int __pyx_tp_traverse_5_cdec___pyx_scope_struct_1___iter__(PyObject *o, visitproc v, void *a) {
   int e;
-  struct __pyx_obj_5_cdec_Decoder *p = (struct __pyx_obj_5_cdec_Decoder *)o;
-  if (p->weights) {
-    e = (*v)(((PyObject*)p->weights), a); if (e) return e;
+  struct __pyx_obj_5_cdec___pyx_scope_struct_1___iter__ *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_1___iter__ *)o;
+  if (p->__pyx_v_self) {
+    e = (*v)(((PyObject*)p->__pyx_v_self), a); if (e) return e;
   }
   return 0;
 }
 
-static int __pyx_tp_clear_5_cdec_Decoder(PyObject *o) {
-  struct __pyx_obj_5_cdec_Decoder *p = (struct __pyx_obj_5_cdec_Decoder *)o;
+static int __pyx_tp_clear_5_cdec___pyx_scope_struct_1___iter__(PyObject *o) {
+  struct __pyx_obj_5_cdec___pyx_scope_struct_1___iter__ *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_1___iter__ *)o;
   PyObject* tmp;
-  tmp = ((PyObject*)p->weights);
-  p->weights = ((struct __pyx_obj_5_cdec_DenseVector *)Py_None); Py_INCREF(Py_None);
+  tmp = ((PyObject*)p->__pyx_v_self);
+  p->__pyx_v_self = ((struct __pyx_obj_5_cdec_SparseVector *)Py_None); Py_INCREF(Py_None);
   Py_XDECREF(tmp);
   return 0;
 }
 
-static PyObject *__pyx_getprop_5_cdec_7Decoder_weights(PyObject *o, void *x) {
-  return __pyx_pw_5_cdec_7Decoder_7weights_1__get__(o);
-}
-
-static int __pyx_setprop_5_cdec_7Decoder_weights(PyObject *o, PyObject *v, void *x) {
-  if (v) {
-    return __pyx_pw_5_cdec_7Decoder_7weights_3__set__(o, v);
-  }
-  else {
-    PyErr_SetString(PyExc_NotImplementedError, "__del__");
-    return -1;
-  }
-}
-
-static PyObject *__pyx_getprop_5_cdec_7Decoder_formalism(PyObject *o, void *x) {
-  return __pyx_pw_5_cdec_7Decoder_9formalism_1__get__(o);
-}
-
-static PyMethodDef __pyx_methods_5_cdec_Decoder[] = {
-  {__Pyx_NAMESTR("read_weights"), (PyCFunction)__pyx_pw_5_cdec_7Decoder_5read_weights, METH_O, __Pyx_DOCSTR(0)},
-  {__Pyx_NAMESTR("translate"), (PyCFunction)__pyx_pw_5_cdec_7Decoder_7translate, METH_VARARGS|METH_KEYWORDS, __Pyx_DOCSTR(0)},
+static PyMethodDef __pyx_methods_5_cdec___pyx_scope_struct_1___iter__[] = {
   {0, 0, 0, 0}
 };
 
-static struct PyGetSetDef __pyx_getsets_5_cdec_Decoder[] = {
-  {(char *)"weights", __pyx_getprop_5_cdec_7Decoder_weights, __pyx_setprop_5_cdec_7Decoder_weights, 0, 0},
-  {(char *)"formalism", __pyx_getprop_5_cdec_7Decoder_formalism, 0, 0, 0},
-  {0, 0, 0, 0, 0}
-};
-
-static PyNumberMethods __pyx_tp_as_number_Decoder = {
+static PyNumberMethods __pyx_tp_as_number___pyx_scope_struct_1___iter__ = {
   0, /*nb_add*/
   0, /*nb_subtract*/
   0, /*nb_multiply*/
@@ -16495,7 +20448,7 @@ static PyNumberMethods __pyx_tp_as_number_Decoder = {
   #endif
 };
 
-static PySequenceMethods __pyx_tp_as_sequence_Decoder = {
+static PySequenceMethods __pyx_tp_as_sequence___pyx_scope_struct_1___iter__ = {
   0, /*sq_length*/
   0, /*sq_concat*/
   0, /*sq_repeat*/
@@ -16508,13 +20461,13 @@ static PySequenceMethods __pyx_tp_as_sequence_Decoder = {
   0, /*sq_inplace_repeat*/
 };
 
-static PyMappingMethods __pyx_tp_as_mapping_Decoder = {
+static PyMappingMethods __pyx_tp_as_mapping___pyx_scope_struct_1___iter__ = {
   0, /*mp_length*/
   0, /*mp_subscript*/
   0, /*mp_ass_subscript*/
 };
 
-static PyBufferProcs __pyx_tp_as_buffer_Decoder = {
+static PyBufferProcs __pyx_tp_as_buffer___pyx_scope_struct_1___iter__ = {
   #if PY_MAJOR_VERSION < 3
   0, /*bf_getreadbuffer*/
   #endif
@@ -16535,12 +20488,12 @@ static PyBufferProcs __pyx_tp_as_buffer_Decoder = {
   #endif
 };
 
-static PyTypeObject __pyx_type_5_cdec_Decoder = {
+static PyTypeObject __pyx_type_5_cdec___pyx_scope_struct_1___iter__ = {
   PyVarObject_HEAD_INIT(0, 0)
-  __Pyx_NAMESTR("_cdec.Decoder"), /*tp_name*/
-  sizeof(struct __pyx_obj_5_cdec_Decoder), /*tp_basicsize*/
+  __Pyx_NAMESTR("_cdec.__pyx_scope_struct_1___iter__"), /*tp_name*/
+  sizeof(struct __pyx_obj_5_cdec___pyx_scope_struct_1___iter__), /*tp_basicsize*/
   0, /*tp_itemsize*/
-  __pyx_tp_dealloc_5_cdec_Decoder, /*tp_dealloc*/
+  __pyx_tp_dealloc_5_cdec___pyx_scope_struct_1___iter__, /*tp_dealloc*/
   0, /*tp_print*/
   0, /*tp_getattr*/
   0, /*tp_setattr*/
@@ -16550,26 +20503,26 @@ static PyTypeObject __pyx_type_5_cdec_Decoder = {
   0, /*reserved*/
   #endif
   0, /*tp_repr*/
-  &__pyx_tp_as_number_Decoder, /*tp_as_number*/
-  &__pyx_tp_as_sequence_Decoder, /*tp_as_sequence*/
-  &__pyx_tp_as_mapping_Decoder, /*tp_as_mapping*/
+  &__pyx_tp_as_number___pyx_scope_struct_1___iter__, /*tp_as_number*/
+  &__pyx_tp_as_sequence___pyx_scope_struct_1___iter__, /*tp_as_sequence*/
+  &__pyx_tp_as_mapping___pyx_scope_struct_1___iter__, /*tp_as_mapping*/
   0, /*tp_hash*/
   0, /*tp_call*/
   0, /*tp_str*/
   0, /*tp_getattro*/
   0, /*tp_setattro*/
-  &__pyx_tp_as_buffer_Decoder, /*tp_as_buffer*/
-  Py_TPFLAGS_DEFAULT|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_HAVE_GC, /*tp_flags*/
+  &__pyx_tp_as_buffer___pyx_scope_struct_1___iter__, /*tp_as_buffer*/
+  Py_TPFLAGS_DEFAULT|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_HAVE_GC, /*tp_flags*/
   0, /*tp_doc*/
-  __pyx_tp_traverse_5_cdec_Decoder, /*tp_traverse*/
-  __pyx_tp_clear_5_cdec_Decoder, /*tp_clear*/
+  __pyx_tp_traverse_5_cdec___pyx_scope_struct_1___iter__, /*tp_traverse*/
+  __pyx_tp_clear_5_cdec___pyx_scope_struct_1___iter__, /*tp_clear*/
   0, /*tp_richcompare*/
   0, /*tp_weaklistoffset*/
   0, /*tp_iter*/
   0, /*tp_iternext*/
-  __pyx_methods_5_cdec_Decoder, /*tp_methods*/
+  __pyx_methods_5_cdec___pyx_scope_struct_1___iter__, /*tp_methods*/
   0, /*tp_members*/
-  __pyx_getsets_5_cdec_Decoder, /*tp_getset*/
+  0, /*tp_getset*/
   0, /*tp_base*/
   0, /*tp_dict*/
   0, /*tp_descr_get*/
@@ -16577,7 +20530,7 @@ static PyTypeObject __pyx_type_5_cdec_Decoder = {
   0, /*tp_dictoffset*/
   0, /*tp_init*/
   0, /*tp_alloc*/
-  __pyx_tp_new_5_cdec_Decoder, /*tp_new*/
+  __pyx_tp_new_5_cdec___pyx_scope_struct_1___iter__, /*tp_new*/
   0, /*tp_free*/
   0, /*tp_is_gc*/
   0, /*tp_bases*/
@@ -16591,44 +20544,44 @@ static PyTypeObject __pyx_type_5_cdec_Decoder = {
   #endif
 };
 
-static PyObject *__pyx_tp_new_5_cdec___pyx_scope_struct____iter__(PyTypeObject *t, PyObject *a, PyObject *k) {
-  struct __pyx_obj_5_cdec___pyx_scope_struct____iter__ *p;
+static PyObject *__pyx_tp_new_5_cdec___pyx_scope_struct_2__phrase(PyTypeObject *t, PyObject *a, PyObject *k) {
+  struct __pyx_obj_5_cdec___pyx_scope_struct_2__phrase *p;
   PyObject *o = (*t->tp_alloc)(t, 0);
   if (!o) return 0;
-  p = ((struct __pyx_obj_5_cdec___pyx_scope_struct____iter__ *)o);
-  p->__pyx_v_self = 0;
+  p = ((struct __pyx_obj_5_cdec___pyx_scope_struct_2__phrase *)o);
+  p->__pyx_v_phrase = 0;
   return o;
 }
 
-static void __pyx_tp_dealloc_5_cdec___pyx_scope_struct____iter__(PyObject *o) {
-  struct __pyx_obj_5_cdec___pyx_scope_struct____iter__ *p = (struct __pyx_obj_5_cdec___pyx_scope_struct____iter__ *)o;
-  Py_XDECREF(((PyObject *)p->__pyx_v_self));
+static void __pyx_tp_dealloc_5_cdec___pyx_scope_struct_2__phrase(PyObject *o) {
+  struct __pyx_obj_5_cdec___pyx_scope_struct_2__phrase *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_2__phrase *)o;
+  Py_XDECREF(p->__pyx_v_phrase);
   (*Py_TYPE(o)->tp_free)(o);
 }
 
-static int __pyx_tp_traverse_5_cdec___pyx_scope_struct____iter__(PyObject *o, visitproc v, void *a) {
+static int __pyx_tp_traverse_5_cdec___pyx_scope_struct_2__phrase(PyObject *o, visitproc v, void *a) {
   int e;
-  struct __pyx_obj_5_cdec___pyx_scope_struct____iter__ *p = (struct __pyx_obj_5_cdec___pyx_scope_struct____iter__ *)o;
-  if (p->__pyx_v_self) {
-    e = (*v)(((PyObject*)p->__pyx_v_self), a); if (e) return e;
+  struct __pyx_obj_5_cdec___pyx_scope_struct_2__phrase *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_2__phrase *)o;
+  if (p->__pyx_v_phrase) {
+    e = (*v)(p->__pyx_v_phrase, a); if (e) return e;
   }
   return 0;
 }
 
-static int __pyx_tp_clear_5_cdec___pyx_scope_struct____iter__(PyObject *o) {
-  struct __pyx_obj_5_cdec___pyx_scope_struct____iter__ *p = (struct __pyx_obj_5_cdec___pyx_scope_struct____iter__ *)o;
+static int __pyx_tp_clear_5_cdec___pyx_scope_struct_2__phrase(PyObject *o) {
+  struct __pyx_obj_5_cdec___pyx_scope_struct_2__phrase *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_2__phrase *)o;
   PyObject* tmp;
-  tmp = ((PyObject*)p->__pyx_v_self);
-  p->__pyx_v_self = ((struct __pyx_obj_5_cdec_DenseVector *)Py_None); Py_INCREF(Py_None);
+  tmp = ((PyObject*)p->__pyx_v_phrase);
+  p->__pyx_v_phrase = Py_None; Py_INCREF(Py_None);
   Py_XDECREF(tmp);
   return 0;
 }
 
-static PyMethodDef __pyx_methods_5_cdec___pyx_scope_struct____iter__[] = {
+static PyMethodDef __pyx_methods_5_cdec___pyx_scope_struct_2__phrase[] = {
   {0, 0, 0, 0}
 };
 
-static PyNumberMethods __pyx_tp_as_number___pyx_scope_struct____iter__ = {
+static PyNumberMethods __pyx_tp_as_number___pyx_scope_struct_2__phrase = {
   0, /*nb_add*/
   0, /*nb_subtract*/
   0, /*nb_multiply*/
@@ -16686,7 +20639,7 @@ static PyNumberMethods __pyx_tp_as_number___pyx_scope_struct____iter__ = {
   #endif
 };
 
-static PySequenceMethods __pyx_tp_as_sequence___pyx_scope_struct____iter__ = {
+static PySequenceMethods __pyx_tp_as_sequence___pyx_scope_struct_2__phrase = {
   0, /*sq_length*/
   0, /*sq_concat*/
   0, /*sq_repeat*/
@@ -16699,13 +20652,13 @@ static PySequenceMethods __pyx_tp_as_sequence___pyx_scope_struct____iter__ = {
   0, /*sq_inplace_repeat*/
 };
 
-static PyMappingMethods __pyx_tp_as_mapping___pyx_scope_struct____iter__ = {
+static PyMappingMethods __pyx_tp_as_mapping___pyx_scope_struct_2__phrase = {
   0, /*mp_length*/
   0, /*mp_subscript*/
   0, /*mp_ass_subscript*/
 };
 
-static PyBufferProcs __pyx_tp_as_buffer___pyx_scope_struct____iter__ = {
+static PyBufferProcs __pyx_tp_as_buffer___pyx_scope_struct_2__phrase = {
   #if PY_MAJOR_VERSION < 3
   0, /*bf_getreadbuffer*/
   #endif
@@ -16726,12 +20679,12 @@ static PyBufferProcs __pyx_tp_as_buffer___pyx_scope_struct____iter__ = {
   #endif
 };
 
-static PyTypeObject __pyx_type_5_cdec___pyx_scope_struct____iter__ = {
+static PyTypeObject __pyx_type_5_cdec___pyx_scope_struct_2__phrase = {
   PyVarObject_HEAD_INIT(0, 0)
-  __Pyx_NAMESTR("_cdec.__pyx_scope_struct____iter__"), /*tp_name*/
-  sizeof(struct __pyx_obj_5_cdec___pyx_scope_struct____iter__), /*tp_basicsize*/
+  __Pyx_NAMESTR("_cdec.__pyx_scope_struct_2__phrase"), /*tp_name*/
+  sizeof(struct __pyx_obj_5_cdec___pyx_scope_struct_2__phrase), /*tp_basicsize*/
   0, /*tp_itemsize*/
-  __pyx_tp_dealloc_5_cdec___pyx_scope_struct____iter__, /*tp_dealloc*/
+  __pyx_tp_dealloc_5_cdec___pyx_scope_struct_2__phrase, /*tp_dealloc*/
   0, /*tp_print*/
   0, /*tp_getattr*/
   0, /*tp_setattr*/
@@ -16741,24 +20694,24 @@ static PyTypeObject __pyx_type_5_cdec___pyx_scope_struct____iter__ = {
   0, /*reserved*/
   #endif
   0, /*tp_repr*/
-  &__pyx_tp_as_number___pyx_scope_struct____iter__, /*tp_as_number*/
-  &__pyx_tp_as_sequence___pyx_scope_struct____iter__, /*tp_as_sequence*/
-  &__pyx_tp_as_mapping___pyx_scope_struct____iter__, /*tp_as_mapping*/
+  &__pyx_tp_as_number___pyx_scope_struct_2__phrase, /*tp_as_number*/
+  &__pyx_tp_as_sequence___pyx_scope_struct_2__phrase, /*tp_as_sequence*/
+  &__pyx_tp_as_mapping___pyx_scope_struct_2__phrase, /*tp_as_mapping*/
   0, /*tp_hash*/
   0, /*tp_call*/
   0, /*tp_str*/
   0, /*tp_getattro*/
   0, /*tp_setattro*/
-  &__pyx_tp_as_buffer___pyx_scope_struct____iter__, /*tp_as_buffer*/
+  &__pyx_tp_as_buffer___pyx_scope_struct_2__phrase, /*tp_as_buffer*/
   Py_TPFLAGS_DEFAULT|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_HAVE_GC, /*tp_flags*/
   0, /*tp_doc*/
-  __pyx_tp_traverse_5_cdec___pyx_scope_struct____iter__, /*tp_traverse*/
-  __pyx_tp_clear_5_cdec___pyx_scope_struct____iter__, /*tp_clear*/
+  __pyx_tp_traverse_5_cdec___pyx_scope_struct_2__phrase, /*tp_traverse*/
+  __pyx_tp_clear_5_cdec___pyx_scope_struct_2__phrase, /*tp_clear*/
   0, /*tp_richcompare*/
   0, /*tp_weaklistoffset*/
   0, /*tp_iter*/
   0, /*tp_iternext*/
-  __pyx_methods_5_cdec___pyx_scope_struct____iter__, /*tp_methods*/
+  __pyx_methods_5_cdec___pyx_scope_struct_2__phrase, /*tp_methods*/
   0, /*tp_members*/
   0, /*tp_getset*/
   0, /*tp_base*/
@@ -16768,7 +20721,7 @@ static PyTypeObject __pyx_type_5_cdec___pyx_scope_struct____iter__ = {
   0, /*tp_dictoffset*/
   0, /*tp_init*/
   0, /*tp_alloc*/
-  __pyx_tp_new_5_cdec___pyx_scope_struct____iter__, /*tp_new*/
+  __pyx_tp_new_5_cdec___pyx_scope_struct_2__phrase, /*tp_new*/
   0, /*tp_free*/
   0, /*tp_is_gc*/
   0, /*tp_bases*/
@@ -16782,44 +20735,60 @@ static PyTypeObject __pyx_type_5_cdec___pyx_scope_struct____iter__ = {
   #endif
 };
 
-static PyObject *__pyx_tp_new_5_cdec___pyx_scope_struct_1___iter__(PyTypeObject *t, PyObject *a, PyObject *k) {
-  struct __pyx_obj_5_cdec___pyx_scope_struct_1___iter__ *p;
+static PyObject *__pyx_tp_new_5_cdec___pyx_scope_struct_3_genexpr(PyTypeObject *t, PyObject *a, PyObject *k) {
+  struct __pyx_obj_5_cdec___pyx_scope_struct_3_genexpr *p;
   PyObject *o = (*t->tp_alloc)(t, 0);
   if (!o) return 0;
-  p = ((struct __pyx_obj_5_cdec___pyx_scope_struct_1___iter__ *)o);
-  p->__pyx_v_self = 0;
+  p = ((struct __pyx_obj_5_cdec___pyx_scope_struct_3_genexpr *)o);
+  p->__pyx_outer_scope = 0;
+  p->__pyx_v_w = 0;
+  p->__pyx_t_0 = 0;
   return o;
 }
 
-static void __pyx_tp_dealloc_5_cdec___pyx_scope_struct_1___iter__(PyObject *o) {
-  struct __pyx_obj_5_cdec___pyx_scope_struct_1___iter__ *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_1___iter__ *)o;
-  Py_XDECREF(((PyObject *)p->__pyx_v_self));
+static void __pyx_tp_dealloc_5_cdec___pyx_scope_struct_3_genexpr(PyObject *o) {
+  struct __pyx_obj_5_cdec___pyx_scope_struct_3_genexpr *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_3_genexpr *)o;
+  Py_XDECREF(((PyObject *)p->__pyx_outer_scope));
+  Py_XDECREF(p->__pyx_v_w);
+  Py_XDECREF(p->__pyx_t_0);
   (*Py_TYPE(o)->tp_free)(o);
 }
 
-static int __pyx_tp_traverse_5_cdec___pyx_scope_struct_1___iter__(PyObject *o, visitproc v, void *a) {
+static int __pyx_tp_traverse_5_cdec___pyx_scope_struct_3_genexpr(PyObject *o, visitproc v, void *a) {
   int e;
-  struct __pyx_obj_5_cdec___pyx_scope_struct_1___iter__ *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_1___iter__ *)o;
-  if (p->__pyx_v_self) {
-    e = (*v)(((PyObject*)p->__pyx_v_self), a); if (e) return e;
+  struct __pyx_obj_5_cdec___pyx_scope_struct_3_genexpr *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_3_genexpr *)o;
+  if (p->__pyx_outer_scope) {
+    e = (*v)(((PyObject*)p->__pyx_outer_scope), a); if (e) return e;
+  }
+  if (p->__pyx_v_w) {
+    e = (*v)(p->__pyx_v_w, a); if (e) return e;
+  }
+  if (p->__pyx_t_0) {
+    e = (*v)(p->__pyx_t_0, a); if (e) return e;
   }
   return 0;
 }
 
-static int __pyx_tp_clear_5_cdec___pyx_scope_struct_1___iter__(PyObject *o) {
-  struct __pyx_obj_5_cdec___pyx_scope_struct_1___iter__ *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_1___iter__ *)o;
+static int __pyx_tp_clear_5_cdec___pyx_scope_struct_3_genexpr(PyObject *o) {
+  struct __pyx_obj_5_cdec___pyx_scope_struct_3_genexpr *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_3_genexpr *)o;
   PyObject* tmp;
-  tmp = ((PyObject*)p->__pyx_v_self);
-  p->__pyx_v_self = ((struct __pyx_obj_5_cdec_SparseVector *)Py_None); Py_INCREF(Py_None);
+  tmp = ((PyObject*)p->__pyx_outer_scope);
+  p->__pyx_outer_scope = ((struct __pyx_obj_5_cdec___pyx_scope_struct_2__phrase *)Py_None); Py_INCREF(Py_None);
+  Py_XDECREF(tmp);
+  tmp = ((PyObject*)p->__pyx_v_w);
+  p->__pyx_v_w = Py_None; Py_INCREF(Py_None);
+  Py_XDECREF(tmp);
+  tmp = ((PyObject*)p->__pyx_t_0);
+  p->__pyx_t_0 = Py_None; Py_INCREF(Py_None);
   Py_XDECREF(tmp);
   return 0;
 }
 
-static PyMethodDef __pyx_methods_5_cdec___pyx_scope_struct_1___iter__[] = {
+static PyMethodDef __pyx_methods_5_cdec___pyx_scope_struct_3_genexpr[] = {
   {0, 0, 0, 0}
 };
 
-static PyNumberMethods __pyx_tp_as_number___pyx_scope_struct_1___iter__ = {
+static PyNumberMethods __pyx_tp_as_number___pyx_scope_struct_3_genexpr = {
   0, /*nb_add*/
   0, /*nb_subtract*/
   0, /*nb_multiply*/
@@ -16877,7 +20846,7 @@ static PyNumberMethods __pyx_tp_as_number___pyx_scope_struct_1___iter__ = {
   #endif
 };
 
-static PySequenceMethods __pyx_tp_as_sequence___pyx_scope_struct_1___iter__ = {
+static PySequenceMethods __pyx_tp_as_sequence___pyx_scope_struct_3_genexpr = {
   0, /*sq_length*/
   0, /*sq_concat*/
   0, /*sq_repeat*/
@@ -16890,13 +20859,13 @@ static PySequenceMethods __pyx_tp_as_sequence___pyx_scope_struct_1___iter__ = {
   0, /*sq_inplace_repeat*/
 };
 
-static PyMappingMethods __pyx_tp_as_mapping___pyx_scope_struct_1___iter__ = {
+static PyMappingMethods __pyx_tp_as_mapping___pyx_scope_struct_3_genexpr = {
   0, /*mp_length*/
   0, /*mp_subscript*/
   0, /*mp_ass_subscript*/
 };
 
-static PyBufferProcs __pyx_tp_as_buffer___pyx_scope_struct_1___iter__ = {
+static PyBufferProcs __pyx_tp_as_buffer___pyx_scope_struct_3_genexpr = {
   #if PY_MAJOR_VERSION < 3
   0, /*bf_getreadbuffer*/
   #endif
@@ -16917,12 +20886,12 @@ static PyBufferProcs __pyx_tp_as_buffer___pyx_scope_struct_1___iter__ = {
   #endif
 };
 
-static PyTypeObject __pyx_type_5_cdec___pyx_scope_struct_1___iter__ = {
+static PyTypeObject __pyx_type_5_cdec___pyx_scope_struct_3_genexpr = {
   PyVarObject_HEAD_INIT(0, 0)
-  __Pyx_NAMESTR("_cdec.__pyx_scope_struct_1___iter__"), /*tp_name*/
-  sizeof(struct __pyx_obj_5_cdec___pyx_scope_struct_1___iter__), /*tp_basicsize*/
+  __Pyx_NAMESTR("_cdec.__pyx_scope_struct_3_genexpr"), /*tp_name*/
+  sizeof(struct __pyx_obj_5_cdec___pyx_scope_struct_3_genexpr), /*tp_basicsize*/
   0, /*tp_itemsize*/
-  __pyx_tp_dealloc_5_cdec___pyx_scope_struct_1___iter__, /*tp_dealloc*/
+  __pyx_tp_dealloc_5_cdec___pyx_scope_struct_3_genexpr, /*tp_dealloc*/
   0, /*tp_print*/
   0, /*tp_getattr*/
   0, /*tp_setattr*/
@@ -16932,24 +20901,24 @@ static PyTypeObject __pyx_type_5_cdec___pyx_scope_struct_1___iter__ = {
   0, /*reserved*/
   #endif
   0, /*tp_repr*/
-  &__pyx_tp_as_number___pyx_scope_struct_1___iter__, /*tp_as_number*/
-  &__pyx_tp_as_sequence___pyx_scope_struct_1___iter__, /*tp_as_sequence*/
-  &__pyx_tp_as_mapping___pyx_scope_struct_1___iter__, /*tp_as_mapping*/
+  &__pyx_tp_as_number___pyx_scope_struct_3_genexpr, /*tp_as_number*/
+  &__pyx_tp_as_sequence___pyx_scope_struct_3_genexpr, /*tp_as_sequence*/
+  &__pyx_tp_as_mapping___pyx_scope_struct_3_genexpr, /*tp_as_mapping*/
   0, /*tp_hash*/
   0, /*tp_call*/
   0, /*tp_str*/
   0, /*tp_getattro*/
   0, /*tp_setattro*/
-  &__pyx_tp_as_buffer___pyx_scope_struct_1___iter__, /*tp_as_buffer*/
+  &__pyx_tp_as_buffer___pyx_scope_struct_3_genexpr, /*tp_as_buffer*/
   Py_TPFLAGS_DEFAULT|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_HAVE_GC, /*tp_flags*/
   0, /*tp_doc*/
-  __pyx_tp_traverse_5_cdec___pyx_scope_struct_1___iter__, /*tp_traverse*/
-  __pyx_tp_clear_5_cdec___pyx_scope_struct_1___iter__, /*tp_clear*/
+  __pyx_tp_traverse_5_cdec___pyx_scope_struct_3_genexpr, /*tp_traverse*/
+  __pyx_tp_clear_5_cdec___pyx_scope_struct_3_genexpr, /*tp_clear*/
   0, /*tp_richcompare*/
   0, /*tp_weaklistoffset*/
   0, /*tp_iter*/
   0, /*tp_iternext*/
-  __pyx_methods_5_cdec___pyx_scope_struct_1___iter__, /*tp_methods*/
+  __pyx_methods_5_cdec___pyx_scope_struct_3_genexpr, /*tp_methods*/
   0, /*tp_members*/
   0, /*tp_getset*/
   0, /*tp_base*/
@@ -16959,7 +20928,7 @@ static PyTypeObject __pyx_type_5_cdec___pyx_scope_struct_1___iter__ = {
   0, /*tp_dictoffset*/
   0, /*tp_init*/
   0, /*tp_alloc*/
-  __pyx_tp_new_5_cdec___pyx_scope_struct_1___iter__, /*tp_new*/
+  __pyx_tp_new_5_cdec___pyx_scope_struct_3_genexpr, /*tp_new*/
   0, /*tp_free*/
   0, /*tp_is_gc*/
   0, /*tp_bases*/
@@ -16973,52 +20942,44 @@ static PyTypeObject __pyx_type_5_cdec___pyx_scope_struct_1___iter__ = {
   #endif
 };
 
-static PyObject *__pyx_tp_new_5_cdec___pyx_scope_struct_2_kbest(PyTypeObject *t, PyObject *a, PyObject *k) {
-  struct __pyx_obj_5_cdec___pyx_scope_struct_2_kbest *p;
+static PyObject *__pyx_tp_new_5_cdec___pyx_scope_struct_4___get__(PyTypeObject *t, PyObject *a, PyObject *k) {
+  struct __pyx_obj_5_cdec___pyx_scope_struct_4___get__ *p;
   PyObject *o = (*t->tp_alloc)(t, 0);
   if (!o) return 0;
-  p = ((struct __pyx_obj_5_cdec___pyx_scope_struct_2_kbest *)o);
+  p = ((struct __pyx_obj_5_cdec___pyx_scope_struct_4___get__ *)o);
   p->__pyx_v_self = 0;
-  p->__pyx_v_size = 0;
   return o;
 }
 
-static void __pyx_tp_dealloc_5_cdec___pyx_scope_struct_2_kbest(PyObject *o) {
-  struct __pyx_obj_5_cdec___pyx_scope_struct_2_kbest *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_2_kbest *)o;
+static void __pyx_tp_dealloc_5_cdec___pyx_scope_struct_4___get__(PyObject *o) {
+  struct __pyx_obj_5_cdec___pyx_scope_struct_4___get__ *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_4___get__ *)o;
   Py_XDECREF(((PyObject *)p->__pyx_v_self));
-  Py_XDECREF(p->__pyx_v_size);
   (*Py_TYPE(o)->tp_free)(o);
 }
 
-static int __pyx_tp_traverse_5_cdec___pyx_scope_struct_2_kbest(PyObject *o, visitproc v, void *a) {
+static int __pyx_tp_traverse_5_cdec___pyx_scope_struct_4___get__(PyObject *o, visitproc v, void *a) {
   int e;
-  struct __pyx_obj_5_cdec___pyx_scope_struct_2_kbest *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_2_kbest *)o;
+  struct __pyx_obj_5_cdec___pyx_scope_struct_4___get__ *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_4___get__ *)o;
   if (p->__pyx_v_self) {
     e = (*v)(((PyObject*)p->__pyx_v_self), a); if (e) return e;
   }
-  if (p->__pyx_v_size) {
-    e = (*v)(p->__pyx_v_size, a); if (e) return e;
-  }
   return 0;
 }
 
-static int __pyx_tp_clear_5_cdec___pyx_scope_struct_2_kbest(PyObject *o) {
-  struct __pyx_obj_5_cdec___pyx_scope_struct_2_kbest *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_2_kbest *)o;
+static int __pyx_tp_clear_5_cdec___pyx_scope_struct_4___get__(PyObject *o) {
+  struct __pyx_obj_5_cdec___pyx_scope_struct_4___get__ *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_4___get__ *)o;
   PyObject* tmp;
   tmp = ((PyObject*)p->__pyx_v_self);
-  p->__pyx_v_self = ((struct __pyx_obj_5_cdec_Hypergraph *)Py_None); Py_INCREF(Py_None);
-  Py_XDECREF(tmp);
-  tmp = ((PyObject*)p->__pyx_v_size);
-  p->__pyx_v_size = Py_None; Py_INCREF(Py_None);
+  p->__pyx_v_self = ((struct __pyx_obj_5_cdec_BaseTRule *)Py_None); Py_INCREF(Py_None);
   Py_XDECREF(tmp);
   return 0;
 }
 
-static PyMethodDef __pyx_methods_5_cdec___pyx_scope_struct_2_kbest[] = {
+static PyMethodDef __pyx_methods_5_cdec___pyx_scope_struct_4___get__[] = {
   {0, 0, 0, 0}
 };
 
-static PyNumberMethods __pyx_tp_as_number___pyx_scope_struct_2_kbest = {
+static PyNumberMethods __pyx_tp_as_number___pyx_scope_struct_4___get__ = {
   0, /*nb_add*/
   0, /*nb_subtract*/
   0, /*nb_multiply*/
@@ -17076,7 +21037,7 @@ static PyNumberMethods __pyx_tp_as_number___pyx_scope_struct_2_kbest = {
   #endif
 };
 
-static PySequenceMethods __pyx_tp_as_sequence___pyx_scope_struct_2_kbest = {
+static PySequenceMethods __pyx_tp_as_sequence___pyx_scope_struct_4___get__ = {
   0, /*sq_length*/
   0, /*sq_concat*/
   0, /*sq_repeat*/
@@ -17089,13 +21050,13 @@ static PySequenceMethods __pyx_tp_as_sequence___pyx_scope_struct_2_kbest = {
   0, /*sq_inplace_repeat*/
 };
 
-static PyMappingMethods __pyx_tp_as_mapping___pyx_scope_struct_2_kbest = {
+static PyMappingMethods __pyx_tp_as_mapping___pyx_scope_struct_4___get__ = {
   0, /*mp_length*/
   0, /*mp_subscript*/
   0, /*mp_ass_subscript*/
 };
 
-static PyBufferProcs __pyx_tp_as_buffer___pyx_scope_struct_2_kbest = {
+static PyBufferProcs __pyx_tp_as_buffer___pyx_scope_struct_4___get__ = {
   #if PY_MAJOR_VERSION < 3
   0, /*bf_getreadbuffer*/
   #endif
@@ -17116,12 +21077,12 @@ static PyBufferProcs __pyx_tp_as_buffer___pyx_scope_struct_2_kbest = {
   #endif
 };
 
-static PyTypeObject __pyx_type_5_cdec___pyx_scope_struct_2_kbest = {
+static PyTypeObject __pyx_type_5_cdec___pyx_scope_struct_4___get__ = {
   PyVarObject_HEAD_INIT(0, 0)
-  __Pyx_NAMESTR("_cdec.__pyx_scope_struct_2_kbest"), /*tp_name*/
-  sizeof(struct __pyx_obj_5_cdec___pyx_scope_struct_2_kbest), /*tp_basicsize*/
+  __Pyx_NAMESTR("_cdec.__pyx_scope_struct_4___get__"), /*tp_name*/
+  sizeof(struct __pyx_obj_5_cdec___pyx_scope_struct_4___get__), /*tp_basicsize*/
   0, /*tp_itemsize*/
-  __pyx_tp_dealloc_5_cdec___pyx_scope_struct_2_kbest, /*tp_dealloc*/
+  __pyx_tp_dealloc_5_cdec___pyx_scope_struct_4___get__, /*tp_dealloc*/
   0, /*tp_print*/
   0, /*tp_getattr*/
   0, /*tp_setattr*/
@@ -17131,24 +21092,24 @@ static PyTypeObject __pyx_type_5_cdec___pyx_scope_struct_2_kbest = {
   0, /*reserved*/
   #endif
   0, /*tp_repr*/
-  &__pyx_tp_as_number___pyx_scope_struct_2_kbest, /*tp_as_number*/
-  &__pyx_tp_as_sequence___pyx_scope_struct_2_kbest, /*tp_as_sequence*/
-  &__pyx_tp_as_mapping___pyx_scope_struct_2_kbest, /*tp_as_mapping*/
+  &__pyx_tp_as_number___pyx_scope_struct_4___get__, /*tp_as_number*/
+  &__pyx_tp_as_sequence___pyx_scope_struct_4___get__, /*tp_as_sequence*/
+  &__pyx_tp_as_mapping___pyx_scope_struct_4___get__, /*tp_as_mapping*/
   0, /*tp_hash*/
   0, /*tp_call*/
   0, /*tp_str*/
   0, /*tp_getattro*/
   0, /*tp_setattro*/
-  &__pyx_tp_as_buffer___pyx_scope_struct_2_kbest, /*tp_as_buffer*/
+  &__pyx_tp_as_buffer___pyx_scope_struct_4___get__, /*tp_as_buffer*/
   Py_TPFLAGS_DEFAULT|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_HAVE_GC, /*tp_flags*/
   0, /*tp_doc*/
-  __pyx_tp_traverse_5_cdec___pyx_scope_struct_2_kbest, /*tp_traverse*/
-  __pyx_tp_clear_5_cdec___pyx_scope_struct_2_kbest, /*tp_clear*/
+  __pyx_tp_traverse_5_cdec___pyx_scope_struct_4___get__, /*tp_traverse*/
+  __pyx_tp_clear_5_cdec___pyx_scope_struct_4___get__, /*tp_clear*/
   0, /*tp_richcompare*/
   0, /*tp_weaklistoffset*/
   0, /*tp_iter*/
   0, /*tp_iternext*/
-  __pyx_methods_5_cdec___pyx_scope_struct_2_kbest, /*tp_methods*/
+  __pyx_methods_5_cdec___pyx_scope_struct_4___get__, /*tp_methods*/
   0, /*tp_members*/
   0, /*tp_getset*/
   0, /*tp_base*/
@@ -17158,7 +21119,7 @@ static PyTypeObject __pyx_type_5_cdec___pyx_scope_struct_2_kbest = {
   0, /*tp_dictoffset*/
   0, /*tp_init*/
   0, /*tp_alloc*/
-  __pyx_tp_new_5_cdec___pyx_scope_struct_2_kbest, /*tp_new*/
+  __pyx_tp_new_5_cdec___pyx_scope_struct_4___get__, /*tp_new*/
   0, /*tp_free*/
   0, /*tp_is_gc*/
   0, /*tp_bases*/
@@ -17172,68 +21133,44 @@ static PyTypeObject __pyx_type_5_cdec___pyx_scope_struct_2_kbest = {
   #endif
 };
 
-static PyObject *__pyx_tp_new_5_cdec___pyx_scope_struct_3_kbest_trees(PyTypeObject *t, PyObject *a, PyObject *k) {
-  struct __pyx_obj_5_cdec___pyx_scope_struct_3_kbest_trees *p;
+static PyObject *__pyx_tp_new_5_cdec___pyx_scope_struct_5___str__(PyTypeObject *t, PyObject *a, PyObject *k) {
+  struct __pyx_obj_5_cdec___pyx_scope_struct_5___str__ *p;
   PyObject *o = (*t->tp_alloc)(t, 0);
   if (!o) return 0;
-  p = ((struct __pyx_obj_5_cdec___pyx_scope_struct_3_kbest_trees *)o);
-  p->__pyx_v_e_tree = 0;
-  p->__pyx_v_f_tree = 0;
+  p = ((struct __pyx_obj_5_cdec___pyx_scope_struct_5___str__ *)o);
   p->__pyx_v_self = 0;
-  p->__pyx_v_size = 0;
   return o;
 }
 
-static void __pyx_tp_dealloc_5_cdec___pyx_scope_struct_3_kbest_trees(PyObject *o) {
-  struct __pyx_obj_5_cdec___pyx_scope_struct_3_kbest_trees *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_3_kbest_trees *)o;
-  Py_XDECREF(((PyObject *)p->__pyx_v_e_tree));
-  Py_XDECREF(((PyObject *)p->__pyx_v_f_tree));
+static void __pyx_tp_dealloc_5_cdec___pyx_scope_struct_5___str__(PyObject *o) {
+  struct __pyx_obj_5_cdec___pyx_scope_struct_5___str__ *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_5___str__ *)o;
   Py_XDECREF(((PyObject *)p->__pyx_v_self));
-  Py_XDECREF(p->__pyx_v_size);
   (*Py_TYPE(o)->tp_free)(o);
 }
 
-static int __pyx_tp_traverse_5_cdec___pyx_scope_struct_3_kbest_trees(PyObject *o, visitproc v, void *a) {
+static int __pyx_tp_traverse_5_cdec___pyx_scope_struct_5___str__(PyObject *o, visitproc v, void *a) {
   int e;
-  struct __pyx_obj_5_cdec___pyx_scope_struct_3_kbest_trees *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_3_kbest_trees *)o;
-  if (p->__pyx_v_e_tree) {
-    e = (*v)(p->__pyx_v_e_tree, a); if (e) return e;
-  }
-  if (p->__pyx_v_f_tree) {
-    e = (*v)(p->__pyx_v_f_tree, a); if (e) return e;
-  }
+  struct __pyx_obj_5_cdec___pyx_scope_struct_5___str__ *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_5___str__ *)o;
   if (p->__pyx_v_self) {
     e = (*v)(((PyObject*)p->__pyx_v_self), a); if (e) return e;
   }
-  if (p->__pyx_v_size) {
-    e = (*v)(p->__pyx_v_size, a); if (e) return e;
-  }
   return 0;
 }
 
-static int __pyx_tp_clear_5_cdec___pyx_scope_struct_3_kbest_trees(PyObject *o) {
-  struct __pyx_obj_5_cdec___pyx_scope_struct_3_kbest_trees *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_3_kbest_trees *)o;
+static int __pyx_tp_clear_5_cdec___pyx_scope_struct_5___str__(PyObject *o) {
+  struct __pyx_obj_5_cdec___pyx_scope_struct_5___str__ *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_5___str__ *)o;
   PyObject* tmp;
-  tmp = ((PyObject*)p->__pyx_v_e_tree);
-  p->__pyx_v_e_tree = ((PyObject*)Py_None); Py_INCREF(Py_None);
-  Py_XDECREF(tmp);
-  tmp = ((PyObject*)p->__pyx_v_f_tree);
-  p->__pyx_v_f_tree = ((PyObject*)Py_None); Py_INCREF(Py_None);
-  Py_XDECREF(tmp);
   tmp = ((PyObject*)p->__pyx_v_self);
-  p->__pyx_v_self = ((struct __pyx_obj_5_cdec_Hypergraph *)Py_None); Py_INCREF(Py_None);
-  Py_XDECREF(tmp);
-  tmp = ((PyObject*)p->__pyx_v_size);
-  p->__pyx_v_size = Py_None; Py_INCREF(Py_None);
+  p->__pyx_v_self = ((struct __pyx_obj_5_cdec_BaseTRule *)Py_None); Py_INCREF(Py_None);
   Py_XDECREF(tmp);
   return 0;
 }
 
-static PyMethodDef __pyx_methods_5_cdec___pyx_scope_struct_3_kbest_trees[] = {
+static PyMethodDef __pyx_methods_5_cdec___pyx_scope_struct_5___str__[] = {
   {0, 0, 0, 0}
 };
 
-static PyNumberMethods __pyx_tp_as_number___pyx_scope_struct_3_kbest_trees = {
+static PyNumberMethods __pyx_tp_as_number___pyx_scope_struct_5___str__ = {
   0, /*nb_add*/
   0, /*nb_subtract*/
   0, /*nb_multiply*/
@@ -17291,7 +21228,7 @@ static PyNumberMethods __pyx_tp_as_number___pyx_scope_struct_3_kbest_trees = {
   #endif
 };
 
-static PySequenceMethods __pyx_tp_as_sequence___pyx_scope_struct_3_kbest_trees = {
+static PySequenceMethods __pyx_tp_as_sequence___pyx_scope_struct_5___str__ = {
   0, /*sq_length*/
   0, /*sq_concat*/
   0, /*sq_repeat*/
@@ -17304,13 +21241,13 @@ static PySequenceMethods __pyx_tp_as_sequence___pyx_scope_struct_3_kbest_trees =
   0, /*sq_inplace_repeat*/
 };
 
-static PyMappingMethods __pyx_tp_as_mapping___pyx_scope_struct_3_kbest_trees = {
+static PyMappingMethods __pyx_tp_as_mapping___pyx_scope_struct_5___str__ = {
   0, /*mp_length*/
   0, /*mp_subscript*/
   0, /*mp_ass_subscript*/
 };
 
-static PyBufferProcs __pyx_tp_as_buffer___pyx_scope_struct_3_kbest_trees = {
+static PyBufferProcs __pyx_tp_as_buffer___pyx_scope_struct_5___str__ = {
   #if PY_MAJOR_VERSION < 3
   0, /*bf_getreadbuffer*/
   #endif
@@ -17331,12 +21268,12 @@ static PyBufferProcs __pyx_tp_as_buffer___pyx_scope_struct_3_kbest_trees = {
   #endif
 };
 
-static PyTypeObject __pyx_type_5_cdec___pyx_scope_struct_3_kbest_trees = {
+static PyTypeObject __pyx_type_5_cdec___pyx_scope_struct_5___str__ = {
   PyVarObject_HEAD_INIT(0, 0)
-  __Pyx_NAMESTR("_cdec.__pyx_scope_struct_3_kbest_trees"), /*tp_name*/
-  sizeof(struct __pyx_obj_5_cdec___pyx_scope_struct_3_kbest_trees), /*tp_basicsize*/
+  __Pyx_NAMESTR("_cdec.__pyx_scope_struct_5___str__"), /*tp_name*/
+  sizeof(struct __pyx_obj_5_cdec___pyx_scope_struct_5___str__), /*tp_basicsize*/
   0, /*tp_itemsize*/
-  __pyx_tp_dealloc_5_cdec___pyx_scope_struct_3_kbest_trees, /*tp_dealloc*/
+  __pyx_tp_dealloc_5_cdec___pyx_scope_struct_5___str__, /*tp_dealloc*/
   0, /*tp_print*/
   0, /*tp_getattr*/
   0, /*tp_setattr*/
@@ -17346,24 +21283,24 @@ static PyTypeObject __pyx_type_5_cdec___pyx_scope_struct_3_kbest_trees = {
   0, /*reserved*/
   #endif
   0, /*tp_repr*/
-  &__pyx_tp_as_number___pyx_scope_struct_3_kbest_trees, /*tp_as_number*/
-  &__pyx_tp_as_sequence___pyx_scope_struct_3_kbest_trees, /*tp_as_sequence*/
-  &__pyx_tp_as_mapping___pyx_scope_struct_3_kbest_trees, /*tp_as_mapping*/
+  &__pyx_tp_as_number___pyx_scope_struct_5___str__, /*tp_as_number*/
+  &__pyx_tp_as_sequence___pyx_scope_struct_5___str__, /*tp_as_sequence*/
+  &__pyx_tp_as_mapping___pyx_scope_struct_5___str__, /*tp_as_mapping*/
   0, /*tp_hash*/
   0, /*tp_call*/
   0, /*tp_str*/
   0, /*tp_getattro*/
   0, /*tp_setattro*/
-  &__pyx_tp_as_buffer___pyx_scope_struct_3_kbest_trees, /*tp_as_buffer*/
+  &__pyx_tp_as_buffer___pyx_scope_struct_5___str__, /*tp_as_buffer*/
   Py_TPFLAGS_DEFAULT|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_HAVE_GC, /*tp_flags*/
   0, /*tp_doc*/
-  __pyx_tp_traverse_5_cdec___pyx_scope_struct_3_kbest_trees, /*tp_traverse*/
-  __pyx_tp_clear_5_cdec___pyx_scope_struct_3_kbest_trees, /*tp_clear*/
+  __pyx_tp_traverse_5_cdec___pyx_scope_struct_5___str__, /*tp_traverse*/
+  __pyx_tp_clear_5_cdec___pyx_scope_struct_5___str__, /*tp_clear*/
   0, /*tp_richcompare*/
   0, /*tp_weaklistoffset*/
   0, /*tp_iter*/
   0, /*tp_iternext*/
-  __pyx_methods_5_cdec___pyx_scope_struct_3_kbest_trees, /*tp_methods*/
+  __pyx_methods_5_cdec___pyx_scope_struct_5___str__, /*tp_methods*/
   0, /*tp_members*/
   0, /*tp_getset*/
   0, /*tp_base*/
@@ -17373,7 +21310,7 @@ static PyTypeObject __pyx_type_5_cdec___pyx_scope_struct_3_kbest_trees = {
   0, /*tp_dictoffset*/
   0, /*tp_init*/
   0, /*tp_alloc*/
-  __pyx_tp_new_5_cdec___pyx_scope_struct_3_kbest_trees, /*tp_new*/
+  __pyx_tp_new_5_cdec___pyx_scope_struct_5___str__, /*tp_new*/
   0, /*tp_free*/
   0, /*tp_is_gc*/
   0, /*tp_bases*/
@@ -17387,60 +21324,60 @@ static PyTypeObject __pyx_type_5_cdec___pyx_scope_struct_3_kbest_trees = {
   #endif
 };
 
-static PyObject *__pyx_tp_new_5_cdec___pyx_scope_struct_4_kbest_features(PyTypeObject *t, PyObject *a, PyObject *k) {
-  struct __pyx_obj_5_cdec___pyx_scope_struct_4_kbest_features *p;
+static PyObject *__pyx_tp_new_5_cdec___pyx_scope_struct_6_genexpr(PyTypeObject *t, PyObject *a, PyObject *k) {
+  struct __pyx_obj_5_cdec___pyx_scope_struct_6_genexpr *p;
   PyObject *o = (*t->tp_alloc)(t, 0);
   if (!o) return 0;
-  p = ((struct __pyx_obj_5_cdec___pyx_scope_struct_4_kbest_features *)o);
-  p->__pyx_v_fmap = 0;
-  p->__pyx_v_self = 0;
-  p->__pyx_v_size = 0;
+  p = ((struct __pyx_obj_5_cdec___pyx_scope_struct_6_genexpr *)o);
+  p->__pyx_outer_scope = 0;
+  p->__pyx_v_feat = 0;
+  p->__pyx_t_0 = 0;
   return o;
 }
 
-static void __pyx_tp_dealloc_5_cdec___pyx_scope_struct_4_kbest_features(PyObject *o) {
-  struct __pyx_obj_5_cdec___pyx_scope_struct_4_kbest_features *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_4_kbest_features *)o;
-  Py_XDECREF(((PyObject *)p->__pyx_v_fmap));
-  Py_XDECREF(((PyObject *)p->__pyx_v_self));
-  Py_XDECREF(p->__pyx_v_size);
+static void __pyx_tp_dealloc_5_cdec___pyx_scope_struct_6_genexpr(PyObject *o) {
+  struct __pyx_obj_5_cdec___pyx_scope_struct_6_genexpr *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_6_genexpr *)o;
+  Py_XDECREF(((PyObject *)p->__pyx_outer_scope));
+  Py_XDECREF(p->__pyx_v_feat);
+  Py_XDECREF(p->__pyx_t_0);
   (*Py_TYPE(o)->tp_free)(o);
 }
 
-static int __pyx_tp_traverse_5_cdec___pyx_scope_struct_4_kbest_features(PyObject *o, visitproc v, void *a) {
+static int __pyx_tp_traverse_5_cdec___pyx_scope_struct_6_genexpr(PyObject *o, visitproc v, void *a) {
   int e;
-  struct __pyx_obj_5_cdec___pyx_scope_struct_4_kbest_features *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_4_kbest_features *)o;
-  if (p->__pyx_v_fmap) {
-    e = (*v)(((PyObject*)p->__pyx_v_fmap), a); if (e) return e;
+  struct __pyx_obj_5_cdec___pyx_scope_struct_6_genexpr *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_6_genexpr *)o;
+  if (p->__pyx_outer_scope) {
+    e = (*v)(((PyObject*)p->__pyx_outer_scope), a); if (e) return e;
   }
-  if (p->__pyx_v_self) {
-    e = (*v)(((PyObject*)p->__pyx_v_self), a); if (e) return e;
+  if (p->__pyx_v_feat) {
+    e = (*v)(p->__pyx_v_feat, a); if (e) return e;
   }
-  if (p->__pyx_v_size) {
-    e = (*v)(p->__pyx_v_size, a); if (e) return e;
+  if (p->__pyx_t_0) {
+    e = (*v)(p->__pyx_t_0, a); if (e) return e;
   }
   return 0;
 }
 
-static int __pyx_tp_clear_5_cdec___pyx_scope_struct_4_kbest_features(PyObject *o) {
-  struct __pyx_obj_5_cdec___pyx_scope_struct_4_kbest_features *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_4_kbest_features *)o;
+static int __pyx_tp_clear_5_cdec___pyx_scope_struct_6_genexpr(PyObject *o) {
+  struct __pyx_obj_5_cdec___pyx_scope_struct_6_genexpr *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_6_genexpr *)o;
   PyObject* tmp;
-  tmp = ((PyObject*)p->__pyx_v_fmap);
-  p->__pyx_v_fmap = ((struct __pyx_obj_5_cdec_SparseVector *)Py_None); Py_INCREF(Py_None);
+  tmp = ((PyObject*)p->__pyx_outer_scope);
+  p->__pyx_outer_scope = ((struct __pyx_obj_5_cdec___pyx_scope_struct_5___str__ *)Py_None); Py_INCREF(Py_None);
   Py_XDECREF(tmp);
-  tmp = ((PyObject*)p->__pyx_v_self);
-  p->__pyx_v_self = ((struct __pyx_obj_5_cdec_Hypergraph *)Py_None); Py_INCREF(Py_None);
+  tmp = ((PyObject*)p->__pyx_v_feat);
+  p->__pyx_v_feat = Py_None; Py_INCREF(Py_None);
   Py_XDECREF(tmp);
-  tmp = ((PyObject*)p->__pyx_v_size);
-  p->__pyx_v_size = Py_None; Py_INCREF(Py_None);
+  tmp = ((PyObject*)p->__pyx_t_0);
+  p->__pyx_t_0 = Py_None; Py_INCREF(Py_None);
   Py_XDECREF(tmp);
   return 0;
 }
 
-static PyMethodDef __pyx_methods_5_cdec___pyx_scope_struct_4_kbest_features[] = {
+static PyMethodDef __pyx_methods_5_cdec___pyx_scope_struct_6_genexpr[] = {
   {0, 0, 0, 0}
 };
 
-static PyNumberMethods __pyx_tp_as_number___pyx_scope_struct_4_kbest_features = {
+static PyNumberMethods __pyx_tp_as_number___pyx_scope_struct_6_genexpr = {
   0, /*nb_add*/
   0, /*nb_subtract*/
   0, /*nb_multiply*/
@@ -17498,7 +21435,7 @@ static PyNumberMethods __pyx_tp_as_number___pyx_scope_struct_4_kbest_features =
   #endif
 };
 
-static PySequenceMethods __pyx_tp_as_sequence___pyx_scope_struct_4_kbest_features = {
+static PySequenceMethods __pyx_tp_as_sequence___pyx_scope_struct_6_genexpr = {
   0, /*sq_length*/
   0, /*sq_concat*/
   0, /*sq_repeat*/
@@ -17511,13 +21448,13 @@ static PySequenceMethods __pyx_tp_as_sequence___pyx_scope_struct_4_kbest_feature
   0, /*sq_inplace_repeat*/
 };
 
-static PyMappingMethods __pyx_tp_as_mapping___pyx_scope_struct_4_kbest_features = {
+static PyMappingMethods __pyx_tp_as_mapping___pyx_scope_struct_6_genexpr = {
   0, /*mp_length*/
   0, /*mp_subscript*/
   0, /*mp_ass_subscript*/
 };
 
-static PyBufferProcs __pyx_tp_as_buffer___pyx_scope_struct_4_kbest_features = {
+static PyBufferProcs __pyx_tp_as_buffer___pyx_scope_struct_6_genexpr = {
   #if PY_MAJOR_VERSION < 3
   0, /*bf_getreadbuffer*/
   #endif
@@ -17538,12 +21475,12 @@ static PyBufferProcs __pyx_tp_as_buffer___pyx_scope_struct_4_kbest_features = {
   #endif
 };
 
-static PyTypeObject __pyx_type_5_cdec___pyx_scope_struct_4_kbest_features = {
+static PyTypeObject __pyx_type_5_cdec___pyx_scope_struct_6_genexpr = {
   PyVarObject_HEAD_INIT(0, 0)
-  __Pyx_NAMESTR("_cdec.__pyx_scope_struct_4_kbest_features"), /*tp_name*/
-  sizeof(struct __pyx_obj_5_cdec___pyx_scope_struct_4_kbest_features), /*tp_basicsize*/
+  __Pyx_NAMESTR("_cdec.__pyx_scope_struct_6_genexpr"), /*tp_name*/
+  sizeof(struct __pyx_obj_5_cdec___pyx_scope_struct_6_genexpr), /*tp_basicsize*/
   0, /*tp_itemsize*/
-  __pyx_tp_dealloc_5_cdec___pyx_scope_struct_4_kbest_features, /*tp_dealloc*/
+  __pyx_tp_dealloc_5_cdec___pyx_scope_struct_6_genexpr, /*tp_dealloc*/
   0, /*tp_print*/
   0, /*tp_getattr*/
   0, /*tp_setattr*/
@@ -17553,24 +21490,24 @@ static PyTypeObject __pyx_type_5_cdec___pyx_scope_struct_4_kbest_features = {
   0, /*reserved*/
   #endif
   0, /*tp_repr*/
-  &__pyx_tp_as_number___pyx_scope_struct_4_kbest_features, /*tp_as_number*/
-  &__pyx_tp_as_sequence___pyx_scope_struct_4_kbest_features, /*tp_as_sequence*/
-  &__pyx_tp_as_mapping___pyx_scope_struct_4_kbest_features, /*tp_as_mapping*/
+  &__pyx_tp_as_number___pyx_scope_struct_6_genexpr, /*tp_as_number*/
+  &__pyx_tp_as_sequence___pyx_scope_struct_6_genexpr, /*tp_as_sequence*/
+  &__pyx_tp_as_mapping___pyx_scope_struct_6_genexpr, /*tp_as_mapping*/
   0, /*tp_hash*/
   0, /*tp_call*/
   0, /*tp_str*/
   0, /*tp_getattro*/
   0, /*tp_setattro*/
-  &__pyx_tp_as_buffer___pyx_scope_struct_4_kbest_features, /*tp_as_buffer*/
+  &__pyx_tp_as_buffer___pyx_scope_struct_6_genexpr, /*tp_as_buffer*/
   Py_TPFLAGS_DEFAULT|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_HAVE_GC, /*tp_flags*/
   0, /*tp_doc*/
-  __pyx_tp_traverse_5_cdec___pyx_scope_struct_4_kbest_features, /*tp_traverse*/
-  __pyx_tp_clear_5_cdec___pyx_scope_struct_4_kbest_features, /*tp_clear*/
+  __pyx_tp_traverse_5_cdec___pyx_scope_struct_6_genexpr, /*tp_traverse*/
+  __pyx_tp_clear_5_cdec___pyx_scope_struct_6_genexpr, /*tp_clear*/
   0, /*tp_richcompare*/
   0, /*tp_weaklistoffset*/
   0, /*tp_iter*/
   0, /*tp_iternext*/
-  __pyx_methods_5_cdec___pyx_scope_struct_4_kbest_features, /*tp_methods*/
+  __pyx_methods_5_cdec___pyx_scope_struct_6_genexpr, /*tp_methods*/
   0, /*tp_members*/
   0, /*tp_getset*/
   0, /*tp_base*/
@@ -17580,7 +21517,7 @@ static PyTypeObject __pyx_type_5_cdec___pyx_scope_struct_4_kbest_features = {
   0, /*tp_dictoffset*/
   0, /*tp_init*/
   0, /*tp_alloc*/
-  __pyx_tp_new_5_cdec___pyx_scope_struct_4_kbest_features, /*tp_new*/
+  __pyx_tp_new_5_cdec___pyx_scope_struct_6_genexpr, /*tp_new*/
   0, /*tp_free*/
   0, /*tp_is_gc*/
   0, /*tp_bases*/
@@ -17594,44 +21531,52 @@ static PyTypeObject __pyx_type_5_cdec___pyx_scope_struct_4_kbest_features = {
   #endif
 };
 
-static PyObject *__pyx_tp_new_5_cdec___pyx_scope_struct_5_sample(PyTypeObject *t, PyObject *a, PyObject *k) {
-  struct __pyx_obj_5_cdec___pyx_scope_struct_5_sample *p;
+static PyObject *__pyx_tp_new_5_cdec___pyx_scope_struct_7___iter__(PyTypeObject *t, PyObject *a, PyObject *k) {
+  struct __pyx_obj_5_cdec___pyx_scope_struct_7___iter__ *p;
   PyObject *o = (*t->tp_alloc)(t, 0);
   if (!o) return 0;
-  p = ((struct __pyx_obj_5_cdec___pyx_scope_struct_5_sample *)o);
+  p = ((struct __pyx_obj_5_cdec___pyx_scope_struct_7___iter__ *)o);
   p->__pyx_v_self = 0;
+  p->__pyx_v_trule = 0;
   return o;
 }
 
-static void __pyx_tp_dealloc_5_cdec___pyx_scope_struct_5_sample(PyObject *o) {
-  struct __pyx_obj_5_cdec___pyx_scope_struct_5_sample *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_5_sample *)o;
+static void __pyx_tp_dealloc_5_cdec___pyx_scope_struct_7___iter__(PyObject *o) {
+  struct __pyx_obj_5_cdec___pyx_scope_struct_7___iter__ *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_7___iter__ *)o;
   Py_XDECREF(((PyObject *)p->__pyx_v_self));
+  Py_XDECREF(((PyObject *)p->__pyx_v_trule));
   (*Py_TYPE(o)->tp_free)(o);
 }
 
-static int __pyx_tp_traverse_5_cdec___pyx_scope_struct_5_sample(PyObject *o, visitproc v, void *a) {
+static int __pyx_tp_traverse_5_cdec___pyx_scope_struct_7___iter__(PyObject *o, visitproc v, void *a) {
   int e;
-  struct __pyx_obj_5_cdec___pyx_scope_struct_5_sample *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_5_sample *)o;
+  struct __pyx_obj_5_cdec___pyx_scope_struct_7___iter__ *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_7___iter__ *)o;
   if (p->__pyx_v_self) {
     e = (*v)(((PyObject*)p->__pyx_v_self), a); if (e) return e;
   }
+  if (p->__pyx_v_trule) {
+    e = (*v)(((PyObject*)p->__pyx_v_trule), a); if (e) return e;
+  }
   return 0;
 }
 
-static int __pyx_tp_clear_5_cdec___pyx_scope_struct_5_sample(PyObject *o) {
-  struct __pyx_obj_5_cdec___pyx_scope_struct_5_sample *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_5_sample *)o;
+static int __pyx_tp_clear_5_cdec___pyx_scope_struct_7___iter__(PyObject *o) {
+  struct __pyx_obj_5_cdec___pyx_scope_struct_7___iter__ *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_7___iter__ *)o;
   PyObject* tmp;
   tmp = ((PyObject*)p->__pyx_v_self);
-  p->__pyx_v_self = ((struct __pyx_obj_5_cdec_Hypergraph *)Py_None); Py_INCREF(Py_None);
+  p->__pyx_v_self = ((struct __pyx_obj_5_cdec_Grammar *)Py_None); Py_INCREF(Py_None);
+  Py_XDECREF(tmp);
+  tmp = ((PyObject*)p->__pyx_v_trule);
+  p->__pyx_v_trule = ((struct __pyx_obj_5_cdec_TRule *)Py_None); Py_INCREF(Py_None);
   Py_XDECREF(tmp);
   return 0;
 }
 
-static PyMethodDef __pyx_methods_5_cdec___pyx_scope_struct_5_sample[] = {
+static PyMethodDef __pyx_methods_5_cdec___pyx_scope_struct_7___iter__[] = {
   {0, 0, 0, 0}
 };
 
-static PyNumberMethods __pyx_tp_as_number___pyx_scope_struct_5_sample = {
+static PyNumberMethods __pyx_tp_as_number___pyx_scope_struct_7___iter__ = {
   0, /*nb_add*/
   0, /*nb_subtract*/
   0, /*nb_multiply*/
@@ -17689,7 +21634,7 @@ static PyNumberMethods __pyx_tp_as_number___pyx_scope_struct_5_sample = {
   #endif
 };
 
-static PySequenceMethods __pyx_tp_as_sequence___pyx_scope_struct_5_sample = {
+static PySequenceMethods __pyx_tp_as_sequence___pyx_scope_struct_7___iter__ = {
   0, /*sq_length*/
   0, /*sq_concat*/
   0, /*sq_repeat*/
@@ -17702,13 +21647,13 @@ static PySequenceMethods __pyx_tp_as_sequence___pyx_scope_struct_5_sample = {
   0, /*sq_inplace_repeat*/
 };
 
-static PyMappingMethods __pyx_tp_as_mapping___pyx_scope_struct_5_sample = {
+static PyMappingMethods __pyx_tp_as_mapping___pyx_scope_struct_7___iter__ = {
   0, /*mp_length*/
   0, /*mp_subscript*/
   0, /*mp_ass_subscript*/
 };
 
-static PyBufferProcs __pyx_tp_as_buffer___pyx_scope_struct_5_sample = {
+static PyBufferProcs __pyx_tp_as_buffer___pyx_scope_struct_7___iter__ = {
   #if PY_MAJOR_VERSION < 3
   0, /*bf_getreadbuffer*/
   #endif
@@ -17729,12 +21674,12 @@ static PyBufferProcs __pyx_tp_as_buffer___pyx_scope_struct_5_sample = {
   #endif
 };
 
-static PyTypeObject __pyx_type_5_cdec___pyx_scope_struct_5_sample = {
+static PyTypeObject __pyx_type_5_cdec___pyx_scope_struct_7___iter__ = {
   PyVarObject_HEAD_INIT(0, 0)
-  __Pyx_NAMESTR("_cdec.__pyx_scope_struct_5_sample"), /*tp_name*/
-  sizeof(struct __pyx_obj_5_cdec___pyx_scope_struct_5_sample), /*tp_basicsize*/
+  __Pyx_NAMESTR("_cdec.__pyx_scope_struct_7___iter__"), /*tp_name*/
+  sizeof(struct __pyx_obj_5_cdec___pyx_scope_struct_7___iter__), /*tp_basicsize*/
   0, /*tp_itemsize*/
-  __pyx_tp_dealloc_5_cdec___pyx_scope_struct_5_sample, /*tp_dealloc*/
+  __pyx_tp_dealloc_5_cdec___pyx_scope_struct_7___iter__, /*tp_dealloc*/
   0, /*tp_print*/
   0, /*tp_getattr*/
   0, /*tp_setattr*/
@@ -17744,24 +21689,24 @@ static PyTypeObject __pyx_type_5_cdec___pyx_scope_struct_5_sample = {
   0, /*reserved*/
   #endif
   0, /*tp_repr*/
-  &__pyx_tp_as_number___pyx_scope_struct_5_sample, /*tp_as_number*/
-  &__pyx_tp_as_sequence___pyx_scope_struct_5_sample, /*tp_as_sequence*/
-  &__pyx_tp_as_mapping___pyx_scope_struct_5_sample, /*tp_as_mapping*/
+  &__pyx_tp_as_number___pyx_scope_struct_7___iter__, /*tp_as_number*/
+  &__pyx_tp_as_sequence___pyx_scope_struct_7___iter__, /*tp_as_sequence*/
+  &__pyx_tp_as_mapping___pyx_scope_struct_7___iter__, /*tp_as_mapping*/
   0, /*tp_hash*/
   0, /*tp_call*/
   0, /*tp_str*/
   0, /*tp_getattro*/
   0, /*tp_setattro*/
-  &__pyx_tp_as_buffer___pyx_scope_struct_5_sample, /*tp_as_buffer*/
+  &__pyx_tp_as_buffer___pyx_scope_struct_7___iter__, /*tp_as_buffer*/
   Py_TPFLAGS_DEFAULT|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_HAVE_GC, /*tp_flags*/
   0, /*tp_doc*/
-  __pyx_tp_traverse_5_cdec___pyx_scope_struct_5_sample, /*tp_traverse*/
-  __pyx_tp_clear_5_cdec___pyx_scope_struct_5_sample, /*tp_clear*/
+  __pyx_tp_traverse_5_cdec___pyx_scope_struct_7___iter__, /*tp_traverse*/
+  __pyx_tp_clear_5_cdec___pyx_scope_struct_7___iter__, /*tp_clear*/
   0, /*tp_richcompare*/
   0, /*tp_weaklistoffset*/
   0, /*tp_iter*/
   0, /*tp_iternext*/
-  __pyx_methods_5_cdec___pyx_scope_struct_5_sample, /*tp_methods*/
+  __pyx_methods_5_cdec___pyx_scope_struct_7___iter__, /*tp_methods*/
   0, /*tp_members*/
   0, /*tp_getset*/
   0, /*tp_base*/
@@ -17771,7 +21716,7 @@ static PyTypeObject __pyx_type_5_cdec___pyx_scope_struct_5_sample = {
   0, /*tp_dictoffset*/
   0, /*tp_init*/
   0, /*tp_alloc*/
-  __pyx_tp_new_5_cdec___pyx_scope_struct_5_sample, /*tp_new*/
+  __pyx_tp_new_5_cdec___pyx_scope_struct_7___iter__, /*tp_new*/
   0, /*tp_free*/
   0, /*tp_is_gc*/
   0, /*tp_bases*/
@@ -17785,44 +21730,52 @@ static PyTypeObject __pyx_type_5_cdec___pyx_scope_struct_5_sample = {
   #endif
 };
 
-static PyObject *__pyx_tp_new_5_cdec___pyx_scope_struct_6___get__(PyTypeObject *t, PyObject *a, PyObject *k) {
-  struct __pyx_obj_5_cdec___pyx_scope_struct_6___get__ *p;
+static PyObject *__pyx_tp_new_5_cdec___pyx_scope_struct_8_kbest(PyTypeObject *t, PyObject *a, PyObject *k) {
+  struct __pyx_obj_5_cdec___pyx_scope_struct_8_kbest *p;
   PyObject *o = (*t->tp_alloc)(t, 0);
   if (!o) return 0;
-  p = ((struct __pyx_obj_5_cdec___pyx_scope_struct_6___get__ *)o);
+  p = ((struct __pyx_obj_5_cdec___pyx_scope_struct_8_kbest *)o);
   p->__pyx_v_self = 0;
+  p->__pyx_v_size = 0;
   return o;
 }
 
-static void __pyx_tp_dealloc_5_cdec___pyx_scope_struct_6___get__(PyObject *o) {
-  struct __pyx_obj_5_cdec___pyx_scope_struct_6___get__ *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_6___get__ *)o;
+static void __pyx_tp_dealloc_5_cdec___pyx_scope_struct_8_kbest(PyObject *o) {
+  struct __pyx_obj_5_cdec___pyx_scope_struct_8_kbest *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_8_kbest *)o;
   Py_XDECREF(((PyObject *)p->__pyx_v_self));
+  Py_XDECREF(p->__pyx_v_size);
   (*Py_TYPE(o)->tp_free)(o);
 }
 
-static int __pyx_tp_traverse_5_cdec___pyx_scope_struct_6___get__(PyObject *o, visitproc v, void *a) {
+static int __pyx_tp_traverse_5_cdec___pyx_scope_struct_8_kbest(PyObject *o, visitproc v, void *a) {
   int e;
-  struct __pyx_obj_5_cdec___pyx_scope_struct_6___get__ *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_6___get__ *)o;
+  struct __pyx_obj_5_cdec___pyx_scope_struct_8_kbest *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_8_kbest *)o;
   if (p->__pyx_v_self) {
     e = (*v)(((PyObject*)p->__pyx_v_self), a); if (e) return e;
   }
+  if (p->__pyx_v_size) {
+    e = (*v)(p->__pyx_v_size, a); if (e) return e;
+  }
   return 0;
 }
 
-static int __pyx_tp_clear_5_cdec___pyx_scope_struct_6___get__(PyObject *o) {
-  struct __pyx_obj_5_cdec___pyx_scope_struct_6___get__ *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_6___get__ *)o;
+static int __pyx_tp_clear_5_cdec___pyx_scope_struct_8_kbest(PyObject *o) {
+  struct __pyx_obj_5_cdec___pyx_scope_struct_8_kbest *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_8_kbest *)o;
   PyObject* tmp;
   tmp = ((PyObject*)p->__pyx_v_self);
   p->__pyx_v_self = ((struct __pyx_obj_5_cdec_Hypergraph *)Py_None); Py_INCREF(Py_None);
   Py_XDECREF(tmp);
+  tmp = ((PyObject*)p->__pyx_v_size);
+  p->__pyx_v_size = Py_None; Py_INCREF(Py_None);
+  Py_XDECREF(tmp);
   return 0;
 }
 
-static PyMethodDef __pyx_methods_5_cdec___pyx_scope_struct_6___get__[] = {
+static PyMethodDef __pyx_methods_5_cdec___pyx_scope_struct_8_kbest[] = {
   {0, 0, 0, 0}
 };
 
-static PyNumberMethods __pyx_tp_as_number___pyx_scope_struct_6___get__ = {
+static PyNumberMethods __pyx_tp_as_number___pyx_scope_struct_8_kbest = {
   0, /*nb_add*/
   0, /*nb_subtract*/
   0, /*nb_multiply*/
@@ -17880,7 +21833,7 @@ static PyNumberMethods __pyx_tp_as_number___pyx_scope_struct_6___get__ = {
   #endif
 };
 
-static PySequenceMethods __pyx_tp_as_sequence___pyx_scope_struct_6___get__ = {
+static PySequenceMethods __pyx_tp_as_sequence___pyx_scope_struct_8_kbest = {
   0, /*sq_length*/
   0, /*sq_concat*/
   0, /*sq_repeat*/
@@ -17893,13 +21846,13 @@ static PySequenceMethods __pyx_tp_as_sequence___pyx_scope_struct_6___get__ = {
   0, /*sq_inplace_repeat*/
 };
 
-static PyMappingMethods __pyx_tp_as_mapping___pyx_scope_struct_6___get__ = {
+static PyMappingMethods __pyx_tp_as_mapping___pyx_scope_struct_8_kbest = {
   0, /*mp_length*/
   0, /*mp_subscript*/
   0, /*mp_ass_subscript*/
 };
 
-static PyBufferProcs __pyx_tp_as_buffer___pyx_scope_struct_6___get__ = {
+static PyBufferProcs __pyx_tp_as_buffer___pyx_scope_struct_8_kbest = {
   #if PY_MAJOR_VERSION < 3
   0, /*bf_getreadbuffer*/
   #endif
@@ -17920,12 +21873,12 @@ static PyBufferProcs __pyx_tp_as_buffer___pyx_scope_struct_6___get__ = {
   #endif
 };
 
-static PyTypeObject __pyx_type_5_cdec___pyx_scope_struct_6___get__ = {
+static PyTypeObject __pyx_type_5_cdec___pyx_scope_struct_8_kbest = {
   PyVarObject_HEAD_INIT(0, 0)
-  __Pyx_NAMESTR("_cdec.__pyx_scope_struct_6___get__"), /*tp_name*/
-  sizeof(struct __pyx_obj_5_cdec___pyx_scope_struct_6___get__), /*tp_basicsize*/
+  __Pyx_NAMESTR("_cdec.__pyx_scope_struct_8_kbest"), /*tp_name*/
+  sizeof(struct __pyx_obj_5_cdec___pyx_scope_struct_8_kbest), /*tp_basicsize*/
   0, /*tp_itemsize*/
-  __pyx_tp_dealloc_5_cdec___pyx_scope_struct_6___get__, /*tp_dealloc*/
+  __pyx_tp_dealloc_5_cdec___pyx_scope_struct_8_kbest, /*tp_dealloc*/
   0, /*tp_print*/
   0, /*tp_getattr*/
   0, /*tp_setattr*/
@@ -17935,24 +21888,24 @@ static PyTypeObject __pyx_type_5_cdec___pyx_scope_struct_6___get__ = {
   0, /*reserved*/
   #endif
   0, /*tp_repr*/
-  &__pyx_tp_as_number___pyx_scope_struct_6___get__, /*tp_as_number*/
-  &__pyx_tp_as_sequence___pyx_scope_struct_6___get__, /*tp_as_sequence*/
-  &__pyx_tp_as_mapping___pyx_scope_struct_6___get__, /*tp_as_mapping*/
+  &__pyx_tp_as_number___pyx_scope_struct_8_kbest, /*tp_as_number*/
+  &__pyx_tp_as_sequence___pyx_scope_struct_8_kbest, /*tp_as_sequence*/
+  &__pyx_tp_as_mapping___pyx_scope_struct_8_kbest, /*tp_as_mapping*/
   0, /*tp_hash*/
   0, /*tp_call*/
   0, /*tp_str*/
   0, /*tp_getattro*/
   0, /*tp_setattro*/
-  &__pyx_tp_as_buffer___pyx_scope_struct_6___get__, /*tp_as_buffer*/
+  &__pyx_tp_as_buffer___pyx_scope_struct_8_kbest, /*tp_as_buffer*/
   Py_TPFLAGS_DEFAULT|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_HAVE_GC, /*tp_flags*/
   0, /*tp_doc*/
-  __pyx_tp_traverse_5_cdec___pyx_scope_struct_6___get__, /*tp_traverse*/
-  __pyx_tp_clear_5_cdec___pyx_scope_struct_6___get__, /*tp_clear*/
+  __pyx_tp_traverse_5_cdec___pyx_scope_struct_8_kbest, /*tp_traverse*/
+  __pyx_tp_clear_5_cdec___pyx_scope_struct_8_kbest, /*tp_clear*/
   0, /*tp_richcompare*/
   0, /*tp_weaklistoffset*/
   0, /*tp_iter*/
   0, /*tp_iternext*/
-  __pyx_methods_5_cdec___pyx_scope_struct_6___get__, /*tp_methods*/
+  __pyx_methods_5_cdec___pyx_scope_struct_8_kbest, /*tp_methods*/
   0, /*tp_members*/
   0, /*tp_getset*/
   0, /*tp_base*/
@@ -17962,7 +21915,7 @@ static PyTypeObject __pyx_type_5_cdec___pyx_scope_struct_6___get__ = {
   0, /*tp_dictoffset*/
   0, /*tp_init*/
   0, /*tp_alloc*/
-  __pyx_tp_new_5_cdec___pyx_scope_struct_6___get__, /*tp_new*/
+  __pyx_tp_new_5_cdec___pyx_scope_struct_8_kbest, /*tp_new*/
   0, /*tp_free*/
   0, /*tp_is_gc*/
   0, /*tp_bases*/
@@ -17976,44 +21929,68 @@ static PyTypeObject __pyx_type_5_cdec___pyx_scope_struct_6___get__ = {
   #endif
 };
 
-static PyObject *__pyx_tp_new_5_cdec___pyx_scope_struct_7___get__(PyTypeObject *t, PyObject *a, PyObject *k) {
-  struct __pyx_obj_5_cdec___pyx_scope_struct_7___get__ *p;
+static PyObject *__pyx_tp_new_5_cdec___pyx_scope_struct_9_kbest_trees(PyTypeObject *t, PyObject *a, PyObject *k) {
+  struct __pyx_obj_5_cdec___pyx_scope_struct_9_kbest_trees *p;
   PyObject *o = (*t->tp_alloc)(t, 0);
   if (!o) return 0;
-  p = ((struct __pyx_obj_5_cdec___pyx_scope_struct_7___get__ *)o);
+  p = ((struct __pyx_obj_5_cdec___pyx_scope_struct_9_kbest_trees *)o);
+  p->__pyx_v_e_tree = 0;
+  p->__pyx_v_f_tree = 0;
   p->__pyx_v_self = 0;
+  p->__pyx_v_size = 0;
   return o;
 }
 
-static void __pyx_tp_dealloc_5_cdec___pyx_scope_struct_7___get__(PyObject *o) {
-  struct __pyx_obj_5_cdec___pyx_scope_struct_7___get__ *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_7___get__ *)o;
+static void __pyx_tp_dealloc_5_cdec___pyx_scope_struct_9_kbest_trees(PyObject *o) {
+  struct __pyx_obj_5_cdec___pyx_scope_struct_9_kbest_trees *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_9_kbest_trees *)o;
+  Py_XDECREF(((PyObject *)p->__pyx_v_e_tree));
+  Py_XDECREF(((PyObject *)p->__pyx_v_f_tree));
   Py_XDECREF(((PyObject *)p->__pyx_v_self));
+  Py_XDECREF(p->__pyx_v_size);
   (*Py_TYPE(o)->tp_free)(o);
 }
 
-static int __pyx_tp_traverse_5_cdec___pyx_scope_struct_7___get__(PyObject *o, visitproc v, void *a) {
+static int __pyx_tp_traverse_5_cdec___pyx_scope_struct_9_kbest_trees(PyObject *o, visitproc v, void *a) {
   int e;
-  struct __pyx_obj_5_cdec___pyx_scope_struct_7___get__ *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_7___get__ *)o;
+  struct __pyx_obj_5_cdec___pyx_scope_struct_9_kbest_trees *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_9_kbest_trees *)o;
+  if (p->__pyx_v_e_tree) {
+    e = (*v)(p->__pyx_v_e_tree, a); if (e) return e;
+  }
+  if (p->__pyx_v_f_tree) {
+    e = (*v)(p->__pyx_v_f_tree, a); if (e) return e;
+  }
   if (p->__pyx_v_self) {
     e = (*v)(((PyObject*)p->__pyx_v_self), a); if (e) return e;
   }
+  if (p->__pyx_v_size) {
+    e = (*v)(p->__pyx_v_size, a); if (e) return e;
+  }
   return 0;
 }
 
-static int __pyx_tp_clear_5_cdec___pyx_scope_struct_7___get__(PyObject *o) {
-  struct __pyx_obj_5_cdec___pyx_scope_struct_7___get__ *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_7___get__ *)o;
+static int __pyx_tp_clear_5_cdec___pyx_scope_struct_9_kbest_trees(PyObject *o) {
+  struct __pyx_obj_5_cdec___pyx_scope_struct_9_kbest_trees *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_9_kbest_trees *)o;
   PyObject* tmp;
+  tmp = ((PyObject*)p->__pyx_v_e_tree);
+  p->__pyx_v_e_tree = ((PyObject*)Py_None); Py_INCREF(Py_None);
+  Py_XDECREF(tmp);
+  tmp = ((PyObject*)p->__pyx_v_f_tree);
+  p->__pyx_v_f_tree = ((PyObject*)Py_None); Py_INCREF(Py_None);
+  Py_XDECREF(tmp);
   tmp = ((PyObject*)p->__pyx_v_self);
   p->__pyx_v_self = ((struct __pyx_obj_5_cdec_Hypergraph *)Py_None); Py_INCREF(Py_None);
   Py_XDECREF(tmp);
+  tmp = ((PyObject*)p->__pyx_v_size);
+  p->__pyx_v_size = Py_None; Py_INCREF(Py_None);
+  Py_XDECREF(tmp);
   return 0;
 }
 
-static PyMethodDef __pyx_methods_5_cdec___pyx_scope_struct_7___get__[] = {
+static PyMethodDef __pyx_methods_5_cdec___pyx_scope_struct_9_kbest_trees[] = {
   {0, 0, 0, 0}
 };
 
-static PyNumberMethods __pyx_tp_as_number___pyx_scope_struct_7___get__ = {
+static PyNumberMethods __pyx_tp_as_number___pyx_scope_struct_9_kbest_trees = {
   0, /*nb_add*/
   0, /*nb_subtract*/
   0, /*nb_multiply*/
@@ -18071,7 +22048,7 @@ static PyNumberMethods __pyx_tp_as_number___pyx_scope_struct_7___get__ = {
   #endif
 };
 
-static PySequenceMethods __pyx_tp_as_sequence___pyx_scope_struct_7___get__ = {
+static PySequenceMethods __pyx_tp_as_sequence___pyx_scope_struct_9_kbest_trees = {
   0, /*sq_length*/
   0, /*sq_concat*/
   0, /*sq_repeat*/
@@ -18084,13 +22061,13 @@ static PySequenceMethods __pyx_tp_as_sequence___pyx_scope_struct_7___get__ = {
   0, /*sq_inplace_repeat*/
 };
 
-static PyMappingMethods __pyx_tp_as_mapping___pyx_scope_struct_7___get__ = {
+static PyMappingMethods __pyx_tp_as_mapping___pyx_scope_struct_9_kbest_trees = {
   0, /*mp_length*/
   0, /*mp_subscript*/
   0, /*mp_ass_subscript*/
 };
 
-static PyBufferProcs __pyx_tp_as_buffer___pyx_scope_struct_7___get__ = {
+static PyBufferProcs __pyx_tp_as_buffer___pyx_scope_struct_9_kbest_trees = {
   #if PY_MAJOR_VERSION < 3
   0, /*bf_getreadbuffer*/
   #endif
@@ -18111,12 +22088,12 @@ static PyBufferProcs __pyx_tp_as_buffer___pyx_scope_struct_7___get__ = {
   #endif
 };
 
-static PyTypeObject __pyx_type_5_cdec___pyx_scope_struct_7___get__ = {
+static PyTypeObject __pyx_type_5_cdec___pyx_scope_struct_9_kbest_trees = {
   PyVarObject_HEAD_INIT(0, 0)
-  __Pyx_NAMESTR("_cdec.__pyx_scope_struct_7___get__"), /*tp_name*/
-  sizeof(struct __pyx_obj_5_cdec___pyx_scope_struct_7___get__), /*tp_basicsize*/
+  __Pyx_NAMESTR("_cdec.__pyx_scope_struct_9_kbest_trees"), /*tp_name*/
+  sizeof(struct __pyx_obj_5_cdec___pyx_scope_struct_9_kbest_trees), /*tp_basicsize*/
   0, /*tp_itemsize*/
-  __pyx_tp_dealloc_5_cdec___pyx_scope_struct_7___get__, /*tp_dealloc*/
+  __pyx_tp_dealloc_5_cdec___pyx_scope_struct_9_kbest_trees, /*tp_dealloc*/
   0, /*tp_print*/
   0, /*tp_getattr*/
   0, /*tp_setattr*/
@@ -18126,24 +22103,24 @@ static PyTypeObject __pyx_type_5_cdec___pyx_scope_struct_7___get__ = {
   0, /*reserved*/
   #endif
   0, /*tp_repr*/
-  &__pyx_tp_as_number___pyx_scope_struct_7___get__, /*tp_as_number*/
-  &__pyx_tp_as_sequence___pyx_scope_struct_7___get__, /*tp_as_sequence*/
-  &__pyx_tp_as_mapping___pyx_scope_struct_7___get__, /*tp_as_mapping*/
+  &__pyx_tp_as_number___pyx_scope_struct_9_kbest_trees, /*tp_as_number*/
+  &__pyx_tp_as_sequence___pyx_scope_struct_9_kbest_trees, /*tp_as_sequence*/
+  &__pyx_tp_as_mapping___pyx_scope_struct_9_kbest_trees, /*tp_as_mapping*/
   0, /*tp_hash*/
   0, /*tp_call*/
   0, /*tp_str*/
   0, /*tp_getattro*/
   0, /*tp_setattro*/
-  &__pyx_tp_as_buffer___pyx_scope_struct_7___get__, /*tp_as_buffer*/
+  &__pyx_tp_as_buffer___pyx_scope_struct_9_kbest_trees, /*tp_as_buffer*/
   Py_TPFLAGS_DEFAULT|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_HAVE_GC, /*tp_flags*/
   0, /*tp_doc*/
-  __pyx_tp_traverse_5_cdec___pyx_scope_struct_7___get__, /*tp_traverse*/
-  __pyx_tp_clear_5_cdec___pyx_scope_struct_7___get__, /*tp_clear*/
+  __pyx_tp_traverse_5_cdec___pyx_scope_struct_9_kbest_trees, /*tp_traverse*/
+  __pyx_tp_clear_5_cdec___pyx_scope_struct_9_kbest_trees, /*tp_clear*/
   0, /*tp_richcompare*/
   0, /*tp_weaklistoffset*/
   0, /*tp_iter*/
   0, /*tp_iternext*/
-  __pyx_methods_5_cdec___pyx_scope_struct_7___get__, /*tp_methods*/
+  __pyx_methods_5_cdec___pyx_scope_struct_9_kbest_trees, /*tp_methods*/
   0, /*tp_members*/
   0, /*tp_getset*/
   0, /*tp_base*/
@@ -18153,7 +22130,7 @@ static PyTypeObject __pyx_type_5_cdec___pyx_scope_struct_7___get__ = {
   0, /*tp_dictoffset*/
   0, /*tp_init*/
   0, /*tp_alloc*/
-  __pyx_tp_new_5_cdec___pyx_scope_struct_7___get__, /*tp_new*/
+  __pyx_tp_new_5_cdec___pyx_scope_struct_9_kbest_trees, /*tp_new*/
   0, /*tp_free*/
   0, /*tp_is_gc*/
   0, /*tp_bases*/
@@ -18167,44 +22144,60 @@ static PyTypeObject __pyx_type_5_cdec___pyx_scope_struct_7___get__ = {
   #endif
 };
 
-static PyObject *__pyx_tp_new_5_cdec___pyx_scope_struct_8__phrase(PyTypeObject *t, PyObject *a, PyObject *k) {
-  struct __pyx_obj_5_cdec___pyx_scope_struct_8__phrase *p;
+static PyObject *__pyx_tp_new_5_cdec___pyx_scope_struct_10_kbest_features(PyTypeObject *t, PyObject *a, PyObject *k) {
+  struct __pyx_obj_5_cdec___pyx_scope_struct_10_kbest_features *p;
   PyObject *o = (*t->tp_alloc)(t, 0);
   if (!o) return 0;
-  p = ((struct __pyx_obj_5_cdec___pyx_scope_struct_8__phrase *)o);
-  p->__pyx_v_phrase = 0;
+  p = ((struct __pyx_obj_5_cdec___pyx_scope_struct_10_kbest_features *)o);
+  p->__pyx_v_fmap = 0;
+  p->__pyx_v_self = 0;
+  p->__pyx_v_size = 0;
   return o;
 }
 
-static void __pyx_tp_dealloc_5_cdec___pyx_scope_struct_8__phrase(PyObject *o) {
-  struct __pyx_obj_5_cdec___pyx_scope_struct_8__phrase *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_8__phrase *)o;
-  Py_XDECREF(p->__pyx_v_phrase);
+static void __pyx_tp_dealloc_5_cdec___pyx_scope_struct_10_kbest_features(PyObject *o) {
+  struct __pyx_obj_5_cdec___pyx_scope_struct_10_kbest_features *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_10_kbest_features *)o;
+  Py_XDECREF(((PyObject *)p->__pyx_v_fmap));
+  Py_XDECREF(((PyObject *)p->__pyx_v_self));
+  Py_XDECREF(p->__pyx_v_size);
   (*Py_TYPE(o)->tp_free)(o);
 }
 
-static int __pyx_tp_traverse_5_cdec___pyx_scope_struct_8__phrase(PyObject *o, visitproc v, void *a) {
+static int __pyx_tp_traverse_5_cdec___pyx_scope_struct_10_kbest_features(PyObject *o, visitproc v, void *a) {
   int e;
-  struct __pyx_obj_5_cdec___pyx_scope_struct_8__phrase *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_8__phrase *)o;
-  if (p->__pyx_v_phrase) {
-    e = (*v)(p->__pyx_v_phrase, a); if (e) return e;
+  struct __pyx_obj_5_cdec___pyx_scope_struct_10_kbest_features *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_10_kbest_features *)o;
+  if (p->__pyx_v_fmap) {
+    e = (*v)(((PyObject*)p->__pyx_v_fmap), a); if (e) return e;
+  }
+  if (p->__pyx_v_self) {
+    e = (*v)(((PyObject*)p->__pyx_v_self), a); if (e) return e;
+  }
+  if (p->__pyx_v_size) {
+    e = (*v)(p->__pyx_v_size, a); if (e) return e;
   }
   return 0;
 }
 
-static int __pyx_tp_clear_5_cdec___pyx_scope_struct_8__phrase(PyObject *o) {
-  struct __pyx_obj_5_cdec___pyx_scope_struct_8__phrase *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_8__phrase *)o;
+static int __pyx_tp_clear_5_cdec___pyx_scope_struct_10_kbest_features(PyObject *o) {
+  struct __pyx_obj_5_cdec___pyx_scope_struct_10_kbest_features *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_10_kbest_features *)o;
   PyObject* tmp;
-  tmp = ((PyObject*)p->__pyx_v_phrase);
-  p->__pyx_v_phrase = Py_None; Py_INCREF(Py_None);
+  tmp = ((PyObject*)p->__pyx_v_fmap);
+  p->__pyx_v_fmap = ((struct __pyx_obj_5_cdec_SparseVector *)Py_None); Py_INCREF(Py_None);
+  Py_XDECREF(tmp);
+  tmp = ((PyObject*)p->__pyx_v_self);
+  p->__pyx_v_self = ((struct __pyx_obj_5_cdec_Hypergraph *)Py_None); Py_INCREF(Py_None);
+  Py_XDECREF(tmp);
+  tmp = ((PyObject*)p->__pyx_v_size);
+  p->__pyx_v_size = Py_None; Py_INCREF(Py_None);
   Py_XDECREF(tmp);
   return 0;
 }
 
-static PyMethodDef __pyx_methods_5_cdec___pyx_scope_struct_8__phrase[] = {
+static PyMethodDef __pyx_methods_5_cdec___pyx_scope_struct_10_kbest_features[] = {
   {0, 0, 0, 0}
 };
 
-static PyNumberMethods __pyx_tp_as_number___pyx_scope_struct_8__phrase = {
+static PyNumberMethods __pyx_tp_as_number___pyx_scope_struct_10_kbest_features = {
   0, /*nb_add*/
   0, /*nb_subtract*/
   0, /*nb_multiply*/
@@ -18262,7 +22255,7 @@ static PyNumberMethods __pyx_tp_as_number___pyx_scope_struct_8__phrase = {
   #endif
 };
 
-static PySequenceMethods __pyx_tp_as_sequence___pyx_scope_struct_8__phrase = {
+static PySequenceMethods __pyx_tp_as_sequence___pyx_scope_struct_10_kbest_features = {
   0, /*sq_length*/
   0, /*sq_concat*/
   0, /*sq_repeat*/
@@ -18275,13 +22268,13 @@ static PySequenceMethods __pyx_tp_as_sequence___pyx_scope_struct_8__phrase = {
   0, /*sq_inplace_repeat*/
 };
 
-static PyMappingMethods __pyx_tp_as_mapping___pyx_scope_struct_8__phrase = {
+static PyMappingMethods __pyx_tp_as_mapping___pyx_scope_struct_10_kbest_features = {
   0, /*mp_length*/
   0, /*mp_subscript*/
   0, /*mp_ass_subscript*/
 };
 
-static PyBufferProcs __pyx_tp_as_buffer___pyx_scope_struct_8__phrase = {
+static PyBufferProcs __pyx_tp_as_buffer___pyx_scope_struct_10_kbest_features = {
   #if PY_MAJOR_VERSION < 3
   0, /*bf_getreadbuffer*/
   #endif
@@ -18302,12 +22295,12 @@ static PyBufferProcs __pyx_tp_as_buffer___pyx_scope_struct_8__phrase = {
   #endif
 };
 
-static PyTypeObject __pyx_type_5_cdec___pyx_scope_struct_8__phrase = {
+static PyTypeObject __pyx_type_5_cdec___pyx_scope_struct_10_kbest_features = {
   PyVarObject_HEAD_INIT(0, 0)
-  __Pyx_NAMESTR("_cdec.__pyx_scope_struct_8__phrase"), /*tp_name*/
-  sizeof(struct __pyx_obj_5_cdec___pyx_scope_struct_8__phrase), /*tp_basicsize*/
+  __Pyx_NAMESTR("_cdec.__pyx_scope_struct_10_kbest_features"), /*tp_name*/
+  sizeof(struct __pyx_obj_5_cdec___pyx_scope_struct_10_kbest_features), /*tp_basicsize*/
   0, /*tp_itemsize*/
-  __pyx_tp_dealloc_5_cdec___pyx_scope_struct_8__phrase, /*tp_dealloc*/
+  __pyx_tp_dealloc_5_cdec___pyx_scope_struct_10_kbest_features, /*tp_dealloc*/
   0, /*tp_print*/
   0, /*tp_getattr*/
   0, /*tp_setattr*/
@@ -18317,24 +22310,24 @@ static PyTypeObject __pyx_type_5_cdec___pyx_scope_struct_8__phrase = {
   0, /*reserved*/
   #endif
   0, /*tp_repr*/
-  &__pyx_tp_as_number___pyx_scope_struct_8__phrase, /*tp_as_number*/
-  &__pyx_tp_as_sequence___pyx_scope_struct_8__phrase, /*tp_as_sequence*/
-  &__pyx_tp_as_mapping___pyx_scope_struct_8__phrase, /*tp_as_mapping*/
+  &__pyx_tp_as_number___pyx_scope_struct_10_kbest_features, /*tp_as_number*/
+  &__pyx_tp_as_sequence___pyx_scope_struct_10_kbest_features, /*tp_as_sequence*/
+  &__pyx_tp_as_mapping___pyx_scope_struct_10_kbest_features, /*tp_as_mapping*/
   0, /*tp_hash*/
   0, /*tp_call*/
   0, /*tp_str*/
   0, /*tp_getattro*/
   0, /*tp_setattro*/
-  &__pyx_tp_as_buffer___pyx_scope_struct_8__phrase, /*tp_as_buffer*/
+  &__pyx_tp_as_buffer___pyx_scope_struct_10_kbest_features, /*tp_as_buffer*/
   Py_TPFLAGS_DEFAULT|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_HAVE_GC, /*tp_flags*/
   0, /*tp_doc*/
-  __pyx_tp_traverse_5_cdec___pyx_scope_struct_8__phrase, /*tp_traverse*/
-  __pyx_tp_clear_5_cdec___pyx_scope_struct_8__phrase, /*tp_clear*/
+  __pyx_tp_traverse_5_cdec___pyx_scope_struct_10_kbest_features, /*tp_traverse*/
+  __pyx_tp_clear_5_cdec___pyx_scope_struct_10_kbest_features, /*tp_clear*/
   0, /*tp_richcompare*/
   0, /*tp_weaklistoffset*/
   0, /*tp_iter*/
   0, /*tp_iternext*/
-  __pyx_methods_5_cdec___pyx_scope_struct_8__phrase, /*tp_methods*/
+  __pyx_methods_5_cdec___pyx_scope_struct_10_kbest_features, /*tp_methods*/
   0, /*tp_members*/
   0, /*tp_getset*/
   0, /*tp_base*/
@@ -18344,7 +22337,7 @@ static PyTypeObject __pyx_type_5_cdec___pyx_scope_struct_8__phrase = {
   0, /*tp_dictoffset*/
   0, /*tp_init*/
   0, /*tp_alloc*/
-  __pyx_tp_new_5_cdec___pyx_scope_struct_8__phrase, /*tp_new*/
+  __pyx_tp_new_5_cdec___pyx_scope_struct_10_kbest_features, /*tp_new*/
   0, /*tp_free*/
   0, /*tp_is_gc*/
   0, /*tp_bases*/
@@ -18358,60 +22351,44 @@ static PyTypeObject __pyx_type_5_cdec___pyx_scope_struct_8__phrase = {
   #endif
 };
 
-static PyObject *__pyx_tp_new_5_cdec___pyx_scope_struct_9_genexpr(PyTypeObject *t, PyObject *a, PyObject *k) {
-  struct __pyx_obj_5_cdec___pyx_scope_struct_9_genexpr *p;
+static PyObject *__pyx_tp_new_5_cdec___pyx_scope_struct_11_sample(PyTypeObject *t, PyObject *a, PyObject *k) {
+  struct __pyx_obj_5_cdec___pyx_scope_struct_11_sample *p;
   PyObject *o = (*t->tp_alloc)(t, 0);
   if (!o) return 0;
-  p = ((struct __pyx_obj_5_cdec___pyx_scope_struct_9_genexpr *)o);
-  p->__pyx_outer_scope = 0;
-  p->__pyx_v_w = 0;
-  p->__pyx_t_0 = 0;
+  p = ((struct __pyx_obj_5_cdec___pyx_scope_struct_11_sample *)o);
+  p->__pyx_v_self = 0;
   return o;
 }
 
-static void __pyx_tp_dealloc_5_cdec___pyx_scope_struct_9_genexpr(PyObject *o) {
-  struct __pyx_obj_5_cdec___pyx_scope_struct_9_genexpr *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_9_genexpr *)o;
-  Py_XDECREF(((PyObject *)p->__pyx_outer_scope));
-  Py_XDECREF(p->__pyx_v_w);
-  Py_XDECREF(p->__pyx_t_0);
+static void __pyx_tp_dealloc_5_cdec___pyx_scope_struct_11_sample(PyObject *o) {
+  struct __pyx_obj_5_cdec___pyx_scope_struct_11_sample *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_11_sample *)o;
+  Py_XDECREF(((PyObject *)p->__pyx_v_self));
   (*Py_TYPE(o)->tp_free)(o);
 }
 
-static int __pyx_tp_traverse_5_cdec___pyx_scope_struct_9_genexpr(PyObject *o, visitproc v, void *a) {
+static int __pyx_tp_traverse_5_cdec___pyx_scope_struct_11_sample(PyObject *o, visitproc v, void *a) {
   int e;
-  struct __pyx_obj_5_cdec___pyx_scope_struct_9_genexpr *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_9_genexpr *)o;
-  if (p->__pyx_outer_scope) {
-    e = (*v)(((PyObject*)p->__pyx_outer_scope), a); if (e) return e;
-  }
-  if (p->__pyx_v_w) {
-    e = (*v)(p->__pyx_v_w, a); if (e) return e;
-  }
-  if (p->__pyx_t_0) {
-    e = (*v)(p->__pyx_t_0, a); if (e) return e;
+  struct __pyx_obj_5_cdec___pyx_scope_struct_11_sample *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_11_sample *)o;
+  if (p->__pyx_v_self) {
+    e = (*v)(((PyObject*)p->__pyx_v_self), a); if (e) return e;
   }
   return 0;
 }
 
-static int __pyx_tp_clear_5_cdec___pyx_scope_struct_9_genexpr(PyObject *o) {
-  struct __pyx_obj_5_cdec___pyx_scope_struct_9_genexpr *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_9_genexpr *)o;
+static int __pyx_tp_clear_5_cdec___pyx_scope_struct_11_sample(PyObject *o) {
+  struct __pyx_obj_5_cdec___pyx_scope_struct_11_sample *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_11_sample *)o;
   PyObject* tmp;
-  tmp = ((PyObject*)p->__pyx_outer_scope);
-  p->__pyx_outer_scope = ((struct __pyx_obj_5_cdec___pyx_scope_struct_8__phrase *)Py_None); Py_INCREF(Py_None);
-  Py_XDECREF(tmp);
-  tmp = ((PyObject*)p->__pyx_v_w);
-  p->__pyx_v_w = Py_None; Py_INCREF(Py_None);
-  Py_XDECREF(tmp);
-  tmp = ((PyObject*)p->__pyx_t_0);
-  p->__pyx_t_0 = Py_None; Py_INCREF(Py_None);
+  tmp = ((PyObject*)p->__pyx_v_self);
+  p->__pyx_v_self = ((struct __pyx_obj_5_cdec_Hypergraph *)Py_None); Py_INCREF(Py_None);
   Py_XDECREF(tmp);
   return 0;
 }
 
-static PyMethodDef __pyx_methods_5_cdec___pyx_scope_struct_9_genexpr[] = {
+static PyMethodDef __pyx_methods_5_cdec___pyx_scope_struct_11_sample[] = {
   {0, 0, 0, 0}
 };
 
-static PyNumberMethods __pyx_tp_as_number___pyx_scope_struct_9_genexpr = {
+static PyNumberMethods __pyx_tp_as_number___pyx_scope_struct_11_sample = {
   0, /*nb_add*/
   0, /*nb_subtract*/
   0, /*nb_multiply*/
@@ -18469,7 +22446,7 @@ static PyNumberMethods __pyx_tp_as_number___pyx_scope_struct_9_genexpr = {
   #endif
 };
 
-static PySequenceMethods __pyx_tp_as_sequence___pyx_scope_struct_9_genexpr = {
+static PySequenceMethods __pyx_tp_as_sequence___pyx_scope_struct_11_sample = {
   0, /*sq_length*/
   0, /*sq_concat*/
   0, /*sq_repeat*/
@@ -18482,13 +22459,13 @@ static PySequenceMethods __pyx_tp_as_sequence___pyx_scope_struct_9_genexpr = {
   0, /*sq_inplace_repeat*/
 };
 
-static PyMappingMethods __pyx_tp_as_mapping___pyx_scope_struct_9_genexpr = {
+static PyMappingMethods __pyx_tp_as_mapping___pyx_scope_struct_11_sample = {
   0, /*mp_length*/
   0, /*mp_subscript*/
   0, /*mp_ass_subscript*/
 };
 
-static PyBufferProcs __pyx_tp_as_buffer___pyx_scope_struct_9_genexpr = {
+static PyBufferProcs __pyx_tp_as_buffer___pyx_scope_struct_11_sample = {
   #if PY_MAJOR_VERSION < 3
   0, /*bf_getreadbuffer*/
   #endif
@@ -18509,12 +22486,12 @@ static PyBufferProcs __pyx_tp_as_buffer___pyx_scope_struct_9_genexpr = {
   #endif
 };
 
-static PyTypeObject __pyx_type_5_cdec___pyx_scope_struct_9_genexpr = {
+static PyTypeObject __pyx_type_5_cdec___pyx_scope_struct_11_sample = {
   PyVarObject_HEAD_INIT(0, 0)
-  __Pyx_NAMESTR("_cdec.__pyx_scope_struct_9_genexpr"), /*tp_name*/
-  sizeof(struct __pyx_obj_5_cdec___pyx_scope_struct_9_genexpr), /*tp_basicsize*/
+  __Pyx_NAMESTR("_cdec.__pyx_scope_struct_11_sample"), /*tp_name*/
+  sizeof(struct __pyx_obj_5_cdec___pyx_scope_struct_11_sample), /*tp_basicsize*/
   0, /*tp_itemsize*/
-  __pyx_tp_dealloc_5_cdec___pyx_scope_struct_9_genexpr, /*tp_dealloc*/
+  __pyx_tp_dealloc_5_cdec___pyx_scope_struct_11_sample, /*tp_dealloc*/
   0, /*tp_print*/
   0, /*tp_getattr*/
   0, /*tp_setattr*/
@@ -18524,24 +22501,24 @@ static PyTypeObject __pyx_type_5_cdec___pyx_scope_struct_9_genexpr = {
   0, /*reserved*/
   #endif
   0, /*tp_repr*/
-  &__pyx_tp_as_number___pyx_scope_struct_9_genexpr, /*tp_as_number*/
-  &__pyx_tp_as_sequence___pyx_scope_struct_9_genexpr, /*tp_as_sequence*/
-  &__pyx_tp_as_mapping___pyx_scope_struct_9_genexpr, /*tp_as_mapping*/
+  &__pyx_tp_as_number___pyx_scope_struct_11_sample, /*tp_as_number*/
+  &__pyx_tp_as_sequence___pyx_scope_struct_11_sample, /*tp_as_sequence*/
+  &__pyx_tp_as_mapping___pyx_scope_struct_11_sample, /*tp_as_mapping*/
   0, /*tp_hash*/
   0, /*tp_call*/
   0, /*tp_str*/
   0, /*tp_getattro*/
   0, /*tp_setattro*/
-  &__pyx_tp_as_buffer___pyx_scope_struct_9_genexpr, /*tp_as_buffer*/
+  &__pyx_tp_as_buffer___pyx_scope_struct_11_sample, /*tp_as_buffer*/
   Py_TPFLAGS_DEFAULT|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_HAVE_GC, /*tp_flags*/
   0, /*tp_doc*/
-  __pyx_tp_traverse_5_cdec___pyx_scope_struct_9_genexpr, /*tp_traverse*/
-  __pyx_tp_clear_5_cdec___pyx_scope_struct_9_genexpr, /*tp_clear*/
+  __pyx_tp_traverse_5_cdec___pyx_scope_struct_11_sample, /*tp_traverse*/
+  __pyx_tp_clear_5_cdec___pyx_scope_struct_11_sample, /*tp_clear*/
   0, /*tp_richcompare*/
   0, /*tp_weaklistoffset*/
   0, /*tp_iter*/
   0, /*tp_iternext*/
-  __pyx_methods_5_cdec___pyx_scope_struct_9_genexpr, /*tp_methods*/
+  __pyx_methods_5_cdec___pyx_scope_struct_11_sample, /*tp_methods*/
   0, /*tp_members*/
   0, /*tp_getset*/
   0, /*tp_base*/
@@ -18551,7 +22528,7 @@ static PyTypeObject __pyx_type_5_cdec___pyx_scope_struct_9_genexpr = {
   0, /*tp_dictoffset*/
   0, /*tp_init*/
   0, /*tp_alloc*/
-  __pyx_tp_new_5_cdec___pyx_scope_struct_9_genexpr, /*tp_new*/
+  __pyx_tp_new_5_cdec___pyx_scope_struct_11_sample, /*tp_new*/
   0, /*tp_free*/
   0, /*tp_is_gc*/
   0, /*tp_bases*/
@@ -18565,44 +22542,44 @@ static PyTypeObject __pyx_type_5_cdec___pyx_scope_struct_9_genexpr = {
   #endif
 };
 
-static PyObject *__pyx_tp_new_5_cdec___pyx_scope_struct_10___str__(PyTypeObject *t, PyObject *a, PyObject *k) {
-  struct __pyx_obj_5_cdec___pyx_scope_struct_10___str__ *p;
+static PyObject *__pyx_tp_new_5_cdec___pyx_scope_struct_12___get__(PyTypeObject *t, PyObject *a, PyObject *k) {
+  struct __pyx_obj_5_cdec___pyx_scope_struct_12___get__ *p;
   PyObject *o = (*t->tp_alloc)(t, 0);
   if (!o) return 0;
-  p = ((struct __pyx_obj_5_cdec___pyx_scope_struct_10___str__ *)o);
+  p = ((struct __pyx_obj_5_cdec___pyx_scope_struct_12___get__ *)o);
   p->__pyx_v_self = 0;
   return o;
 }
 
-static void __pyx_tp_dealloc_5_cdec___pyx_scope_struct_10___str__(PyObject *o) {
-  struct __pyx_obj_5_cdec___pyx_scope_struct_10___str__ *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_10___str__ *)o;
+static void __pyx_tp_dealloc_5_cdec___pyx_scope_struct_12___get__(PyObject *o) {
+  struct __pyx_obj_5_cdec___pyx_scope_struct_12___get__ *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_12___get__ *)o;
   Py_XDECREF(((PyObject *)p->__pyx_v_self));
   (*Py_TYPE(o)->tp_free)(o);
 }
 
-static int __pyx_tp_traverse_5_cdec___pyx_scope_struct_10___str__(PyObject *o, visitproc v, void *a) {
+static int __pyx_tp_traverse_5_cdec___pyx_scope_struct_12___get__(PyObject *o, visitproc v, void *a) {
   int e;
-  struct __pyx_obj_5_cdec___pyx_scope_struct_10___str__ *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_10___str__ *)o;
+  struct __pyx_obj_5_cdec___pyx_scope_struct_12___get__ *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_12___get__ *)o;
   if (p->__pyx_v_self) {
     e = (*v)(((PyObject*)p->__pyx_v_self), a); if (e) return e;
   }
   return 0;
 }
 
-static int __pyx_tp_clear_5_cdec___pyx_scope_struct_10___str__(PyObject *o) {
-  struct __pyx_obj_5_cdec___pyx_scope_struct_10___str__ *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_10___str__ *)o;
+static int __pyx_tp_clear_5_cdec___pyx_scope_struct_12___get__(PyObject *o) {
+  struct __pyx_obj_5_cdec___pyx_scope_struct_12___get__ *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_12___get__ *)o;
   PyObject* tmp;
   tmp = ((PyObject*)p->__pyx_v_self);
-  p->__pyx_v_self = ((struct __pyx_obj_5_cdec_TRule *)Py_None); Py_INCREF(Py_None);
+  p->__pyx_v_self = ((struct __pyx_obj_5_cdec_Hypergraph *)Py_None); Py_INCREF(Py_None);
   Py_XDECREF(tmp);
   return 0;
 }
 
-static PyMethodDef __pyx_methods_5_cdec___pyx_scope_struct_10___str__[] = {
+static PyMethodDef __pyx_methods_5_cdec___pyx_scope_struct_12___get__[] = {
   {0, 0, 0, 0}
 };
 
-static PyNumberMethods __pyx_tp_as_number___pyx_scope_struct_10___str__ = {
+static PyNumberMethods __pyx_tp_as_number___pyx_scope_struct_12___get__ = {
   0, /*nb_add*/
   0, /*nb_subtract*/
   0, /*nb_multiply*/
@@ -18660,7 +22637,7 @@ static PyNumberMethods __pyx_tp_as_number___pyx_scope_struct_10___str__ = {
   #endif
 };
 
-static PySequenceMethods __pyx_tp_as_sequence___pyx_scope_struct_10___str__ = {
+static PySequenceMethods __pyx_tp_as_sequence___pyx_scope_struct_12___get__ = {
   0, /*sq_length*/
   0, /*sq_concat*/
   0, /*sq_repeat*/
@@ -18673,13 +22650,13 @@ static PySequenceMethods __pyx_tp_as_sequence___pyx_scope_struct_10___str__ = {
   0, /*sq_inplace_repeat*/
 };
 
-static PyMappingMethods __pyx_tp_as_mapping___pyx_scope_struct_10___str__ = {
+static PyMappingMethods __pyx_tp_as_mapping___pyx_scope_struct_12___get__ = {
   0, /*mp_length*/
   0, /*mp_subscript*/
   0, /*mp_ass_subscript*/
 };
 
-static PyBufferProcs __pyx_tp_as_buffer___pyx_scope_struct_10___str__ = {
+static PyBufferProcs __pyx_tp_as_buffer___pyx_scope_struct_12___get__ = {
   #if PY_MAJOR_VERSION < 3
   0, /*bf_getreadbuffer*/
   #endif
@@ -18700,12 +22677,12 @@ static PyBufferProcs __pyx_tp_as_buffer___pyx_scope_struct_10___str__ = {
   #endif
 };
 
-static PyTypeObject __pyx_type_5_cdec___pyx_scope_struct_10___str__ = {
+static PyTypeObject __pyx_type_5_cdec___pyx_scope_struct_12___get__ = {
   PyVarObject_HEAD_INIT(0, 0)
-  __Pyx_NAMESTR("_cdec.__pyx_scope_struct_10___str__"), /*tp_name*/
-  sizeof(struct __pyx_obj_5_cdec___pyx_scope_struct_10___str__), /*tp_basicsize*/
+  __Pyx_NAMESTR("_cdec.__pyx_scope_struct_12___get__"), /*tp_name*/
+  sizeof(struct __pyx_obj_5_cdec___pyx_scope_struct_12___get__), /*tp_basicsize*/
   0, /*tp_itemsize*/
-  __pyx_tp_dealloc_5_cdec___pyx_scope_struct_10___str__, /*tp_dealloc*/
+  __pyx_tp_dealloc_5_cdec___pyx_scope_struct_12___get__, /*tp_dealloc*/
   0, /*tp_print*/
   0, /*tp_getattr*/
   0, /*tp_setattr*/
@@ -18715,24 +22692,24 @@ static PyTypeObject __pyx_type_5_cdec___pyx_scope_struct_10___str__ = {
   0, /*reserved*/
   #endif
   0, /*tp_repr*/
-  &__pyx_tp_as_number___pyx_scope_struct_10___str__, /*tp_as_number*/
-  &__pyx_tp_as_sequence___pyx_scope_struct_10___str__, /*tp_as_sequence*/
-  &__pyx_tp_as_mapping___pyx_scope_struct_10___str__, /*tp_as_mapping*/
+  &__pyx_tp_as_number___pyx_scope_struct_12___get__, /*tp_as_number*/
+  &__pyx_tp_as_sequence___pyx_scope_struct_12___get__, /*tp_as_sequence*/
+  &__pyx_tp_as_mapping___pyx_scope_struct_12___get__, /*tp_as_mapping*/
   0, /*tp_hash*/
   0, /*tp_call*/
   0, /*tp_str*/
   0, /*tp_getattro*/
   0, /*tp_setattro*/
-  &__pyx_tp_as_buffer___pyx_scope_struct_10___str__, /*tp_as_buffer*/
+  &__pyx_tp_as_buffer___pyx_scope_struct_12___get__, /*tp_as_buffer*/
   Py_TPFLAGS_DEFAULT|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_HAVE_GC, /*tp_flags*/
   0, /*tp_doc*/
-  __pyx_tp_traverse_5_cdec___pyx_scope_struct_10___str__, /*tp_traverse*/
-  __pyx_tp_clear_5_cdec___pyx_scope_struct_10___str__, /*tp_clear*/
+  __pyx_tp_traverse_5_cdec___pyx_scope_struct_12___get__, /*tp_traverse*/
+  __pyx_tp_clear_5_cdec___pyx_scope_struct_12___get__, /*tp_clear*/
   0, /*tp_richcompare*/
   0, /*tp_weaklistoffset*/
   0, /*tp_iter*/
   0, /*tp_iternext*/
-  __pyx_methods_5_cdec___pyx_scope_struct_10___str__, /*tp_methods*/
+  __pyx_methods_5_cdec___pyx_scope_struct_12___get__, /*tp_methods*/
   0, /*tp_members*/
   0, /*tp_getset*/
   0, /*tp_base*/
@@ -18742,7 +22719,7 @@ static PyTypeObject __pyx_type_5_cdec___pyx_scope_struct_10___str__ = {
   0, /*tp_dictoffset*/
   0, /*tp_init*/
   0, /*tp_alloc*/
-  __pyx_tp_new_5_cdec___pyx_scope_struct_10___str__, /*tp_new*/
+  __pyx_tp_new_5_cdec___pyx_scope_struct_12___get__, /*tp_new*/
   0, /*tp_free*/
   0, /*tp_is_gc*/
   0, /*tp_bases*/
@@ -18756,60 +22733,44 @@ static PyTypeObject __pyx_type_5_cdec___pyx_scope_struct_10___str__ = {
   #endif
 };
 
-static PyObject *__pyx_tp_new_5_cdec___pyx_scope_struct_11_genexpr(PyTypeObject *t, PyObject *a, PyObject *k) {
-  struct __pyx_obj_5_cdec___pyx_scope_struct_11_genexpr *p;
+static PyObject *__pyx_tp_new_5_cdec___pyx_scope_struct_13___get__(PyTypeObject *t, PyObject *a, PyObject *k) {
+  struct __pyx_obj_5_cdec___pyx_scope_struct_13___get__ *p;
   PyObject *o = (*t->tp_alloc)(t, 0);
   if (!o) return 0;
-  p = ((struct __pyx_obj_5_cdec___pyx_scope_struct_11_genexpr *)o);
-  p->__pyx_outer_scope = 0;
-  p->__pyx_v_feat = 0;
-  p->__pyx_t_0 = 0;
+  p = ((struct __pyx_obj_5_cdec___pyx_scope_struct_13___get__ *)o);
+  p->__pyx_v_self = 0;
   return o;
 }
 
-static void __pyx_tp_dealloc_5_cdec___pyx_scope_struct_11_genexpr(PyObject *o) {
-  struct __pyx_obj_5_cdec___pyx_scope_struct_11_genexpr *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_11_genexpr *)o;
-  Py_XDECREF(((PyObject *)p->__pyx_outer_scope));
-  Py_XDECREF(p->__pyx_v_feat);
-  Py_XDECREF(p->__pyx_t_0);
+static void __pyx_tp_dealloc_5_cdec___pyx_scope_struct_13___get__(PyObject *o) {
+  struct __pyx_obj_5_cdec___pyx_scope_struct_13___get__ *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_13___get__ *)o;
+  Py_XDECREF(((PyObject *)p->__pyx_v_self));
   (*Py_TYPE(o)->tp_free)(o);
 }
 
-static int __pyx_tp_traverse_5_cdec___pyx_scope_struct_11_genexpr(PyObject *o, visitproc v, void *a) {
+static int __pyx_tp_traverse_5_cdec___pyx_scope_struct_13___get__(PyObject *o, visitproc v, void *a) {
   int e;
-  struct __pyx_obj_5_cdec___pyx_scope_struct_11_genexpr *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_11_genexpr *)o;
-  if (p->__pyx_outer_scope) {
-    e = (*v)(((PyObject*)p->__pyx_outer_scope), a); if (e) return e;
-  }
-  if (p->__pyx_v_feat) {
-    e = (*v)(p->__pyx_v_feat, a); if (e) return e;
-  }
-  if (p->__pyx_t_0) {
-    e = (*v)(p->__pyx_t_0, a); if (e) return e;
+  struct __pyx_obj_5_cdec___pyx_scope_struct_13___get__ *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_13___get__ *)o;
+  if (p->__pyx_v_self) {
+    e = (*v)(((PyObject*)p->__pyx_v_self), a); if (e) return e;
   }
   return 0;
 }
 
-static int __pyx_tp_clear_5_cdec___pyx_scope_struct_11_genexpr(PyObject *o) {
-  struct __pyx_obj_5_cdec___pyx_scope_struct_11_genexpr *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_11_genexpr *)o;
+static int __pyx_tp_clear_5_cdec___pyx_scope_struct_13___get__(PyObject *o) {
+  struct __pyx_obj_5_cdec___pyx_scope_struct_13___get__ *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_13___get__ *)o;
   PyObject* tmp;
-  tmp = ((PyObject*)p->__pyx_outer_scope);
-  p->__pyx_outer_scope = ((struct __pyx_obj_5_cdec___pyx_scope_struct_10___str__ *)Py_None); Py_INCREF(Py_None);
-  Py_XDECREF(tmp);
-  tmp = ((PyObject*)p->__pyx_v_feat);
-  p->__pyx_v_feat = Py_None; Py_INCREF(Py_None);
-  Py_XDECREF(tmp);
-  tmp = ((PyObject*)p->__pyx_t_0);
-  p->__pyx_t_0 = Py_None; Py_INCREF(Py_None);
+  tmp = ((PyObject*)p->__pyx_v_self);
+  p->__pyx_v_self = ((struct __pyx_obj_5_cdec_Hypergraph *)Py_None); Py_INCREF(Py_None);
   Py_XDECREF(tmp);
   return 0;
 }
 
-static PyMethodDef __pyx_methods_5_cdec___pyx_scope_struct_11_genexpr[] = {
+static PyMethodDef __pyx_methods_5_cdec___pyx_scope_struct_13___get__[] = {
   {0, 0, 0, 0}
 };
 
-static PyNumberMethods __pyx_tp_as_number___pyx_scope_struct_11_genexpr = {
+static PyNumberMethods __pyx_tp_as_number___pyx_scope_struct_13___get__ = {
   0, /*nb_add*/
   0, /*nb_subtract*/
   0, /*nb_multiply*/
@@ -18867,7 +22828,7 @@ static PyNumberMethods __pyx_tp_as_number___pyx_scope_struct_11_genexpr = {
   #endif
 };
 
-static PySequenceMethods __pyx_tp_as_sequence___pyx_scope_struct_11_genexpr = {
+static PySequenceMethods __pyx_tp_as_sequence___pyx_scope_struct_13___get__ = {
   0, /*sq_length*/
   0, /*sq_concat*/
   0, /*sq_repeat*/
@@ -18880,13 +22841,13 @@ static PySequenceMethods __pyx_tp_as_sequence___pyx_scope_struct_11_genexpr = {
   0, /*sq_inplace_repeat*/
 };
 
-static PyMappingMethods __pyx_tp_as_mapping___pyx_scope_struct_11_genexpr = {
+static PyMappingMethods __pyx_tp_as_mapping___pyx_scope_struct_13___get__ = {
   0, /*mp_length*/
   0, /*mp_subscript*/
   0, /*mp_ass_subscript*/
 };
 
-static PyBufferProcs __pyx_tp_as_buffer___pyx_scope_struct_11_genexpr = {
+static PyBufferProcs __pyx_tp_as_buffer___pyx_scope_struct_13___get__ = {
   #if PY_MAJOR_VERSION < 3
   0, /*bf_getreadbuffer*/
   #endif
@@ -18907,12 +22868,12 @@ static PyBufferProcs __pyx_tp_as_buffer___pyx_scope_struct_11_genexpr = {
   #endif
 };
 
-static PyTypeObject __pyx_type_5_cdec___pyx_scope_struct_11_genexpr = {
+static PyTypeObject __pyx_type_5_cdec___pyx_scope_struct_13___get__ = {
   PyVarObject_HEAD_INIT(0, 0)
-  __Pyx_NAMESTR("_cdec.__pyx_scope_struct_11_genexpr"), /*tp_name*/
-  sizeof(struct __pyx_obj_5_cdec___pyx_scope_struct_11_genexpr), /*tp_basicsize*/
+  __Pyx_NAMESTR("_cdec.__pyx_scope_struct_13___get__"), /*tp_name*/
+  sizeof(struct __pyx_obj_5_cdec___pyx_scope_struct_13___get__), /*tp_basicsize*/
   0, /*tp_itemsize*/
-  __pyx_tp_dealloc_5_cdec___pyx_scope_struct_11_genexpr, /*tp_dealloc*/
+  __pyx_tp_dealloc_5_cdec___pyx_scope_struct_13___get__, /*tp_dealloc*/
   0, /*tp_print*/
   0, /*tp_getattr*/
   0, /*tp_setattr*/
@@ -18922,24 +22883,24 @@ static PyTypeObject __pyx_type_5_cdec___pyx_scope_struct_11_genexpr = {
   0, /*reserved*/
   #endif
   0, /*tp_repr*/
-  &__pyx_tp_as_number___pyx_scope_struct_11_genexpr, /*tp_as_number*/
-  &__pyx_tp_as_sequence___pyx_scope_struct_11_genexpr, /*tp_as_sequence*/
-  &__pyx_tp_as_mapping___pyx_scope_struct_11_genexpr, /*tp_as_mapping*/
+  &__pyx_tp_as_number___pyx_scope_struct_13___get__, /*tp_as_number*/
+  &__pyx_tp_as_sequence___pyx_scope_struct_13___get__, /*tp_as_sequence*/
+  &__pyx_tp_as_mapping___pyx_scope_struct_13___get__, /*tp_as_mapping*/
   0, /*tp_hash*/
   0, /*tp_call*/
   0, /*tp_str*/
   0, /*tp_getattro*/
   0, /*tp_setattro*/
-  &__pyx_tp_as_buffer___pyx_scope_struct_11_genexpr, /*tp_as_buffer*/
+  &__pyx_tp_as_buffer___pyx_scope_struct_13___get__, /*tp_as_buffer*/
   Py_TPFLAGS_DEFAULT|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_HAVE_GC, /*tp_flags*/
   0, /*tp_doc*/
-  __pyx_tp_traverse_5_cdec___pyx_scope_struct_11_genexpr, /*tp_traverse*/
-  __pyx_tp_clear_5_cdec___pyx_scope_struct_11_genexpr, /*tp_clear*/
+  __pyx_tp_traverse_5_cdec___pyx_scope_struct_13___get__, /*tp_traverse*/
+  __pyx_tp_clear_5_cdec___pyx_scope_struct_13___get__, /*tp_clear*/
   0, /*tp_richcompare*/
   0, /*tp_weaklistoffset*/
   0, /*tp_iter*/
   0, /*tp_iternext*/
-  __pyx_methods_5_cdec___pyx_scope_struct_11_genexpr, /*tp_methods*/
+  __pyx_methods_5_cdec___pyx_scope_struct_13___get__, /*tp_methods*/
   0, /*tp_members*/
   0, /*tp_getset*/
   0, /*tp_base*/
@@ -18949,7 +22910,7 @@ static PyTypeObject __pyx_type_5_cdec___pyx_scope_struct_11_genexpr = {
   0, /*tp_dictoffset*/
   0, /*tp_init*/
   0, /*tp_alloc*/
-  __pyx_tp_new_5_cdec___pyx_scope_struct_11_genexpr, /*tp_new*/
+  __pyx_tp_new_5_cdec___pyx_scope_struct_13___get__, /*tp_new*/
   0, /*tp_free*/
   0, /*tp_is_gc*/
   0, /*tp_bases*/
@@ -18963,32 +22924,32 @@ static PyTypeObject __pyx_type_5_cdec___pyx_scope_struct_11_genexpr = {
   #endif
 };
 
-static PyObject *__pyx_tp_new_5_cdec___pyx_scope_struct_12___get__(PyTypeObject *t, PyObject *a, PyObject *k) {
-  struct __pyx_obj_5_cdec___pyx_scope_struct_12___get__ *p;
+static PyObject *__pyx_tp_new_5_cdec___pyx_scope_struct_14___get__(PyTypeObject *t, PyObject *a, PyObject *k) {
+  struct __pyx_obj_5_cdec___pyx_scope_struct_14___get__ *p;
   PyObject *o = (*t->tp_alloc)(t, 0);
   if (!o) return 0;
-  p = ((struct __pyx_obj_5_cdec___pyx_scope_struct_12___get__ *)o);
+  p = ((struct __pyx_obj_5_cdec___pyx_scope_struct_14___get__ *)o);
   p->__pyx_v_self = 0;
   return o;
 }
 
-static void __pyx_tp_dealloc_5_cdec___pyx_scope_struct_12___get__(PyObject *o) {
-  struct __pyx_obj_5_cdec___pyx_scope_struct_12___get__ *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_12___get__ *)o;
+static void __pyx_tp_dealloc_5_cdec___pyx_scope_struct_14___get__(PyObject *o) {
+  struct __pyx_obj_5_cdec___pyx_scope_struct_14___get__ *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_14___get__ *)o;
   Py_XDECREF(((PyObject *)p->__pyx_v_self));
   (*Py_TYPE(o)->tp_free)(o);
 }
 
-static int __pyx_tp_traverse_5_cdec___pyx_scope_struct_12___get__(PyObject *o, visitproc v, void *a) {
+static int __pyx_tp_traverse_5_cdec___pyx_scope_struct_14___get__(PyObject *o, visitproc v, void *a) {
   int e;
-  struct __pyx_obj_5_cdec___pyx_scope_struct_12___get__ *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_12___get__ *)o;
+  struct __pyx_obj_5_cdec___pyx_scope_struct_14___get__ *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_14___get__ *)o;
   if (p->__pyx_v_self) {
     e = (*v)(((PyObject*)p->__pyx_v_self), a); if (e) return e;
   }
   return 0;
 }
 
-static int __pyx_tp_clear_5_cdec___pyx_scope_struct_12___get__(PyObject *o) {
-  struct __pyx_obj_5_cdec___pyx_scope_struct_12___get__ *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_12___get__ *)o;
+static int __pyx_tp_clear_5_cdec___pyx_scope_struct_14___get__(PyObject *o) {
+  struct __pyx_obj_5_cdec___pyx_scope_struct_14___get__ *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_14___get__ *)o;
   PyObject* tmp;
   tmp = ((PyObject*)p->__pyx_v_self);
   p->__pyx_v_self = ((struct __pyx_obj_5_cdec_HypergraphEdge *)Py_None); Py_INCREF(Py_None);
@@ -18996,11 +22957,11 @@ static int __pyx_tp_clear_5_cdec___pyx_scope_struct_12___get__(PyObject *o) {
   return 0;
 }
 
-static PyMethodDef __pyx_methods_5_cdec___pyx_scope_struct_12___get__[] = {
+static PyMethodDef __pyx_methods_5_cdec___pyx_scope_struct_14___get__[] = {
   {0, 0, 0, 0}
 };
 
-static PyNumberMethods __pyx_tp_as_number___pyx_scope_struct_12___get__ = {
+static PyNumberMethods __pyx_tp_as_number___pyx_scope_struct_14___get__ = {
   0, /*nb_add*/
   0, /*nb_subtract*/
   0, /*nb_multiply*/
@@ -19058,7 +23019,7 @@ static PyNumberMethods __pyx_tp_as_number___pyx_scope_struct_12___get__ = {
   #endif
 };
 
-static PySequenceMethods __pyx_tp_as_sequence___pyx_scope_struct_12___get__ = {
+static PySequenceMethods __pyx_tp_as_sequence___pyx_scope_struct_14___get__ = {
   0, /*sq_length*/
   0, /*sq_concat*/
   0, /*sq_repeat*/
@@ -19071,13 +23032,13 @@ static PySequenceMethods __pyx_tp_as_sequence___pyx_scope_struct_12___get__ = {
   0, /*sq_inplace_repeat*/
 };
 
-static PyMappingMethods __pyx_tp_as_mapping___pyx_scope_struct_12___get__ = {
+static PyMappingMethods __pyx_tp_as_mapping___pyx_scope_struct_14___get__ = {
   0, /*mp_length*/
   0, /*mp_subscript*/
   0, /*mp_ass_subscript*/
 };
 
-static PyBufferProcs __pyx_tp_as_buffer___pyx_scope_struct_12___get__ = {
+static PyBufferProcs __pyx_tp_as_buffer___pyx_scope_struct_14___get__ = {
   #if PY_MAJOR_VERSION < 3
   0, /*bf_getreadbuffer*/
   #endif
@@ -19098,12 +23059,12 @@ static PyBufferProcs __pyx_tp_as_buffer___pyx_scope_struct_12___get__ = {
   #endif
 };
 
-static PyTypeObject __pyx_type_5_cdec___pyx_scope_struct_12___get__ = {
+static PyTypeObject __pyx_type_5_cdec___pyx_scope_struct_14___get__ = {
   PyVarObject_HEAD_INIT(0, 0)
-  __Pyx_NAMESTR("_cdec.__pyx_scope_struct_12___get__"), /*tp_name*/
-  sizeof(struct __pyx_obj_5_cdec___pyx_scope_struct_12___get__), /*tp_basicsize*/
+  __Pyx_NAMESTR("_cdec.__pyx_scope_struct_14___get__"), /*tp_name*/
+  sizeof(struct __pyx_obj_5_cdec___pyx_scope_struct_14___get__), /*tp_basicsize*/
   0, /*tp_itemsize*/
-  __pyx_tp_dealloc_5_cdec___pyx_scope_struct_12___get__, /*tp_dealloc*/
+  __pyx_tp_dealloc_5_cdec___pyx_scope_struct_14___get__, /*tp_dealloc*/
   0, /*tp_print*/
   0, /*tp_getattr*/
   0, /*tp_setattr*/
@@ -19113,24 +23074,24 @@ static PyTypeObject __pyx_type_5_cdec___pyx_scope_struct_12___get__ = {
   0, /*reserved*/
   #endif
   0, /*tp_repr*/
-  &__pyx_tp_as_number___pyx_scope_struct_12___get__, /*tp_as_number*/
-  &__pyx_tp_as_sequence___pyx_scope_struct_12___get__, /*tp_as_sequence*/
-  &__pyx_tp_as_mapping___pyx_scope_struct_12___get__, /*tp_as_mapping*/
+  &__pyx_tp_as_number___pyx_scope_struct_14___get__, /*tp_as_number*/
+  &__pyx_tp_as_sequence___pyx_scope_struct_14___get__, /*tp_as_sequence*/
+  &__pyx_tp_as_mapping___pyx_scope_struct_14___get__, /*tp_as_mapping*/
   0, /*tp_hash*/
   0, /*tp_call*/
   0, /*tp_str*/
   0, /*tp_getattro*/
   0, /*tp_setattro*/
-  &__pyx_tp_as_buffer___pyx_scope_struct_12___get__, /*tp_as_buffer*/
+  &__pyx_tp_as_buffer___pyx_scope_struct_14___get__, /*tp_as_buffer*/
   Py_TPFLAGS_DEFAULT|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_HAVE_GC, /*tp_flags*/
   0, /*tp_doc*/
-  __pyx_tp_traverse_5_cdec___pyx_scope_struct_12___get__, /*tp_traverse*/
-  __pyx_tp_clear_5_cdec___pyx_scope_struct_12___get__, /*tp_clear*/
+  __pyx_tp_traverse_5_cdec___pyx_scope_struct_14___get__, /*tp_traverse*/
+  __pyx_tp_clear_5_cdec___pyx_scope_struct_14___get__, /*tp_clear*/
   0, /*tp_richcompare*/
   0, /*tp_weaklistoffset*/
   0, /*tp_iter*/
   0, /*tp_iternext*/
-  __pyx_methods_5_cdec___pyx_scope_struct_12___get__, /*tp_methods*/
+  __pyx_methods_5_cdec___pyx_scope_struct_14___get__, /*tp_methods*/
   0, /*tp_members*/
   0, /*tp_getset*/
   0, /*tp_base*/
@@ -19140,7 +23101,7 @@ static PyTypeObject __pyx_type_5_cdec___pyx_scope_struct_12___get__ = {
   0, /*tp_dictoffset*/
   0, /*tp_init*/
   0, /*tp_alloc*/
-  __pyx_tp_new_5_cdec___pyx_scope_struct_12___get__, /*tp_new*/
+  __pyx_tp_new_5_cdec___pyx_scope_struct_14___get__, /*tp_new*/
   0, /*tp_free*/
   0, /*tp_is_gc*/
   0, /*tp_bases*/
@@ -19154,32 +23115,32 @@ static PyTypeObject __pyx_type_5_cdec___pyx_scope_struct_12___get__ = {
   #endif
 };
 
-static PyObject *__pyx_tp_new_5_cdec___pyx_scope_struct_13___get__(PyTypeObject *t, PyObject *a, PyObject *k) {
-  struct __pyx_obj_5_cdec___pyx_scope_struct_13___get__ *p;
+static PyObject *__pyx_tp_new_5_cdec___pyx_scope_struct_15___get__(PyTypeObject *t, PyObject *a, PyObject *k) {
+  struct __pyx_obj_5_cdec___pyx_scope_struct_15___get__ *p;
   PyObject *o = (*t->tp_alloc)(t, 0);
   if (!o) return 0;
-  p = ((struct __pyx_obj_5_cdec___pyx_scope_struct_13___get__ *)o);
+  p = ((struct __pyx_obj_5_cdec___pyx_scope_struct_15___get__ *)o);
   p->__pyx_v_self = 0;
   return o;
 }
 
-static void __pyx_tp_dealloc_5_cdec___pyx_scope_struct_13___get__(PyObject *o) {
-  struct __pyx_obj_5_cdec___pyx_scope_struct_13___get__ *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_13___get__ *)o;
+static void __pyx_tp_dealloc_5_cdec___pyx_scope_struct_15___get__(PyObject *o) {
+  struct __pyx_obj_5_cdec___pyx_scope_struct_15___get__ *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_15___get__ *)o;
   Py_XDECREF(((PyObject *)p->__pyx_v_self));
   (*Py_TYPE(o)->tp_free)(o);
 }
 
-static int __pyx_tp_traverse_5_cdec___pyx_scope_struct_13___get__(PyObject *o, visitproc v, void *a) {
+static int __pyx_tp_traverse_5_cdec___pyx_scope_struct_15___get__(PyObject *o, visitproc v, void *a) {
   int e;
-  struct __pyx_obj_5_cdec___pyx_scope_struct_13___get__ *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_13___get__ *)o;
+  struct __pyx_obj_5_cdec___pyx_scope_struct_15___get__ *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_15___get__ *)o;
   if (p->__pyx_v_self) {
     e = (*v)(((PyObject*)p->__pyx_v_self), a); if (e) return e;
   }
   return 0;
 }
 
-static int __pyx_tp_clear_5_cdec___pyx_scope_struct_13___get__(PyObject *o) {
-  struct __pyx_obj_5_cdec___pyx_scope_struct_13___get__ *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_13___get__ *)o;
+static int __pyx_tp_clear_5_cdec___pyx_scope_struct_15___get__(PyObject *o) {
+  struct __pyx_obj_5_cdec___pyx_scope_struct_15___get__ *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_15___get__ *)o;
   PyObject* tmp;
   tmp = ((PyObject*)p->__pyx_v_self);
   p->__pyx_v_self = ((struct __pyx_obj_5_cdec_HypergraphNode *)Py_None); Py_INCREF(Py_None);
@@ -19187,11 +23148,11 @@ static int __pyx_tp_clear_5_cdec___pyx_scope_struct_13___get__(PyObject *o) {
   return 0;
 }
 
-static PyMethodDef __pyx_methods_5_cdec___pyx_scope_struct_13___get__[] = {
+static PyMethodDef __pyx_methods_5_cdec___pyx_scope_struct_15___get__[] = {
   {0, 0, 0, 0}
 };
 
-static PyNumberMethods __pyx_tp_as_number___pyx_scope_struct_13___get__ = {
+static PyNumberMethods __pyx_tp_as_number___pyx_scope_struct_15___get__ = {
   0, /*nb_add*/
   0, /*nb_subtract*/
   0, /*nb_multiply*/
@@ -19249,7 +23210,7 @@ static PyNumberMethods __pyx_tp_as_number___pyx_scope_struct_13___get__ = {
   #endif
 };
 
-static PySequenceMethods __pyx_tp_as_sequence___pyx_scope_struct_13___get__ = {
+static PySequenceMethods __pyx_tp_as_sequence___pyx_scope_struct_15___get__ = {
   0, /*sq_length*/
   0, /*sq_concat*/
   0, /*sq_repeat*/
@@ -19262,13 +23223,13 @@ static PySequenceMethods __pyx_tp_as_sequence___pyx_scope_struct_13___get__ = {
   0, /*sq_inplace_repeat*/
 };
 
-static PyMappingMethods __pyx_tp_as_mapping___pyx_scope_struct_13___get__ = {
+static PyMappingMethods __pyx_tp_as_mapping___pyx_scope_struct_15___get__ = {
   0, /*mp_length*/
   0, /*mp_subscript*/
   0, /*mp_ass_subscript*/
 };
 
-static PyBufferProcs __pyx_tp_as_buffer___pyx_scope_struct_13___get__ = {
+static PyBufferProcs __pyx_tp_as_buffer___pyx_scope_struct_15___get__ = {
   #if PY_MAJOR_VERSION < 3
   0, /*bf_getreadbuffer*/
   #endif
@@ -19289,12 +23250,12 @@ static PyBufferProcs __pyx_tp_as_buffer___pyx_scope_struct_13___get__ = {
   #endif
 };
 
-static PyTypeObject __pyx_type_5_cdec___pyx_scope_struct_13___get__ = {
+static PyTypeObject __pyx_type_5_cdec___pyx_scope_struct_15___get__ = {
   PyVarObject_HEAD_INIT(0, 0)
-  __Pyx_NAMESTR("_cdec.__pyx_scope_struct_13___get__"), /*tp_name*/
-  sizeof(struct __pyx_obj_5_cdec___pyx_scope_struct_13___get__), /*tp_basicsize*/
+  __Pyx_NAMESTR("_cdec.__pyx_scope_struct_15___get__"), /*tp_name*/
+  sizeof(struct __pyx_obj_5_cdec___pyx_scope_struct_15___get__), /*tp_basicsize*/
   0, /*tp_itemsize*/
-  __pyx_tp_dealloc_5_cdec___pyx_scope_struct_13___get__, /*tp_dealloc*/
+  __pyx_tp_dealloc_5_cdec___pyx_scope_struct_15___get__, /*tp_dealloc*/
   0, /*tp_print*/
   0, /*tp_getattr*/
   0, /*tp_setattr*/
@@ -19304,24 +23265,24 @@ static PyTypeObject __pyx_type_5_cdec___pyx_scope_struct_13___get__ = {
   0, /*reserved*/
   #endif
   0, /*tp_repr*/
-  &__pyx_tp_as_number___pyx_scope_struct_13___get__, /*tp_as_number*/
-  &__pyx_tp_as_sequence___pyx_scope_struct_13___get__, /*tp_as_sequence*/
-  &__pyx_tp_as_mapping___pyx_scope_struct_13___get__, /*tp_as_mapping*/
+  &__pyx_tp_as_number___pyx_scope_struct_15___get__, /*tp_as_number*/
+  &__pyx_tp_as_sequence___pyx_scope_struct_15___get__, /*tp_as_sequence*/
+  &__pyx_tp_as_mapping___pyx_scope_struct_15___get__, /*tp_as_mapping*/
   0, /*tp_hash*/
   0, /*tp_call*/
   0, /*tp_str*/
   0, /*tp_getattro*/
   0, /*tp_setattro*/
-  &__pyx_tp_as_buffer___pyx_scope_struct_13___get__, /*tp_as_buffer*/
+  &__pyx_tp_as_buffer___pyx_scope_struct_15___get__, /*tp_as_buffer*/
   Py_TPFLAGS_DEFAULT|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_HAVE_GC, /*tp_flags*/
   0, /*tp_doc*/
-  __pyx_tp_traverse_5_cdec___pyx_scope_struct_13___get__, /*tp_traverse*/
-  __pyx_tp_clear_5_cdec___pyx_scope_struct_13___get__, /*tp_clear*/
+  __pyx_tp_traverse_5_cdec___pyx_scope_struct_15___get__, /*tp_traverse*/
+  __pyx_tp_clear_5_cdec___pyx_scope_struct_15___get__, /*tp_clear*/
   0, /*tp_richcompare*/
   0, /*tp_weaklistoffset*/
   0, /*tp_iter*/
   0, /*tp_iternext*/
-  __pyx_methods_5_cdec___pyx_scope_struct_13___get__, /*tp_methods*/
+  __pyx_methods_5_cdec___pyx_scope_struct_15___get__, /*tp_methods*/
   0, /*tp_members*/
   0, /*tp_getset*/
   0, /*tp_base*/
@@ -19331,7 +23292,7 @@ static PyTypeObject __pyx_type_5_cdec___pyx_scope_struct_13___get__ = {
   0, /*tp_dictoffset*/
   0, /*tp_init*/
   0, /*tp_alloc*/
-  __pyx_tp_new_5_cdec___pyx_scope_struct_13___get__, /*tp_new*/
+  __pyx_tp_new_5_cdec___pyx_scope_struct_15___get__, /*tp_new*/
   0, /*tp_free*/
   0, /*tp_is_gc*/
   0, /*tp_bases*/
@@ -19345,32 +23306,32 @@ static PyTypeObject __pyx_type_5_cdec___pyx_scope_struct_13___get__ = {
   #endif
 };
 
-static PyObject *__pyx_tp_new_5_cdec___pyx_scope_struct_14___get__(PyTypeObject *t, PyObject *a, PyObject *k) {
-  struct __pyx_obj_5_cdec___pyx_scope_struct_14___get__ *p;
+static PyObject *__pyx_tp_new_5_cdec___pyx_scope_struct_16___get__(PyTypeObject *t, PyObject *a, PyObject *k) {
+  struct __pyx_obj_5_cdec___pyx_scope_struct_16___get__ *p;
   PyObject *o = (*t->tp_alloc)(t, 0);
   if (!o) return 0;
-  p = ((struct __pyx_obj_5_cdec___pyx_scope_struct_14___get__ *)o);
+  p = ((struct __pyx_obj_5_cdec___pyx_scope_struct_16___get__ *)o);
   p->__pyx_v_self = 0;
   return o;
 }
 
-static void __pyx_tp_dealloc_5_cdec___pyx_scope_struct_14___get__(PyObject *o) {
-  struct __pyx_obj_5_cdec___pyx_scope_struct_14___get__ *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_14___get__ *)o;
+static void __pyx_tp_dealloc_5_cdec___pyx_scope_struct_16___get__(PyObject *o) {
+  struct __pyx_obj_5_cdec___pyx_scope_struct_16___get__ *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_16___get__ *)o;
   Py_XDECREF(((PyObject *)p->__pyx_v_self));
   (*Py_TYPE(o)->tp_free)(o);
 }
 
-static int __pyx_tp_traverse_5_cdec___pyx_scope_struct_14___get__(PyObject *o, visitproc v, void *a) {
+static int __pyx_tp_traverse_5_cdec___pyx_scope_struct_16___get__(PyObject *o, visitproc v, void *a) {
   int e;
-  struct __pyx_obj_5_cdec___pyx_scope_struct_14___get__ *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_14___get__ *)o;
+  struct __pyx_obj_5_cdec___pyx_scope_struct_16___get__ *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_16___get__ *)o;
   if (p->__pyx_v_self) {
     e = (*v)(((PyObject*)p->__pyx_v_self), a); if (e) return e;
   }
   return 0;
 }
 
-static int __pyx_tp_clear_5_cdec___pyx_scope_struct_14___get__(PyObject *o) {
-  struct __pyx_obj_5_cdec___pyx_scope_struct_14___get__ *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_14___get__ *)o;
+static int __pyx_tp_clear_5_cdec___pyx_scope_struct_16___get__(PyObject *o) {
+  struct __pyx_obj_5_cdec___pyx_scope_struct_16___get__ *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_16___get__ *)o;
   PyObject* tmp;
   tmp = ((PyObject*)p->__pyx_v_self);
   p->__pyx_v_self = ((struct __pyx_obj_5_cdec_HypergraphNode *)Py_None); Py_INCREF(Py_None);
@@ -19378,11 +23339,11 @@ static int __pyx_tp_clear_5_cdec___pyx_scope_struct_14___get__(PyObject *o) {
   return 0;
 }
 
-static PyMethodDef __pyx_methods_5_cdec___pyx_scope_struct_14___get__[] = {
+static PyMethodDef __pyx_methods_5_cdec___pyx_scope_struct_16___get__[] = {
   {0, 0, 0, 0}
 };
 
-static PyNumberMethods __pyx_tp_as_number___pyx_scope_struct_14___get__ = {
+static PyNumberMethods __pyx_tp_as_number___pyx_scope_struct_16___get__ = {
   0, /*nb_add*/
   0, /*nb_subtract*/
   0, /*nb_multiply*/
@@ -19440,7 +23401,7 @@ static PyNumberMethods __pyx_tp_as_number___pyx_scope_struct_14___get__ = {
   #endif
 };
 
-static PySequenceMethods __pyx_tp_as_sequence___pyx_scope_struct_14___get__ = {
+static PySequenceMethods __pyx_tp_as_sequence___pyx_scope_struct_16___get__ = {
   0, /*sq_length*/
   0, /*sq_concat*/
   0, /*sq_repeat*/
@@ -19453,13 +23414,13 @@ static PySequenceMethods __pyx_tp_as_sequence___pyx_scope_struct_14___get__ = {
   0, /*sq_inplace_repeat*/
 };
 
-static PyMappingMethods __pyx_tp_as_mapping___pyx_scope_struct_14___get__ = {
+static PyMappingMethods __pyx_tp_as_mapping___pyx_scope_struct_16___get__ = {
   0, /*mp_length*/
   0, /*mp_subscript*/
   0, /*mp_ass_subscript*/
 };
 
-static PyBufferProcs __pyx_tp_as_buffer___pyx_scope_struct_14___get__ = {
+static PyBufferProcs __pyx_tp_as_buffer___pyx_scope_struct_16___get__ = {
   #if PY_MAJOR_VERSION < 3
   0, /*bf_getreadbuffer*/
   #endif
@@ -19480,12 +23441,12 @@ static PyBufferProcs __pyx_tp_as_buffer___pyx_scope_struct_14___get__ = {
   #endif
 };
 
-static PyTypeObject __pyx_type_5_cdec___pyx_scope_struct_14___get__ = {
+static PyTypeObject __pyx_type_5_cdec___pyx_scope_struct_16___get__ = {
   PyVarObject_HEAD_INIT(0, 0)
-  __Pyx_NAMESTR("_cdec.__pyx_scope_struct_14___get__"), /*tp_name*/
-  sizeof(struct __pyx_obj_5_cdec___pyx_scope_struct_14___get__), /*tp_basicsize*/
+  __Pyx_NAMESTR("_cdec.__pyx_scope_struct_16___get__"), /*tp_name*/
+  sizeof(struct __pyx_obj_5_cdec___pyx_scope_struct_16___get__), /*tp_basicsize*/
   0, /*tp_itemsize*/
-  __pyx_tp_dealloc_5_cdec___pyx_scope_struct_14___get__, /*tp_dealloc*/
+  __pyx_tp_dealloc_5_cdec___pyx_scope_struct_16___get__, /*tp_dealloc*/
   0, /*tp_print*/
   0, /*tp_getattr*/
   0, /*tp_setattr*/
@@ -19495,24 +23456,24 @@ static PyTypeObject __pyx_type_5_cdec___pyx_scope_struct_14___get__ = {
   0, /*reserved*/
   #endif
   0, /*tp_repr*/
-  &__pyx_tp_as_number___pyx_scope_struct_14___get__, /*tp_as_number*/
-  &__pyx_tp_as_sequence___pyx_scope_struct_14___get__, /*tp_as_sequence*/
-  &__pyx_tp_as_mapping___pyx_scope_struct_14___get__, /*tp_as_mapping*/
+  &__pyx_tp_as_number___pyx_scope_struct_16___get__, /*tp_as_number*/
+  &__pyx_tp_as_sequence___pyx_scope_struct_16___get__, /*tp_as_sequence*/
+  &__pyx_tp_as_mapping___pyx_scope_struct_16___get__, /*tp_as_mapping*/
   0, /*tp_hash*/
   0, /*tp_call*/
   0, /*tp_str*/
   0, /*tp_getattro*/
   0, /*tp_setattro*/
-  &__pyx_tp_as_buffer___pyx_scope_struct_14___get__, /*tp_as_buffer*/
+  &__pyx_tp_as_buffer___pyx_scope_struct_16___get__, /*tp_as_buffer*/
   Py_TPFLAGS_DEFAULT|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_HAVE_GC, /*tp_flags*/
   0, /*tp_doc*/
-  __pyx_tp_traverse_5_cdec___pyx_scope_struct_14___get__, /*tp_traverse*/
-  __pyx_tp_clear_5_cdec___pyx_scope_struct_14___get__, /*tp_clear*/
+  __pyx_tp_traverse_5_cdec___pyx_scope_struct_16___get__, /*tp_traverse*/
+  __pyx_tp_clear_5_cdec___pyx_scope_struct_16___get__, /*tp_clear*/
   0, /*tp_richcompare*/
   0, /*tp_weaklistoffset*/
   0, /*tp_iter*/
   0, /*tp_iternext*/
-  __pyx_methods_5_cdec___pyx_scope_struct_14___get__, /*tp_methods*/
+  __pyx_methods_5_cdec___pyx_scope_struct_16___get__, /*tp_methods*/
   0, /*tp_members*/
   0, /*tp_getset*/
   0, /*tp_base*/
@@ -19522,7 +23483,7 @@ static PyTypeObject __pyx_type_5_cdec___pyx_scope_struct_14___get__ = {
   0, /*tp_dictoffset*/
   0, /*tp_init*/
   0, /*tp_alloc*/
-  __pyx_tp_new_5_cdec___pyx_scope_struct_14___get__, /*tp_new*/
+  __pyx_tp_new_5_cdec___pyx_scope_struct_16___get__, /*tp_new*/
   0, /*tp_free*/
   0, /*tp_is_gc*/
   0, /*tp_bases*/
@@ -19536,32 +23497,32 @@ static PyTypeObject __pyx_type_5_cdec___pyx_scope_struct_14___get__ = {
   #endif
 };
 
-static PyObject *__pyx_tp_new_5_cdec___pyx_scope_struct_15___iter__(PyTypeObject *t, PyObject *a, PyObject *k) {
-  struct __pyx_obj_5_cdec___pyx_scope_struct_15___iter__ *p;
+static PyObject *__pyx_tp_new_5_cdec___pyx_scope_struct_17___iter__(PyTypeObject *t, PyObject *a, PyObject *k) {
+  struct __pyx_obj_5_cdec___pyx_scope_struct_17___iter__ *p;
   PyObject *o = (*t->tp_alloc)(t, 0);
   if (!o) return 0;
-  p = ((struct __pyx_obj_5_cdec___pyx_scope_struct_15___iter__ *)o);
+  p = ((struct __pyx_obj_5_cdec___pyx_scope_struct_17___iter__ *)o);
   p->__pyx_v_self = 0;
   return o;
 }
 
-static void __pyx_tp_dealloc_5_cdec___pyx_scope_struct_15___iter__(PyObject *o) {
-  struct __pyx_obj_5_cdec___pyx_scope_struct_15___iter__ *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_15___iter__ *)o;
+static void __pyx_tp_dealloc_5_cdec___pyx_scope_struct_17___iter__(PyObject *o) {
+  struct __pyx_obj_5_cdec___pyx_scope_struct_17___iter__ *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_17___iter__ *)o;
   Py_XDECREF(((PyObject *)p->__pyx_v_self));
   (*Py_TYPE(o)->tp_free)(o);
 }
 
-static int __pyx_tp_traverse_5_cdec___pyx_scope_struct_15___iter__(PyObject *o, visitproc v, void *a) {
+static int __pyx_tp_traverse_5_cdec___pyx_scope_struct_17___iter__(PyObject *o, visitproc v, void *a) {
   int e;
-  struct __pyx_obj_5_cdec___pyx_scope_struct_15___iter__ *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_15___iter__ *)o;
+  struct __pyx_obj_5_cdec___pyx_scope_struct_17___iter__ *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_17___iter__ *)o;
   if (p->__pyx_v_self) {
     e = (*v)(((PyObject*)p->__pyx_v_self), a); if (e) return e;
   }
   return 0;
 }
 
-static int __pyx_tp_clear_5_cdec___pyx_scope_struct_15___iter__(PyObject *o) {
-  struct __pyx_obj_5_cdec___pyx_scope_struct_15___iter__ *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_15___iter__ *)o;
+static int __pyx_tp_clear_5_cdec___pyx_scope_struct_17___iter__(PyObject *o) {
+  struct __pyx_obj_5_cdec___pyx_scope_struct_17___iter__ *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_17___iter__ *)o;
   PyObject* tmp;
   tmp = ((PyObject*)p->__pyx_v_self);
   p->__pyx_v_self = ((struct __pyx_obj_5_cdec_Lattice *)Py_None); Py_INCREF(Py_None);
@@ -19569,11 +23530,11 @@ static int __pyx_tp_clear_5_cdec___pyx_scope_struct_15___iter__(PyObject *o) {
   return 0;
 }
 
-static PyMethodDef __pyx_methods_5_cdec___pyx_scope_struct_15___iter__[] = {
+static PyMethodDef __pyx_methods_5_cdec___pyx_scope_struct_17___iter__[] = {
   {0, 0, 0, 0}
 };
 
-static PyNumberMethods __pyx_tp_as_number___pyx_scope_struct_15___iter__ = {
+static PyNumberMethods __pyx_tp_as_number___pyx_scope_struct_17___iter__ = {
   0, /*nb_add*/
   0, /*nb_subtract*/
   0, /*nb_multiply*/
@@ -19631,7 +23592,7 @@ static PyNumberMethods __pyx_tp_as_number___pyx_scope_struct_15___iter__ = {
   #endif
 };
 
-static PySequenceMethods __pyx_tp_as_sequence___pyx_scope_struct_15___iter__ = {
+static PySequenceMethods __pyx_tp_as_sequence___pyx_scope_struct_17___iter__ = {
   0, /*sq_length*/
   0, /*sq_concat*/
   0, /*sq_repeat*/
@@ -19644,13 +23605,13 @@ static PySequenceMethods __pyx_tp_as_sequence___pyx_scope_struct_15___iter__ = {
   0, /*sq_inplace_repeat*/
 };
 
-static PyMappingMethods __pyx_tp_as_mapping___pyx_scope_struct_15___iter__ = {
+static PyMappingMethods __pyx_tp_as_mapping___pyx_scope_struct_17___iter__ = {
   0, /*mp_length*/
   0, /*mp_subscript*/
   0, /*mp_ass_subscript*/
 };
 
-static PyBufferProcs __pyx_tp_as_buffer___pyx_scope_struct_15___iter__ = {
+static PyBufferProcs __pyx_tp_as_buffer___pyx_scope_struct_17___iter__ = {
   #if PY_MAJOR_VERSION < 3
   0, /*bf_getreadbuffer*/
   #endif
@@ -19671,12 +23632,12 @@ static PyBufferProcs __pyx_tp_as_buffer___pyx_scope_struct_15___iter__ = {
   #endif
 };
 
-static PyTypeObject __pyx_type_5_cdec___pyx_scope_struct_15___iter__ = {
+static PyTypeObject __pyx_type_5_cdec___pyx_scope_struct_17___iter__ = {
   PyVarObject_HEAD_INIT(0, 0)
-  __Pyx_NAMESTR("_cdec.__pyx_scope_struct_15___iter__"), /*tp_name*/
-  sizeof(struct __pyx_obj_5_cdec___pyx_scope_struct_15___iter__), /*tp_basicsize*/
+  __Pyx_NAMESTR("_cdec.__pyx_scope_struct_17___iter__"), /*tp_name*/
+  sizeof(struct __pyx_obj_5_cdec___pyx_scope_struct_17___iter__), /*tp_basicsize*/
   0, /*tp_itemsize*/
-  __pyx_tp_dealloc_5_cdec___pyx_scope_struct_15___iter__, /*tp_dealloc*/
+  __pyx_tp_dealloc_5_cdec___pyx_scope_struct_17___iter__, /*tp_dealloc*/
   0, /*tp_print*/
   0, /*tp_getattr*/
   0, /*tp_setattr*/
@@ -19686,24 +23647,24 @@ static PyTypeObject __pyx_type_5_cdec___pyx_scope_struct_15___iter__ = {
   0, /*reserved*/
   #endif
   0, /*tp_repr*/
-  &__pyx_tp_as_number___pyx_scope_struct_15___iter__, /*tp_as_number*/
-  &__pyx_tp_as_sequence___pyx_scope_struct_15___iter__, /*tp_as_sequence*/
-  &__pyx_tp_as_mapping___pyx_scope_struct_15___iter__, /*tp_as_mapping*/
+  &__pyx_tp_as_number___pyx_scope_struct_17___iter__, /*tp_as_number*/
+  &__pyx_tp_as_sequence___pyx_scope_struct_17___iter__, /*tp_as_sequence*/
+  &__pyx_tp_as_mapping___pyx_scope_struct_17___iter__, /*tp_as_mapping*/
   0, /*tp_hash*/
   0, /*tp_call*/
   0, /*tp_str*/
   0, /*tp_getattro*/
   0, /*tp_setattro*/
-  &__pyx_tp_as_buffer___pyx_scope_struct_15___iter__, /*tp_as_buffer*/
+  &__pyx_tp_as_buffer___pyx_scope_struct_17___iter__, /*tp_as_buffer*/
   Py_TPFLAGS_DEFAULT|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_HAVE_GC, /*tp_flags*/
   0, /*tp_doc*/
-  __pyx_tp_traverse_5_cdec___pyx_scope_struct_15___iter__, /*tp_traverse*/
-  __pyx_tp_clear_5_cdec___pyx_scope_struct_15___iter__, /*tp_clear*/
+  __pyx_tp_traverse_5_cdec___pyx_scope_struct_17___iter__, /*tp_traverse*/
+  __pyx_tp_clear_5_cdec___pyx_scope_struct_17___iter__, /*tp_clear*/
   0, /*tp_richcompare*/
   0, /*tp_weaklistoffset*/
   0, /*tp_iter*/
   0, /*tp_iternext*/
-  __pyx_methods_5_cdec___pyx_scope_struct_15___iter__, /*tp_methods*/
+  __pyx_methods_5_cdec___pyx_scope_struct_17___iter__, /*tp_methods*/
   0, /*tp_members*/
   0, /*tp_getset*/
   0, /*tp_base*/
@@ -19713,7 +23674,7 @@ static PyTypeObject __pyx_type_5_cdec___pyx_scope_struct_15___iter__ = {
   0, /*tp_dictoffset*/
   0, /*tp_init*/
   0, /*tp_alloc*/
-  __pyx_tp_new_5_cdec___pyx_scope_struct_15___iter__, /*tp_new*/
+  __pyx_tp_new_5_cdec___pyx_scope_struct_17___iter__, /*tp_new*/
   0, /*tp_free*/
   0, /*tp_is_gc*/
   0, /*tp_bases*/
@@ -19727,32 +23688,32 @@ static PyTypeObject __pyx_type_5_cdec___pyx_scope_struct_15___iter__ = {
   #endif
 };
 
-static PyObject *__pyx_tp_new_5_cdec___pyx_scope_struct_16_todot(PyTypeObject *t, PyObject *a, PyObject *k) {
-  struct __pyx_obj_5_cdec___pyx_scope_struct_16_todot *p;
+static PyObject *__pyx_tp_new_5_cdec___pyx_scope_struct_18_todot(PyTypeObject *t, PyObject *a, PyObject *k) {
+  struct __pyx_obj_5_cdec___pyx_scope_struct_18_todot *p;
   PyObject *o = (*t->tp_alloc)(t, 0);
   if (!o) return 0;
-  p = ((struct __pyx_obj_5_cdec___pyx_scope_struct_16_todot *)o);
+  p = ((struct __pyx_obj_5_cdec___pyx_scope_struct_18_todot *)o);
   p->__pyx_v_self = 0;
   return o;
 }
 
-static void __pyx_tp_dealloc_5_cdec___pyx_scope_struct_16_todot(PyObject *o) {
-  struct __pyx_obj_5_cdec___pyx_scope_struct_16_todot *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_16_todot *)o;
+static void __pyx_tp_dealloc_5_cdec___pyx_scope_struct_18_todot(PyObject *o) {
+  struct __pyx_obj_5_cdec___pyx_scope_struct_18_todot *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_18_todot *)o;
   Py_XDECREF(((PyObject *)p->__pyx_v_self));
   (*Py_TYPE(o)->tp_free)(o);
 }
 
-static int __pyx_tp_traverse_5_cdec___pyx_scope_struct_16_todot(PyObject *o, visitproc v, void *a) {
+static int __pyx_tp_traverse_5_cdec___pyx_scope_struct_18_todot(PyObject *o, visitproc v, void *a) {
   int e;
-  struct __pyx_obj_5_cdec___pyx_scope_struct_16_todot *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_16_todot *)o;
+  struct __pyx_obj_5_cdec___pyx_scope_struct_18_todot *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_18_todot *)o;
   if (p->__pyx_v_self) {
     e = (*v)(((PyObject*)p->__pyx_v_self), a); if (e) return e;
   }
   return 0;
 }
 
-static int __pyx_tp_clear_5_cdec___pyx_scope_struct_16_todot(PyObject *o) {
-  struct __pyx_obj_5_cdec___pyx_scope_struct_16_todot *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_16_todot *)o;
+static int __pyx_tp_clear_5_cdec___pyx_scope_struct_18_todot(PyObject *o) {
+  struct __pyx_obj_5_cdec___pyx_scope_struct_18_todot *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_18_todot *)o;
   PyObject* tmp;
   tmp = ((PyObject*)p->__pyx_v_self);
   p->__pyx_v_self = ((struct __pyx_obj_5_cdec_Lattice *)Py_None); Py_INCREF(Py_None);
@@ -19760,11 +23721,11 @@ static int __pyx_tp_clear_5_cdec___pyx_scope_struct_16_todot(PyObject *o) {
   return 0;
 }
 
-static PyMethodDef __pyx_methods_5_cdec___pyx_scope_struct_16_todot[] = {
+static PyMethodDef __pyx_methods_5_cdec___pyx_scope_struct_18_todot[] = {
   {0, 0, 0, 0}
 };
 
-static PyNumberMethods __pyx_tp_as_number___pyx_scope_struct_16_todot = {
+static PyNumberMethods __pyx_tp_as_number___pyx_scope_struct_18_todot = {
   0, /*nb_add*/
   0, /*nb_subtract*/
   0, /*nb_multiply*/
@@ -19822,7 +23783,7 @@ static PyNumberMethods __pyx_tp_as_number___pyx_scope_struct_16_todot = {
   #endif
 };
 
-static PySequenceMethods __pyx_tp_as_sequence___pyx_scope_struct_16_todot = {
+static PySequenceMethods __pyx_tp_as_sequence___pyx_scope_struct_18_todot = {
   0, /*sq_length*/
   0, /*sq_concat*/
   0, /*sq_repeat*/
@@ -19835,13 +23796,13 @@ static PySequenceMethods __pyx_tp_as_sequence___pyx_scope_struct_16_todot = {
   0, /*sq_inplace_repeat*/
 };
 
-static PyMappingMethods __pyx_tp_as_mapping___pyx_scope_struct_16_todot = {
+static PyMappingMethods __pyx_tp_as_mapping___pyx_scope_struct_18_todot = {
   0, /*mp_length*/
   0, /*mp_subscript*/
   0, /*mp_ass_subscript*/
 };
 
-static PyBufferProcs __pyx_tp_as_buffer___pyx_scope_struct_16_todot = {
+static PyBufferProcs __pyx_tp_as_buffer___pyx_scope_struct_18_todot = {
   #if PY_MAJOR_VERSION < 3
   0, /*bf_getreadbuffer*/
   #endif
@@ -19862,12 +23823,12 @@ static PyBufferProcs __pyx_tp_as_buffer___pyx_scope_struct_16_todot = {
   #endif
 };
 
-static PyTypeObject __pyx_type_5_cdec___pyx_scope_struct_16_todot = {
+static PyTypeObject __pyx_type_5_cdec___pyx_scope_struct_18_todot = {
   PyVarObject_HEAD_INIT(0, 0)
-  __Pyx_NAMESTR("_cdec.__pyx_scope_struct_16_todot"), /*tp_name*/
-  sizeof(struct __pyx_obj_5_cdec___pyx_scope_struct_16_todot), /*tp_basicsize*/
+  __Pyx_NAMESTR("_cdec.__pyx_scope_struct_18_todot"), /*tp_name*/
+  sizeof(struct __pyx_obj_5_cdec___pyx_scope_struct_18_todot), /*tp_basicsize*/
   0, /*tp_itemsize*/
-  __pyx_tp_dealloc_5_cdec___pyx_scope_struct_16_todot, /*tp_dealloc*/
+  __pyx_tp_dealloc_5_cdec___pyx_scope_struct_18_todot, /*tp_dealloc*/
   0, /*tp_print*/
   0, /*tp_getattr*/
   0, /*tp_setattr*/
@@ -19877,24 +23838,24 @@ static PyTypeObject __pyx_type_5_cdec___pyx_scope_struct_16_todot = {
   0, /*reserved*/
   #endif
   0, /*tp_repr*/
-  &__pyx_tp_as_number___pyx_scope_struct_16_todot, /*tp_as_number*/
-  &__pyx_tp_as_sequence___pyx_scope_struct_16_todot, /*tp_as_sequence*/
-  &__pyx_tp_as_mapping___pyx_scope_struct_16_todot, /*tp_as_mapping*/
+  &__pyx_tp_as_number___pyx_scope_struct_18_todot, /*tp_as_number*/
+  &__pyx_tp_as_sequence___pyx_scope_struct_18_todot, /*tp_as_sequence*/
+  &__pyx_tp_as_mapping___pyx_scope_struct_18_todot, /*tp_as_mapping*/
   0, /*tp_hash*/
   0, /*tp_call*/
   0, /*tp_str*/
   0, /*tp_getattro*/
   0, /*tp_setattro*/
-  &__pyx_tp_as_buffer___pyx_scope_struct_16_todot, /*tp_as_buffer*/
+  &__pyx_tp_as_buffer___pyx_scope_struct_18_todot, /*tp_as_buffer*/
   Py_TPFLAGS_DEFAULT|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_HAVE_GC, /*tp_flags*/
   0, /*tp_doc*/
-  __pyx_tp_traverse_5_cdec___pyx_scope_struct_16_todot, /*tp_traverse*/
-  __pyx_tp_clear_5_cdec___pyx_scope_struct_16_todot, /*tp_clear*/
+  __pyx_tp_traverse_5_cdec___pyx_scope_struct_18_todot, /*tp_traverse*/
+  __pyx_tp_clear_5_cdec___pyx_scope_struct_18_todot, /*tp_clear*/
   0, /*tp_richcompare*/
   0, /*tp_weaklistoffset*/
   0, /*tp_iter*/
   0, /*tp_iternext*/
-  __pyx_methods_5_cdec___pyx_scope_struct_16_todot, /*tp_methods*/
+  __pyx_methods_5_cdec___pyx_scope_struct_18_todot, /*tp_methods*/
   0, /*tp_members*/
   0, /*tp_getset*/
   0, /*tp_base*/
@@ -19904,7 +23865,7 @@ static PyTypeObject __pyx_type_5_cdec___pyx_scope_struct_16_todot = {
   0, /*tp_dictoffset*/
   0, /*tp_init*/
   0, /*tp_alloc*/
-  __pyx_tp_new_5_cdec___pyx_scope_struct_16_todot, /*tp_new*/
+  __pyx_tp_new_5_cdec___pyx_scope_struct_18_todot, /*tp_new*/
   0, /*tp_free*/
   0, /*tp_is_gc*/
   0, /*tp_bases*/
@@ -19918,11 +23879,11 @@ static PyTypeObject __pyx_type_5_cdec___pyx_scope_struct_16_todot = {
   #endif
 };
 
-static PyObject *__pyx_tp_new_5_cdec___pyx_scope_struct_17_lines(PyTypeObject *t, PyObject *a, PyObject *k) {
-  struct __pyx_obj_5_cdec___pyx_scope_struct_17_lines *p;
+static PyObject *__pyx_tp_new_5_cdec___pyx_scope_struct_19_lines(PyTypeObject *t, PyObject *a, PyObject *k) {
+  struct __pyx_obj_5_cdec___pyx_scope_struct_19_lines *p;
   PyObject *o = (*t->tp_alloc)(t, 0);
   if (!o) return 0;
-  p = ((struct __pyx_obj_5_cdec___pyx_scope_struct_17_lines *)o);
+  p = ((struct __pyx_obj_5_cdec___pyx_scope_struct_19_lines *)o);
   p->__pyx_outer_scope = 0;
   p->__pyx_v_delta = 0;
   p->__pyx_v_i = 0;
@@ -19933,8 +23894,8 @@ static PyObject *__pyx_tp_new_5_cdec___pyx_scope_struct_17_lines(PyTypeObject *t
   return o;
 }
 
-static void __pyx_tp_dealloc_5_cdec___pyx_scope_struct_17_lines(PyObject *o) {
-  struct __pyx_obj_5_cdec___pyx_scope_struct_17_lines *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_17_lines *)o;
+static void __pyx_tp_dealloc_5_cdec___pyx_scope_struct_19_lines(PyObject *o) {
+  struct __pyx_obj_5_cdec___pyx_scope_struct_19_lines *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_19_lines *)o;
   Py_XDECREF(((PyObject *)p->__pyx_outer_scope));
   Py_XDECREF(p->__pyx_v_delta);
   Py_XDECREF(p->__pyx_v_i);
@@ -19945,9 +23906,9 @@ static void __pyx_tp_dealloc_5_cdec___pyx_scope_struct_17_lines(PyObject *o) {
   (*Py_TYPE(o)->tp_free)(o);
 }
 
-static int __pyx_tp_traverse_5_cdec___pyx_scope_struct_17_lines(PyObject *o, visitproc v, void *a) {
+static int __pyx_tp_traverse_5_cdec___pyx_scope_struct_19_lines(PyObject *o, visitproc v, void *a) {
   int e;
-  struct __pyx_obj_5_cdec___pyx_scope_struct_17_lines *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_17_lines *)o;
+  struct __pyx_obj_5_cdec___pyx_scope_struct_19_lines *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_19_lines *)o;
   if (p->__pyx_outer_scope) {
     e = (*v)(((PyObject*)p->__pyx_outer_scope), a); if (e) return e;
   }
@@ -19972,11 +23933,11 @@ static int __pyx_tp_traverse_5_cdec___pyx_scope_struct_17_lines(PyObject *o, vis
   return 0;
 }
 
-static int __pyx_tp_clear_5_cdec___pyx_scope_struct_17_lines(PyObject *o) {
-  struct __pyx_obj_5_cdec___pyx_scope_struct_17_lines *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_17_lines *)o;
+static int __pyx_tp_clear_5_cdec___pyx_scope_struct_19_lines(PyObject *o) {
+  struct __pyx_obj_5_cdec___pyx_scope_struct_19_lines *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_19_lines *)o;
   PyObject* tmp;
   tmp = ((PyObject*)p->__pyx_outer_scope);
-  p->__pyx_outer_scope = ((struct __pyx_obj_5_cdec___pyx_scope_struct_16_todot *)Py_None); Py_INCREF(Py_None);
+  p->__pyx_outer_scope = ((struct __pyx_obj_5_cdec___pyx_scope_struct_18_todot *)Py_None); Py_INCREF(Py_None);
   Py_XDECREF(tmp);
   tmp = ((PyObject*)p->__pyx_v_delta);
   p->__pyx_v_delta = Py_None; Py_INCREF(Py_None);
@@ -19999,11 +23960,11 @@ static int __pyx_tp_clear_5_cdec___pyx_scope_struct_17_lines(PyObject *o) {
   return 0;
 }
 
-static PyMethodDef __pyx_methods_5_cdec___pyx_scope_struct_17_lines[] = {
+static PyMethodDef __pyx_methods_5_cdec___pyx_scope_struct_19_lines[] = {
   {0, 0, 0, 0}
 };
 
-static PyNumberMethods __pyx_tp_as_number___pyx_scope_struct_17_lines = {
+static PyNumberMethods __pyx_tp_as_number___pyx_scope_struct_19_lines = {
   0, /*nb_add*/
   0, /*nb_subtract*/
   0, /*nb_multiply*/
@@ -20061,7 +24022,7 @@ static PyNumberMethods __pyx_tp_as_number___pyx_scope_struct_17_lines = {
   #endif
 };
 
-static PySequenceMethods __pyx_tp_as_sequence___pyx_scope_struct_17_lines = {
+static PySequenceMethods __pyx_tp_as_sequence___pyx_scope_struct_19_lines = {
   0, /*sq_length*/
   0, /*sq_concat*/
   0, /*sq_repeat*/
@@ -20074,13 +24035,13 @@ static PySequenceMethods __pyx_tp_as_sequence___pyx_scope_struct_17_lines = {
   0, /*sq_inplace_repeat*/
 };
 
-static PyMappingMethods __pyx_tp_as_mapping___pyx_scope_struct_17_lines = {
+static PyMappingMethods __pyx_tp_as_mapping___pyx_scope_struct_19_lines = {
   0, /*mp_length*/
   0, /*mp_subscript*/
   0, /*mp_ass_subscript*/
 };
 
-static PyBufferProcs __pyx_tp_as_buffer___pyx_scope_struct_17_lines = {
+static PyBufferProcs __pyx_tp_as_buffer___pyx_scope_struct_19_lines = {
   #if PY_MAJOR_VERSION < 3
   0, /*bf_getreadbuffer*/
   #endif
@@ -20101,12 +24062,12 @@ static PyBufferProcs __pyx_tp_as_buffer___pyx_scope_struct_17_lines = {
   #endif
 };
 
-static PyTypeObject __pyx_type_5_cdec___pyx_scope_struct_17_lines = {
+static PyTypeObject __pyx_type_5_cdec___pyx_scope_struct_19_lines = {
   PyVarObject_HEAD_INIT(0, 0)
-  __Pyx_NAMESTR("_cdec.__pyx_scope_struct_17_lines"), /*tp_name*/
-  sizeof(struct __pyx_obj_5_cdec___pyx_scope_struct_17_lines), /*tp_basicsize*/
+  __Pyx_NAMESTR("_cdec.__pyx_scope_struct_19_lines"), /*tp_name*/
+  sizeof(struct __pyx_obj_5_cdec___pyx_scope_struct_19_lines), /*tp_basicsize*/
   0, /*tp_itemsize*/
-  __pyx_tp_dealloc_5_cdec___pyx_scope_struct_17_lines, /*tp_dealloc*/
+  __pyx_tp_dealloc_5_cdec___pyx_scope_struct_19_lines, /*tp_dealloc*/
   0, /*tp_print*/
   0, /*tp_getattr*/
   0, /*tp_setattr*/
@@ -20116,24 +24077,24 @@ static PyTypeObject __pyx_type_5_cdec___pyx_scope_struct_17_lines = {
   0, /*reserved*/
   #endif
   0, /*tp_repr*/
-  &__pyx_tp_as_number___pyx_scope_struct_17_lines, /*tp_as_number*/
-  &__pyx_tp_as_sequence___pyx_scope_struct_17_lines, /*tp_as_sequence*/
-  &__pyx_tp_as_mapping___pyx_scope_struct_17_lines, /*tp_as_mapping*/
+  &__pyx_tp_as_number___pyx_scope_struct_19_lines, /*tp_as_number*/
+  &__pyx_tp_as_sequence___pyx_scope_struct_19_lines, /*tp_as_sequence*/
+  &__pyx_tp_as_mapping___pyx_scope_struct_19_lines, /*tp_as_mapping*/
   0, /*tp_hash*/
   0, /*tp_call*/
   0, /*tp_str*/
   0, /*tp_getattro*/
   0, /*tp_setattro*/
-  &__pyx_tp_as_buffer___pyx_scope_struct_17_lines, /*tp_as_buffer*/
+  &__pyx_tp_as_buffer___pyx_scope_struct_19_lines, /*tp_as_buffer*/
   Py_TPFLAGS_DEFAULT|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_HAVE_GC, /*tp_flags*/
   0, /*tp_doc*/
-  __pyx_tp_traverse_5_cdec___pyx_scope_struct_17_lines, /*tp_traverse*/
-  __pyx_tp_clear_5_cdec___pyx_scope_struct_17_lines, /*tp_clear*/
+  __pyx_tp_traverse_5_cdec___pyx_scope_struct_19_lines, /*tp_traverse*/
+  __pyx_tp_clear_5_cdec___pyx_scope_struct_19_lines, /*tp_clear*/
   0, /*tp_richcompare*/
   0, /*tp_weaklistoffset*/
   0, /*tp_iter*/
   0, /*tp_iternext*/
-  __pyx_methods_5_cdec___pyx_scope_struct_17_lines, /*tp_methods*/
+  __pyx_methods_5_cdec___pyx_scope_struct_19_lines, /*tp_methods*/
   0, /*tp_members*/
   0, /*tp_getset*/
   0, /*tp_base*/
@@ -20143,7 +24104,7 @@ static PyTypeObject __pyx_type_5_cdec___pyx_scope_struct_17_lines = {
   0, /*tp_dictoffset*/
   0, /*tp_init*/
   0, /*tp_alloc*/
-  __pyx_tp_new_5_cdec___pyx_scope_struct_17_lines, /*tp_new*/
+  __pyx_tp_new_5_cdec___pyx_scope_struct_19_lines, /*tp_new*/
   0, /*tp_free*/
   0, /*tp_is_gc*/
   0, /*tp_bases*/
@@ -20157,28 +24118,28 @@ static PyTypeObject __pyx_type_5_cdec___pyx_scope_struct_17_lines = {
   #endif
 };
 
-static PyObject *__pyx_tp_new_5_cdec___pyx_scope_struct_18___iter__(PyTypeObject *t, PyObject *a, PyObject *k) {
-  struct __pyx_obj_5_cdec___pyx_scope_struct_18___iter__ *p;
+static PyObject *__pyx_tp_new_5_cdec___pyx_scope_struct_20___iter__(PyTypeObject *t, PyObject *a, PyObject *k) {
+  struct __pyx_obj_5_cdec___pyx_scope_struct_20___iter__ *p;
   PyObject *o = (*t->tp_alloc)(t, 0);
   if (!o) return 0;
-  p = ((struct __pyx_obj_5_cdec___pyx_scope_struct_18___iter__ *)o);
+  p = ((struct __pyx_obj_5_cdec___pyx_scope_struct_20___iter__ *)o);
   p->__pyx_v_i = 0;
   p->__pyx_v_self = 0;
   p->__pyx_t_1 = 0;
   return o;
 }
 
-static void __pyx_tp_dealloc_5_cdec___pyx_scope_struct_18___iter__(PyObject *o) {
-  struct __pyx_obj_5_cdec___pyx_scope_struct_18___iter__ *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_18___iter__ *)o;
+static void __pyx_tp_dealloc_5_cdec___pyx_scope_struct_20___iter__(PyObject *o) {
+  struct __pyx_obj_5_cdec___pyx_scope_struct_20___iter__ *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_20___iter__ *)o;
   Py_XDECREF(p->__pyx_v_i);
   Py_XDECREF(((PyObject *)p->__pyx_v_self));
   Py_XDECREF(p->__pyx_t_1);
   (*Py_TYPE(o)->tp_free)(o);
 }
 
-static int __pyx_tp_traverse_5_cdec___pyx_scope_struct_18___iter__(PyObject *o, visitproc v, void *a) {
+static int __pyx_tp_traverse_5_cdec___pyx_scope_struct_20___iter__(PyObject *o, visitproc v, void *a) {
   int e;
-  struct __pyx_obj_5_cdec___pyx_scope_struct_18___iter__ *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_18___iter__ *)o;
+  struct __pyx_obj_5_cdec___pyx_scope_struct_20___iter__ *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_20___iter__ *)o;
   if (p->__pyx_v_i) {
     e = (*v)(p->__pyx_v_i, a); if (e) return e;
   }
@@ -20191,8 +24152,8 @@ static int __pyx_tp_traverse_5_cdec___pyx_scope_struct_18___iter__(PyObject *o,
   return 0;
 }
 
-static int __pyx_tp_clear_5_cdec___pyx_scope_struct_18___iter__(PyObject *o) {
-  struct __pyx_obj_5_cdec___pyx_scope_struct_18___iter__ *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_18___iter__ *)o;
+static int __pyx_tp_clear_5_cdec___pyx_scope_struct_20___iter__(PyObject *o) {
+  struct __pyx_obj_5_cdec___pyx_scope_struct_20___iter__ *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_20___iter__ *)o;
   PyObject* tmp;
   tmp = ((PyObject*)p->__pyx_v_i);
   p->__pyx_v_i = Py_None; Py_INCREF(Py_None);
@@ -20206,11 +24167,11 @@ static int __pyx_tp_clear_5_cdec___pyx_scope_struct_18___iter__(PyObject *o) {
   return 0;
 }
 
-static PyMethodDef __pyx_methods_5_cdec___pyx_scope_struct_18___iter__[] = {
+static PyMethodDef __pyx_methods_5_cdec___pyx_scope_struct_20___iter__[] = {
   {0, 0, 0, 0}
 };
 
-static PyNumberMethods __pyx_tp_as_number___pyx_scope_struct_18___iter__ = {
+static PyNumberMethods __pyx_tp_as_number___pyx_scope_struct_20___iter__ = {
   0, /*nb_add*/
   0, /*nb_subtract*/
   0, /*nb_multiply*/
@@ -20268,7 +24229,7 @@ static PyNumberMethods __pyx_tp_as_number___pyx_scope_struct_18___iter__ = {
   #endif
 };
 
-static PySequenceMethods __pyx_tp_as_sequence___pyx_scope_struct_18___iter__ = {
+static PySequenceMethods __pyx_tp_as_sequence___pyx_scope_struct_20___iter__ = {
   0, /*sq_length*/
   0, /*sq_concat*/
   0, /*sq_repeat*/
@@ -20281,13 +24242,13 @@ static PySequenceMethods __pyx_tp_as_sequence___pyx_scope_struct_18___iter__ = {
   0, /*sq_inplace_repeat*/
 };
 
-static PyMappingMethods __pyx_tp_as_mapping___pyx_scope_struct_18___iter__ = {
+static PyMappingMethods __pyx_tp_as_mapping___pyx_scope_struct_20___iter__ = {
   0, /*mp_length*/
   0, /*mp_subscript*/
   0, /*mp_ass_subscript*/
 };
 
-static PyBufferProcs __pyx_tp_as_buffer___pyx_scope_struct_18___iter__ = {
+static PyBufferProcs __pyx_tp_as_buffer___pyx_scope_struct_20___iter__ = {
   #if PY_MAJOR_VERSION < 3
   0, /*bf_getreadbuffer*/
   #endif
@@ -20308,12 +24269,12 @@ static PyBufferProcs __pyx_tp_as_buffer___pyx_scope_struct_18___iter__ = {
   #endif
 };
 
-static PyTypeObject __pyx_type_5_cdec___pyx_scope_struct_18___iter__ = {
+static PyTypeObject __pyx_type_5_cdec___pyx_scope_struct_20___iter__ = {
   PyVarObject_HEAD_INIT(0, 0)
-  __Pyx_NAMESTR("_cdec.__pyx_scope_struct_18___iter__"), /*tp_name*/
-  sizeof(struct __pyx_obj_5_cdec___pyx_scope_struct_18___iter__), /*tp_basicsize*/
+  __Pyx_NAMESTR("_cdec.__pyx_scope_struct_20___iter__"), /*tp_name*/
+  sizeof(struct __pyx_obj_5_cdec___pyx_scope_struct_20___iter__), /*tp_basicsize*/
   0, /*tp_itemsize*/
-  __pyx_tp_dealloc_5_cdec___pyx_scope_struct_18___iter__, /*tp_dealloc*/
+  __pyx_tp_dealloc_5_cdec___pyx_scope_struct_20___iter__, /*tp_dealloc*/
   0, /*tp_print*/
   0, /*tp_getattr*/
   0, /*tp_setattr*/
@@ -20323,24 +24284,24 @@ static PyTypeObject __pyx_type_5_cdec___pyx_scope_struct_18___iter__ = {
   0, /*reserved*/
   #endif
   0, /*tp_repr*/
-  &__pyx_tp_as_number___pyx_scope_struct_18___iter__, /*tp_as_number*/
-  &__pyx_tp_as_sequence___pyx_scope_struct_18___iter__, /*tp_as_sequence*/
-  &__pyx_tp_as_mapping___pyx_scope_struct_18___iter__, /*tp_as_mapping*/
+  &__pyx_tp_as_number___pyx_scope_struct_20___iter__, /*tp_as_number*/
+  &__pyx_tp_as_sequence___pyx_scope_struct_20___iter__, /*tp_as_sequence*/
+  &__pyx_tp_as_mapping___pyx_scope_struct_20___iter__, /*tp_as_mapping*/
   0, /*tp_hash*/
   0, /*tp_call*/
   0, /*tp_str*/
   0, /*tp_getattro*/
   0, /*tp_setattro*/
-  &__pyx_tp_as_buffer___pyx_scope_struct_18___iter__, /*tp_as_buffer*/
+  &__pyx_tp_as_buffer___pyx_scope_struct_20___iter__, /*tp_as_buffer*/
   Py_TPFLAGS_DEFAULT|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_HAVE_GC, /*tp_flags*/
   0, /*tp_doc*/
-  __pyx_tp_traverse_5_cdec___pyx_scope_struct_18___iter__, /*tp_traverse*/
-  __pyx_tp_clear_5_cdec___pyx_scope_struct_18___iter__, /*tp_clear*/
+  __pyx_tp_traverse_5_cdec___pyx_scope_struct_20___iter__, /*tp_traverse*/
+  __pyx_tp_clear_5_cdec___pyx_scope_struct_20___iter__, /*tp_clear*/
   0, /*tp_richcompare*/
   0, /*tp_weaklistoffset*/
   0, /*tp_iter*/
   0, /*tp_iternext*/
-  __pyx_methods_5_cdec___pyx_scope_struct_18___iter__, /*tp_methods*/
+  __pyx_methods_5_cdec___pyx_scope_struct_20___iter__, /*tp_methods*/
   0, /*tp_members*/
   0, /*tp_getset*/
   0, /*tp_base*/
@@ -20350,7 +24311,7 @@ static PyTypeObject __pyx_type_5_cdec___pyx_scope_struct_18___iter__ = {
   0, /*tp_dictoffset*/
   0, /*tp_init*/
   0, /*tp_alloc*/
-  __pyx_tp_new_5_cdec___pyx_scope_struct_18___iter__, /*tp_new*/
+  __pyx_tp_new_5_cdec___pyx_scope_struct_20___iter__, /*tp_new*/
   0, /*tp_free*/
   0, /*tp_is_gc*/
   0, /*tp_bases*/
@@ -20364,32 +24325,32 @@ static PyTypeObject __pyx_type_5_cdec___pyx_scope_struct_18___iter__ = {
   #endif
 };
 
-static PyObject *__pyx_tp_new_5_cdec___pyx_scope_struct_19___iter__(PyTypeObject *t, PyObject *a, PyObject *k) {
-  struct __pyx_obj_5_cdec___pyx_scope_struct_19___iter__ *p;
+static PyObject *__pyx_tp_new_5_cdec___pyx_scope_struct_21___iter__(PyTypeObject *t, PyObject *a, PyObject *k) {
+  struct __pyx_obj_5_cdec___pyx_scope_struct_21___iter__ *p;
   PyObject *o = (*t->tp_alloc)(t, 0);
   if (!o) return 0;
-  p = ((struct __pyx_obj_5_cdec___pyx_scope_struct_19___iter__ *)o);
+  p = ((struct __pyx_obj_5_cdec___pyx_scope_struct_21___iter__ *)o);
   p->__pyx_v_self = 0;
   return o;
 }
 
-static void __pyx_tp_dealloc_5_cdec___pyx_scope_struct_19___iter__(PyObject *o) {
-  struct __pyx_obj_5_cdec___pyx_scope_struct_19___iter__ *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_19___iter__ *)o;
+static void __pyx_tp_dealloc_5_cdec___pyx_scope_struct_21___iter__(PyObject *o) {
+  struct __pyx_obj_5_cdec___pyx_scope_struct_21___iter__ *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_21___iter__ *)o;
   Py_XDECREF(((PyObject *)p->__pyx_v_self));
   (*Py_TYPE(o)->tp_free)(o);
 }
 
-static int __pyx_tp_traverse_5_cdec___pyx_scope_struct_19___iter__(PyObject *o, visitproc v, void *a) {
+static int __pyx_tp_traverse_5_cdec___pyx_scope_struct_21___iter__(PyObject *o, visitproc v, void *a) {
   int e;
-  struct __pyx_obj_5_cdec___pyx_scope_struct_19___iter__ *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_19___iter__ *)o;
+  struct __pyx_obj_5_cdec___pyx_scope_struct_21___iter__ *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_21___iter__ *)o;
   if (p->__pyx_v_self) {
     e = (*v)(((PyObject*)p->__pyx_v_self), a); if (e) return e;
   }
   return 0;
 }
 
-static int __pyx_tp_clear_5_cdec___pyx_scope_struct_19___iter__(PyObject *o) {
-  struct __pyx_obj_5_cdec___pyx_scope_struct_19___iter__ *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_19___iter__ *)o;
+static int __pyx_tp_clear_5_cdec___pyx_scope_struct_21___iter__(PyObject *o) {
+  struct __pyx_obj_5_cdec___pyx_scope_struct_21___iter__ *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_21___iter__ *)o;
   PyObject* tmp;
   tmp = ((PyObject*)p->__pyx_v_self);
   p->__pyx_v_self = ((struct __pyx_obj_5_cdec_CandidateSet *)Py_None); Py_INCREF(Py_None);
@@ -20397,11 +24358,11 @@ static int __pyx_tp_clear_5_cdec___pyx_scope_struct_19___iter__(PyObject *o) {
   return 0;
 }
 
-static PyMethodDef __pyx_methods_5_cdec___pyx_scope_struct_19___iter__[] = {
+static PyMethodDef __pyx_methods_5_cdec___pyx_scope_struct_21___iter__[] = {
   {0, 0, 0, 0}
 };
 
-static PyNumberMethods __pyx_tp_as_number___pyx_scope_struct_19___iter__ = {
+static PyNumberMethods __pyx_tp_as_number___pyx_scope_struct_21___iter__ = {
   0, /*nb_add*/
   0, /*nb_subtract*/
   0, /*nb_multiply*/
@@ -20459,7 +24420,7 @@ static PyNumberMethods __pyx_tp_as_number___pyx_scope_struct_19___iter__ = {
   #endif
 };
 
-static PySequenceMethods __pyx_tp_as_sequence___pyx_scope_struct_19___iter__ = {
+static PySequenceMethods __pyx_tp_as_sequence___pyx_scope_struct_21___iter__ = {
   0, /*sq_length*/
   0, /*sq_concat*/
   0, /*sq_repeat*/
@@ -20472,13 +24433,13 @@ static PySequenceMethods __pyx_tp_as_sequence___pyx_scope_struct_19___iter__ = {
   0, /*sq_inplace_repeat*/
 };
 
-static PyMappingMethods __pyx_tp_as_mapping___pyx_scope_struct_19___iter__ = {
+static PyMappingMethods __pyx_tp_as_mapping___pyx_scope_struct_21___iter__ = {
   0, /*mp_length*/
   0, /*mp_subscript*/
   0, /*mp_ass_subscript*/
 };
 
-static PyBufferProcs __pyx_tp_as_buffer___pyx_scope_struct_19___iter__ = {
+static PyBufferProcs __pyx_tp_as_buffer___pyx_scope_struct_21___iter__ = {
   #if PY_MAJOR_VERSION < 3
   0, /*bf_getreadbuffer*/
   #endif
@@ -20499,12 +24460,12 @@ static PyBufferProcs __pyx_tp_as_buffer___pyx_scope_struct_19___iter__ = {
   #endif
 };
 
-static PyTypeObject __pyx_type_5_cdec___pyx_scope_struct_19___iter__ = {
+static PyTypeObject __pyx_type_5_cdec___pyx_scope_struct_21___iter__ = {
   PyVarObject_HEAD_INIT(0, 0)
-  __Pyx_NAMESTR("_cdec.__pyx_scope_struct_19___iter__"), /*tp_name*/
-  sizeof(struct __pyx_obj_5_cdec___pyx_scope_struct_19___iter__), /*tp_basicsize*/
+  __Pyx_NAMESTR("_cdec.__pyx_scope_struct_21___iter__"), /*tp_name*/
+  sizeof(struct __pyx_obj_5_cdec___pyx_scope_struct_21___iter__), /*tp_basicsize*/
   0, /*tp_itemsize*/
-  __pyx_tp_dealloc_5_cdec___pyx_scope_struct_19___iter__, /*tp_dealloc*/
+  __pyx_tp_dealloc_5_cdec___pyx_scope_struct_21___iter__, /*tp_dealloc*/
   0, /*tp_print*/
   0, /*tp_getattr*/
   0, /*tp_setattr*/
@@ -20514,24 +24475,24 @@ static PyTypeObject __pyx_type_5_cdec___pyx_scope_struct_19___iter__ = {
   0, /*reserved*/
   #endif
   0, /*tp_repr*/
-  &__pyx_tp_as_number___pyx_scope_struct_19___iter__, /*tp_as_number*/
-  &__pyx_tp_as_sequence___pyx_scope_struct_19___iter__, /*tp_as_sequence*/
-  &__pyx_tp_as_mapping___pyx_scope_struct_19___iter__, /*tp_as_mapping*/
+  &__pyx_tp_as_number___pyx_scope_struct_21___iter__, /*tp_as_number*/
+  &__pyx_tp_as_sequence___pyx_scope_struct_21___iter__, /*tp_as_sequence*/
+  &__pyx_tp_as_mapping___pyx_scope_struct_21___iter__, /*tp_as_mapping*/
   0, /*tp_hash*/
   0, /*tp_call*/
   0, /*tp_str*/
   0, /*tp_getattro*/
   0, /*tp_setattro*/
-  &__pyx_tp_as_buffer___pyx_scope_struct_19___iter__, /*tp_as_buffer*/
+  &__pyx_tp_as_buffer___pyx_scope_struct_21___iter__, /*tp_as_buffer*/
   Py_TPFLAGS_DEFAULT|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_HAVE_GC, /*tp_flags*/
   0, /*tp_doc*/
-  __pyx_tp_traverse_5_cdec___pyx_scope_struct_19___iter__, /*tp_traverse*/
-  __pyx_tp_clear_5_cdec___pyx_scope_struct_19___iter__, /*tp_clear*/
+  __pyx_tp_traverse_5_cdec___pyx_scope_struct_21___iter__, /*tp_traverse*/
+  __pyx_tp_clear_5_cdec___pyx_scope_struct_21___iter__, /*tp_clear*/
   0, /*tp_richcompare*/
   0, /*tp_weaklistoffset*/
   0, /*tp_iter*/
   0, /*tp_iternext*/
-  __pyx_methods_5_cdec___pyx_scope_struct_19___iter__, /*tp_methods*/
+  __pyx_methods_5_cdec___pyx_scope_struct_21___iter__, /*tp_methods*/
   0, /*tp_members*/
   0, /*tp_getset*/
   0, /*tp_base*/
@@ -20541,7 +24502,7 @@ static PyTypeObject __pyx_type_5_cdec___pyx_scope_struct_19___iter__ = {
   0, /*tp_dictoffset*/
   0, /*tp_init*/
   0, /*tp_alloc*/
-  __pyx_tp_new_5_cdec___pyx_scope_struct_19___iter__, /*tp_new*/
+  __pyx_tp_new_5_cdec___pyx_scope_struct_21___iter__, /*tp_new*/
   0, /*tp_free*/
   0, /*tp_is_gc*/
   0, /*tp_bases*/
@@ -20555,11 +24516,11 @@ static PyTypeObject __pyx_type_5_cdec___pyx_scope_struct_19___iter__ = {
   #endif
 };
 
-static PyObject *__pyx_tp_new_5_cdec___pyx_scope_struct_20__make_config(PyTypeObject *t, PyObject *a, PyObject *k) {
-  struct __pyx_obj_5_cdec___pyx_scope_struct_20__make_config *p;
+static PyObject *__pyx_tp_new_5_cdec___pyx_scope_struct_22__make_config(PyTypeObject *t, PyObject *a, PyObject *k) {
+  struct __pyx_obj_5_cdec___pyx_scope_struct_22__make_config *p;
   PyObject *o = (*t->tp_alloc)(t, 0);
   if (!o) return 0;
-  p = ((struct __pyx_obj_5_cdec___pyx_scope_struct_20__make_config *)o);
+  p = ((struct __pyx_obj_5_cdec___pyx_scope_struct_22__make_config *)o);
   p->__pyx_v_config = 0;
   p->__pyx_v_info = 0;
   p->__pyx_v_key = 0;
@@ -20570,8 +24531,8 @@ static PyObject *__pyx_tp_new_5_cdec___pyx_scope_struct_20__make_config(PyTypeOb
   return o;
 }
 
-static void __pyx_tp_dealloc_5_cdec___pyx_scope_struct_20__make_config(PyObject *o) {
-  struct __pyx_obj_5_cdec___pyx_scope_struct_20__make_config *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_20__make_config *)o;
+static void __pyx_tp_dealloc_5_cdec___pyx_scope_struct_22__make_config(PyObject *o) {
+  struct __pyx_obj_5_cdec___pyx_scope_struct_22__make_config *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_22__make_config *)o;
   Py_XDECREF(p->__pyx_v_config);
   Py_XDECREF(p->__pyx_v_info);
   Py_XDECREF(p->__pyx_v_key);
@@ -20582,9 +24543,9 @@ static void __pyx_tp_dealloc_5_cdec___pyx_scope_struct_20__make_config(PyObject
   (*Py_TYPE(o)->tp_free)(o);
 }
 
-static int __pyx_tp_traverse_5_cdec___pyx_scope_struct_20__make_config(PyObject *o, visitproc v, void *a) {
+static int __pyx_tp_traverse_5_cdec___pyx_scope_struct_22__make_config(PyObject *o, visitproc v, void *a) {
   int e;
-  struct __pyx_obj_5_cdec___pyx_scope_struct_20__make_config *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_20__make_config *)o;
+  struct __pyx_obj_5_cdec___pyx_scope_struct_22__make_config *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_22__make_config *)o;
   if (p->__pyx_v_config) {
     e = (*v)(p->__pyx_v_config, a); if (e) return e;
   }
@@ -20609,8 +24570,8 @@ static int __pyx_tp_traverse_5_cdec___pyx_scope_struct_20__make_config(PyObject
   return 0;
 }
 
-static int __pyx_tp_clear_5_cdec___pyx_scope_struct_20__make_config(PyObject *o) {
-  struct __pyx_obj_5_cdec___pyx_scope_struct_20__make_config *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_20__make_config *)o;
+static int __pyx_tp_clear_5_cdec___pyx_scope_struct_22__make_config(PyObject *o) {
+  struct __pyx_obj_5_cdec___pyx_scope_struct_22__make_config *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_22__make_config *)o;
   PyObject* tmp;
   tmp = ((PyObject*)p->__pyx_v_config);
   p->__pyx_v_config = Py_None; Py_INCREF(Py_None);
@@ -20636,11 +24597,11 @@ static int __pyx_tp_clear_5_cdec___pyx_scope_struct_20__make_config(PyObject *o)
   return 0;
 }
 
-static PyMethodDef __pyx_methods_5_cdec___pyx_scope_struct_20__make_config[] = {
+static PyMethodDef __pyx_methods_5_cdec___pyx_scope_struct_22__make_config[] = {
   {0, 0, 0, 0}
 };
 
-static PyNumberMethods __pyx_tp_as_number___pyx_scope_struct_20__make_config = {
+static PyNumberMethods __pyx_tp_as_number___pyx_scope_struct_22__make_config = {
   0, /*nb_add*/
   0, /*nb_subtract*/
   0, /*nb_multiply*/
@@ -20698,7 +24659,7 @@ static PyNumberMethods __pyx_tp_as_number___pyx_scope_struct_20__make_config = {
   #endif
 };
 
-static PySequenceMethods __pyx_tp_as_sequence___pyx_scope_struct_20__make_config = {
+static PySequenceMethods __pyx_tp_as_sequence___pyx_scope_struct_22__make_config = {
   0, /*sq_length*/
   0, /*sq_concat*/
   0, /*sq_repeat*/
@@ -20711,13 +24672,13 @@ static PySequenceMethods __pyx_tp_as_sequence___pyx_scope_struct_20__make_config
   0, /*sq_inplace_repeat*/
 };
 
-static PyMappingMethods __pyx_tp_as_mapping___pyx_scope_struct_20__make_config = {
+static PyMappingMethods __pyx_tp_as_mapping___pyx_scope_struct_22__make_config = {
   0, /*mp_length*/
   0, /*mp_subscript*/
   0, /*mp_ass_subscript*/
 };
 
-static PyBufferProcs __pyx_tp_as_buffer___pyx_scope_struct_20__make_config = {
+static PyBufferProcs __pyx_tp_as_buffer___pyx_scope_struct_22__make_config = {
   #if PY_MAJOR_VERSION < 3
   0, /*bf_getreadbuffer*/
   #endif
@@ -20738,12 +24699,12 @@ static PyBufferProcs __pyx_tp_as_buffer___pyx_scope_struct_20__make_config = {
   #endif
 };
 
-static PyTypeObject __pyx_type_5_cdec___pyx_scope_struct_20__make_config = {
+static PyTypeObject __pyx_type_5_cdec___pyx_scope_struct_22__make_config = {
   PyVarObject_HEAD_INIT(0, 0)
-  __Pyx_NAMESTR("_cdec.__pyx_scope_struct_20__make_config"), /*tp_name*/
-  sizeof(struct __pyx_obj_5_cdec___pyx_scope_struct_20__make_config), /*tp_basicsize*/
+  __Pyx_NAMESTR("_cdec.__pyx_scope_struct_22__make_config"), /*tp_name*/
+  sizeof(struct __pyx_obj_5_cdec___pyx_scope_struct_22__make_config), /*tp_basicsize*/
   0, /*tp_itemsize*/
-  __pyx_tp_dealloc_5_cdec___pyx_scope_struct_20__make_config, /*tp_dealloc*/
+  __pyx_tp_dealloc_5_cdec___pyx_scope_struct_22__make_config, /*tp_dealloc*/
   0, /*tp_print*/
   0, /*tp_getattr*/
   0, /*tp_setattr*/
@@ -20753,24 +24714,24 @@ static PyTypeObject __pyx_type_5_cdec___pyx_scope_struct_20__make_config = {
   0, /*reserved*/
   #endif
   0, /*tp_repr*/
-  &__pyx_tp_as_number___pyx_scope_struct_20__make_config, /*tp_as_number*/
-  &__pyx_tp_as_sequence___pyx_scope_struct_20__make_config, /*tp_as_sequence*/
-  &__pyx_tp_as_mapping___pyx_scope_struct_20__make_config, /*tp_as_mapping*/
+  &__pyx_tp_as_number___pyx_scope_struct_22__make_config, /*tp_as_number*/
+  &__pyx_tp_as_sequence___pyx_scope_struct_22__make_config, /*tp_as_sequence*/
+  &__pyx_tp_as_mapping___pyx_scope_struct_22__make_config, /*tp_as_mapping*/
   0, /*tp_hash*/
   0, /*tp_call*/
   0, /*tp_str*/
   0, /*tp_getattro*/
   0, /*tp_setattro*/
-  &__pyx_tp_as_buffer___pyx_scope_struct_20__make_config, /*tp_as_buffer*/
+  &__pyx_tp_as_buffer___pyx_scope_struct_22__make_config, /*tp_as_buffer*/
   Py_TPFLAGS_DEFAULT|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_HAVE_GC, /*tp_flags*/
   0, /*tp_doc*/
-  __pyx_tp_traverse_5_cdec___pyx_scope_struct_20__make_config, /*tp_traverse*/
-  __pyx_tp_clear_5_cdec___pyx_scope_struct_20__make_config, /*tp_clear*/
+  __pyx_tp_traverse_5_cdec___pyx_scope_struct_22__make_config, /*tp_traverse*/
+  __pyx_tp_clear_5_cdec___pyx_scope_struct_22__make_config, /*tp_clear*/
   0, /*tp_richcompare*/
   0, /*tp_weaklistoffset*/
   0, /*tp_iter*/
   0, /*tp_iternext*/
-  __pyx_methods_5_cdec___pyx_scope_struct_20__make_config, /*tp_methods*/
+  __pyx_methods_5_cdec___pyx_scope_struct_22__make_config, /*tp_methods*/
   0, /*tp_members*/
   0, /*tp_getset*/
   0, /*tp_base*/
@@ -20780,7 +24741,7 @@ static PyTypeObject __pyx_type_5_cdec___pyx_scope_struct_20__make_config = {
   0, /*tp_dictoffset*/
   0, /*tp_init*/
   0, /*tp_alloc*/
-  __pyx_tp_new_5_cdec___pyx_scope_struct_20__make_config, /*tp_new*/
+  __pyx_tp_new_5_cdec___pyx_scope_struct_22__make_config, /*tp_new*/
   0, /*tp_free*/
   0, /*tp_is_gc*/
   0, /*tp_bases*/
@@ -20794,32 +24755,32 @@ static PyTypeObject __pyx_type_5_cdec___pyx_scope_struct_20__make_config = {
   #endif
 };
 
-static PyObject *__pyx_tp_new_5_cdec___pyx_scope_struct_21___cinit__(PyTypeObject *t, PyObject *a, PyObject *k) {
-  struct __pyx_obj_5_cdec___pyx_scope_struct_21___cinit__ *p;
+static PyObject *__pyx_tp_new_5_cdec___pyx_scope_struct_23___cinit__(PyTypeObject *t, PyObject *a, PyObject *k) {
+  struct __pyx_obj_5_cdec___pyx_scope_struct_23___cinit__ *p;
   PyObject *o = (*t->tp_alloc)(t, 0);
   if (!o) return 0;
-  p = ((struct __pyx_obj_5_cdec___pyx_scope_struct_21___cinit__ *)o);
+  p = ((struct __pyx_obj_5_cdec___pyx_scope_struct_23___cinit__ *)o);
   p->__pyx_v_config = 0;
   return o;
 }
 
-static void __pyx_tp_dealloc_5_cdec___pyx_scope_struct_21___cinit__(PyObject *o) {
-  struct __pyx_obj_5_cdec___pyx_scope_struct_21___cinit__ *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_21___cinit__ *)o;
+static void __pyx_tp_dealloc_5_cdec___pyx_scope_struct_23___cinit__(PyObject *o) {
+  struct __pyx_obj_5_cdec___pyx_scope_struct_23___cinit__ *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_23___cinit__ *)o;
   Py_XDECREF(p->__pyx_v_config);
   (*Py_TYPE(o)->tp_free)(o);
 }
 
-static int __pyx_tp_traverse_5_cdec___pyx_scope_struct_21___cinit__(PyObject *o, visitproc v, void *a) {
+static int __pyx_tp_traverse_5_cdec___pyx_scope_struct_23___cinit__(PyObject *o, visitproc v, void *a) {
   int e;
-  struct __pyx_obj_5_cdec___pyx_scope_struct_21___cinit__ *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_21___cinit__ *)o;
+  struct __pyx_obj_5_cdec___pyx_scope_struct_23___cinit__ *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_23___cinit__ *)o;
   if (p->__pyx_v_config) {
     e = (*v)(p->__pyx_v_config, a); if (e) return e;
   }
   return 0;
 }
 
-static int __pyx_tp_clear_5_cdec___pyx_scope_struct_21___cinit__(PyObject *o) {
-  struct __pyx_obj_5_cdec___pyx_scope_struct_21___cinit__ *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_21___cinit__ *)o;
+static int __pyx_tp_clear_5_cdec___pyx_scope_struct_23___cinit__(PyObject *o) {
+  struct __pyx_obj_5_cdec___pyx_scope_struct_23___cinit__ *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_23___cinit__ *)o;
   PyObject* tmp;
   tmp = ((PyObject*)p->__pyx_v_config);
   p->__pyx_v_config = Py_None; Py_INCREF(Py_None);
@@ -20827,11 +24788,11 @@ static int __pyx_tp_clear_5_cdec___pyx_scope_struct_21___cinit__(PyObject *o) {
   return 0;
 }
 
-static PyMethodDef __pyx_methods_5_cdec___pyx_scope_struct_21___cinit__[] = {
+static PyMethodDef __pyx_methods_5_cdec___pyx_scope_struct_23___cinit__[] = {
   {0, 0, 0, 0}
 };
 
-static PyNumberMethods __pyx_tp_as_number___pyx_scope_struct_21___cinit__ = {
+static PyNumberMethods __pyx_tp_as_number___pyx_scope_struct_23___cinit__ = {
   0, /*nb_add*/
   0, /*nb_subtract*/
   0, /*nb_multiply*/
@@ -20889,7 +24850,7 @@ static PyNumberMethods __pyx_tp_as_number___pyx_scope_struct_21___cinit__ = {
   #endif
 };
 
-static PySequenceMethods __pyx_tp_as_sequence___pyx_scope_struct_21___cinit__ = {
+static PySequenceMethods __pyx_tp_as_sequence___pyx_scope_struct_23___cinit__ = {
   0, /*sq_length*/
   0, /*sq_concat*/
   0, /*sq_repeat*/
@@ -20902,13 +24863,13 @@ static PySequenceMethods __pyx_tp_as_sequence___pyx_scope_struct_21___cinit__ =
   0, /*sq_inplace_repeat*/
 };
 
-static PyMappingMethods __pyx_tp_as_mapping___pyx_scope_struct_21___cinit__ = {
+static PyMappingMethods __pyx_tp_as_mapping___pyx_scope_struct_23___cinit__ = {
   0, /*mp_length*/
   0, /*mp_subscript*/
   0, /*mp_ass_subscript*/
 };
 
-static PyBufferProcs __pyx_tp_as_buffer___pyx_scope_struct_21___cinit__ = {
+static PyBufferProcs __pyx_tp_as_buffer___pyx_scope_struct_23___cinit__ = {
   #if PY_MAJOR_VERSION < 3
   0, /*bf_getreadbuffer*/
   #endif
@@ -20929,12 +24890,12 @@ static PyBufferProcs __pyx_tp_as_buffer___pyx_scope_struct_21___cinit__ = {
   #endif
 };
 
-static PyTypeObject __pyx_type_5_cdec___pyx_scope_struct_21___cinit__ = {
+static PyTypeObject __pyx_type_5_cdec___pyx_scope_struct_23___cinit__ = {
   PyVarObject_HEAD_INIT(0, 0)
-  __Pyx_NAMESTR("_cdec.__pyx_scope_struct_21___cinit__"), /*tp_name*/
-  sizeof(struct __pyx_obj_5_cdec___pyx_scope_struct_21___cinit__), /*tp_basicsize*/
+  __Pyx_NAMESTR("_cdec.__pyx_scope_struct_23___cinit__"), /*tp_name*/
+  sizeof(struct __pyx_obj_5_cdec___pyx_scope_struct_23___cinit__), /*tp_basicsize*/
   0, /*tp_itemsize*/
-  __pyx_tp_dealloc_5_cdec___pyx_scope_struct_21___cinit__, /*tp_dealloc*/
+  __pyx_tp_dealloc_5_cdec___pyx_scope_struct_23___cinit__, /*tp_dealloc*/
   0, /*tp_print*/
   0, /*tp_getattr*/
   0, /*tp_setattr*/
@@ -20944,24 +24905,24 @@ static PyTypeObject __pyx_type_5_cdec___pyx_scope_struct_21___cinit__ = {
   0, /*reserved*/
   #endif
   0, /*tp_repr*/
-  &__pyx_tp_as_number___pyx_scope_struct_21___cinit__, /*tp_as_number*/
-  &__pyx_tp_as_sequence___pyx_scope_struct_21___cinit__, /*tp_as_sequence*/
-  &__pyx_tp_as_mapping___pyx_scope_struct_21___cinit__, /*tp_as_mapping*/
+  &__pyx_tp_as_number___pyx_scope_struct_23___cinit__, /*tp_as_number*/
+  &__pyx_tp_as_sequence___pyx_scope_struct_23___cinit__, /*tp_as_sequence*/
+  &__pyx_tp_as_mapping___pyx_scope_struct_23___cinit__, /*tp_as_mapping*/
   0, /*tp_hash*/
   0, /*tp_call*/
   0, /*tp_str*/
   0, /*tp_getattro*/
   0, /*tp_setattro*/
-  &__pyx_tp_as_buffer___pyx_scope_struct_21___cinit__, /*tp_as_buffer*/
+  &__pyx_tp_as_buffer___pyx_scope_struct_23___cinit__, /*tp_as_buffer*/
   Py_TPFLAGS_DEFAULT|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_HAVE_GC, /*tp_flags*/
   0, /*tp_doc*/
-  __pyx_tp_traverse_5_cdec___pyx_scope_struct_21___cinit__, /*tp_traverse*/
-  __pyx_tp_clear_5_cdec___pyx_scope_struct_21___cinit__, /*tp_clear*/
+  __pyx_tp_traverse_5_cdec___pyx_scope_struct_23___cinit__, /*tp_traverse*/
+  __pyx_tp_clear_5_cdec___pyx_scope_struct_23___cinit__, /*tp_clear*/
   0, /*tp_richcompare*/
   0, /*tp_weaklistoffset*/
   0, /*tp_iter*/
   0, /*tp_iternext*/
-  __pyx_methods_5_cdec___pyx_scope_struct_21___cinit__, /*tp_methods*/
+  __pyx_methods_5_cdec___pyx_scope_struct_23___cinit__, /*tp_methods*/
   0, /*tp_members*/
   0, /*tp_getset*/
   0, /*tp_base*/
@@ -20971,7 +24932,7 @@ static PyTypeObject __pyx_type_5_cdec___pyx_scope_struct_21___cinit__ = {
   0, /*tp_dictoffset*/
   0, /*tp_init*/
   0, /*tp_alloc*/
-  __pyx_tp_new_5_cdec___pyx_scope_struct_21___cinit__, /*tp_new*/
+  __pyx_tp_new_5_cdec___pyx_scope_struct_23___cinit__, /*tp_new*/
   0, /*tp_free*/
   0, /*tp_is_gc*/
   0, /*tp_bases*/
@@ -20985,28 +24946,28 @@ static PyTypeObject __pyx_type_5_cdec___pyx_scope_struct_21___cinit__ = {
   #endif
 };
 
-static PyObject *__pyx_tp_new_5_cdec___pyx_scope_struct_22_genexpr(PyTypeObject *t, PyObject *a, PyObject *k) {
-  struct __pyx_obj_5_cdec___pyx_scope_struct_22_genexpr *p;
+static PyObject *__pyx_tp_new_5_cdec___pyx_scope_struct_24_genexpr(PyTypeObject *t, PyObject *a, PyObject *k) {
+  struct __pyx_obj_5_cdec___pyx_scope_struct_24_genexpr *p;
   PyObject *o = (*t->tp_alloc)(t, 0);
   if (!o) return 0;
-  p = ((struct __pyx_obj_5_cdec___pyx_scope_struct_22_genexpr *)o);
+  p = ((struct __pyx_obj_5_cdec___pyx_scope_struct_24_genexpr *)o);
   p->__pyx_outer_scope = 0;
   p->__pyx_v_kv = 0;
   p->__pyx_t_0 = 0;
   return o;
 }
 
-static void __pyx_tp_dealloc_5_cdec___pyx_scope_struct_22_genexpr(PyObject *o) {
-  struct __pyx_obj_5_cdec___pyx_scope_struct_22_genexpr *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_22_genexpr *)o;
+static void __pyx_tp_dealloc_5_cdec___pyx_scope_struct_24_genexpr(PyObject *o) {
+  struct __pyx_obj_5_cdec___pyx_scope_struct_24_genexpr *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_24_genexpr *)o;
   Py_XDECREF(((PyObject *)p->__pyx_outer_scope));
   Py_XDECREF(p->__pyx_v_kv);
   Py_XDECREF(p->__pyx_t_0);
   (*Py_TYPE(o)->tp_free)(o);
 }
 
-static int __pyx_tp_traverse_5_cdec___pyx_scope_struct_22_genexpr(PyObject *o, visitproc v, void *a) {
+static int __pyx_tp_traverse_5_cdec___pyx_scope_struct_24_genexpr(PyObject *o, visitproc v, void *a) {
   int e;
-  struct __pyx_obj_5_cdec___pyx_scope_struct_22_genexpr *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_22_genexpr *)o;
+  struct __pyx_obj_5_cdec___pyx_scope_struct_24_genexpr *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_24_genexpr *)o;
   if (p->__pyx_outer_scope) {
     e = (*v)(((PyObject*)p->__pyx_outer_scope), a); if (e) return e;
   }
@@ -21019,11 +24980,11 @@ static int __pyx_tp_traverse_5_cdec___pyx_scope_struct_22_genexpr(PyObject *o, v
   return 0;
 }
 
-static int __pyx_tp_clear_5_cdec___pyx_scope_struct_22_genexpr(PyObject *o) {
-  struct __pyx_obj_5_cdec___pyx_scope_struct_22_genexpr *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_22_genexpr *)o;
+static int __pyx_tp_clear_5_cdec___pyx_scope_struct_24_genexpr(PyObject *o) {
+  struct __pyx_obj_5_cdec___pyx_scope_struct_24_genexpr *p = (struct __pyx_obj_5_cdec___pyx_scope_struct_24_genexpr *)o;
   PyObject* tmp;
   tmp = ((PyObject*)p->__pyx_outer_scope);
-  p->__pyx_outer_scope = ((struct __pyx_obj_5_cdec___pyx_scope_struct_21___cinit__ *)Py_None); Py_INCREF(Py_None);
+  p->__pyx_outer_scope = ((struct __pyx_obj_5_cdec___pyx_scope_struct_23___cinit__ *)Py_None); Py_INCREF(Py_None);
   Py_XDECREF(tmp);
   tmp = ((PyObject*)p->__pyx_v_kv);
   p->__pyx_v_kv = Py_None; Py_INCREF(Py_None);
@@ -21034,11 +24995,11 @@ static int __pyx_tp_clear_5_cdec___pyx_scope_struct_22_genexpr(PyObject *o) {
   return 0;
 }
 
-static PyMethodDef __pyx_methods_5_cdec___pyx_scope_struct_22_genexpr[] = {
+static PyMethodDef __pyx_methods_5_cdec___pyx_scope_struct_24_genexpr[] = {
   {0, 0, 0, 0}
 };
 
-static PyNumberMethods __pyx_tp_as_number___pyx_scope_struct_22_genexpr = {
+static PyNumberMethods __pyx_tp_as_number___pyx_scope_struct_24_genexpr = {
   0, /*nb_add*/
   0, /*nb_subtract*/
   0, /*nb_multiply*/
@@ -21096,7 +25057,7 @@ static PyNumberMethods __pyx_tp_as_number___pyx_scope_struct_22_genexpr = {
   #endif
 };
 
-static PySequenceMethods __pyx_tp_as_sequence___pyx_scope_struct_22_genexpr = {
+static PySequenceMethods __pyx_tp_as_sequence___pyx_scope_struct_24_genexpr = {
   0, /*sq_length*/
   0, /*sq_concat*/
   0, /*sq_repeat*/
@@ -21109,13 +25070,13 @@ static PySequenceMethods __pyx_tp_as_sequence___pyx_scope_struct_22_genexpr = {
   0, /*sq_inplace_repeat*/
 };
 
-static PyMappingMethods __pyx_tp_as_mapping___pyx_scope_struct_22_genexpr = {
+static PyMappingMethods __pyx_tp_as_mapping___pyx_scope_struct_24_genexpr = {
   0, /*mp_length*/
   0, /*mp_subscript*/
   0, /*mp_ass_subscript*/
 };
 
-static PyBufferProcs __pyx_tp_as_buffer___pyx_scope_struct_22_genexpr = {
+static PyBufferProcs __pyx_tp_as_buffer___pyx_scope_struct_24_genexpr = {
   #if PY_MAJOR_VERSION < 3
   0, /*bf_getreadbuffer*/
   #endif
@@ -21136,12 +25097,12 @@ static PyBufferProcs __pyx_tp_as_buffer___pyx_scope_struct_22_genexpr = {
   #endif
 };
 
-static PyTypeObject __pyx_type_5_cdec___pyx_scope_struct_22_genexpr = {
+static PyTypeObject __pyx_type_5_cdec___pyx_scope_struct_24_genexpr = {
   PyVarObject_HEAD_INIT(0, 0)
-  __Pyx_NAMESTR("_cdec.__pyx_scope_struct_22_genexpr"), /*tp_name*/
-  sizeof(struct __pyx_obj_5_cdec___pyx_scope_struct_22_genexpr), /*tp_basicsize*/
+  __Pyx_NAMESTR("_cdec.__pyx_scope_struct_24_genexpr"), /*tp_name*/
+  sizeof(struct __pyx_obj_5_cdec___pyx_scope_struct_24_genexpr), /*tp_basicsize*/
   0, /*tp_itemsize*/
-  __pyx_tp_dealloc_5_cdec___pyx_scope_struct_22_genexpr, /*tp_dealloc*/
+  __pyx_tp_dealloc_5_cdec___pyx_scope_struct_24_genexpr, /*tp_dealloc*/
   0, /*tp_print*/
   0, /*tp_getattr*/
   0, /*tp_setattr*/
@@ -21151,24 +25112,24 @@ static PyTypeObject __pyx_type_5_cdec___pyx_scope_struct_22_genexpr = {
   0, /*reserved*/
   #endif
   0, /*tp_repr*/
-  &__pyx_tp_as_number___pyx_scope_struct_22_genexpr, /*tp_as_number*/
-  &__pyx_tp_as_sequence___pyx_scope_struct_22_genexpr, /*tp_as_sequence*/
-  &__pyx_tp_as_mapping___pyx_scope_struct_22_genexpr, /*tp_as_mapping*/
+  &__pyx_tp_as_number___pyx_scope_struct_24_genexpr, /*tp_as_number*/
+  &__pyx_tp_as_sequence___pyx_scope_struct_24_genexpr, /*tp_as_sequence*/
+  &__pyx_tp_as_mapping___pyx_scope_struct_24_genexpr, /*tp_as_mapping*/
   0, /*tp_hash*/
   0, /*tp_call*/
   0, /*tp_str*/
   0, /*tp_getattro*/
   0, /*tp_setattro*/
-  &__pyx_tp_as_buffer___pyx_scope_struct_22_genexpr, /*tp_as_buffer*/
+  &__pyx_tp_as_buffer___pyx_scope_struct_24_genexpr, /*tp_as_buffer*/
   Py_TPFLAGS_DEFAULT|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_HAVE_GC, /*tp_flags*/
   0, /*tp_doc*/
-  __pyx_tp_traverse_5_cdec___pyx_scope_struct_22_genexpr, /*tp_traverse*/
-  __pyx_tp_clear_5_cdec___pyx_scope_struct_22_genexpr, /*tp_clear*/
+  __pyx_tp_traverse_5_cdec___pyx_scope_struct_24_genexpr, /*tp_traverse*/
+  __pyx_tp_clear_5_cdec___pyx_scope_struct_24_genexpr, /*tp_clear*/
   0, /*tp_richcompare*/
   0, /*tp_weaklistoffset*/
   0, /*tp_iter*/
   0, /*tp_iternext*/
-  __pyx_methods_5_cdec___pyx_scope_struct_22_genexpr, /*tp_methods*/
+  __pyx_methods_5_cdec___pyx_scope_struct_24_genexpr, /*tp_methods*/
   0, /*tp_members*/
   0, /*tp_getset*/
   0, /*tp_base*/
@@ -21178,7 +25139,7 @@ static PyTypeObject __pyx_type_5_cdec___pyx_scope_struct_22_genexpr = {
   0, /*tp_dictoffset*/
   0, /*tp_init*/
   0, /*tp_alloc*/
-  __pyx_tp_new_5_cdec___pyx_scope_struct_22_genexpr, /*tp_new*/
+  __pyx_tp_new_5_cdec___pyx_scope_struct_24_genexpr, /*tp_new*/
   0, /*tp_free*/
   0, /*tp_is_gc*/
   0, /*tp_bases*/
@@ -21216,33 +25177,36 @@ static __Pyx_StringTabEntry __pyx_string_tab[] = {
   {&__pyx_kp_s_11, __pyx_k_11, sizeof(__pyx_k_11), 0, 0, 1, 0},
   {&__pyx_kp_s_12, __pyx_k_12, sizeof(__pyx_k_12), 0, 0, 1, 0},
   {&__pyx_kp_s_13, __pyx_k_13, sizeof(__pyx_k_13), 0, 0, 1, 0},
-  {&__pyx_kp_s_15, __pyx_k_15, sizeof(__pyx_k_15), 0, 0, 1, 0},
-  {&__pyx_kp_s_18, __pyx_k_18, sizeof(__pyx_k_18), 0, 0, 1, 0},
+  {&__pyx_n_s_15, __pyx_k_15, sizeof(__pyx_k_15), 0, 0, 1, 1},
+  {&__pyx_kp_s_16, __pyx_k_16, sizeof(__pyx_k_16), 0, 0, 1, 0},
+  {&__pyx_kp_s_17, __pyx_k_17, sizeof(__pyx_k_17), 0, 0, 1, 0},
   {&__pyx_kp_s_19, __pyx_k_19, sizeof(__pyx_k_19), 0, 0, 1, 0},
+  {&__pyx_kp_s_22, __pyx_k_22, sizeof(__pyx_k_22), 0, 0, 1, 0},
   {&__pyx_kp_s_23, __pyx_k_23, sizeof(__pyx_k_23), 0, 0, 1, 0},
-  {&__pyx_kp_s_24, __pyx_k_24, sizeof(__pyx_k_24), 0, 0, 1, 0},
-  {&__pyx_kp_s_25, __pyx_k_25, sizeof(__pyx_k_25), 0, 0, 1, 0},
-  {&__pyx_kp_s_26, __pyx_k_26, sizeof(__pyx_k_26), 0, 0, 1, 0},
   {&__pyx_kp_s_27, __pyx_k_27, sizeof(__pyx_k_27), 0, 0, 1, 0},
   {&__pyx_kp_s_28, __pyx_k_28, sizeof(__pyx_k_28), 0, 0, 1, 0},
+  {&__pyx_kp_s_29, __pyx_k_29, sizeof(__pyx_k_29), 0, 0, 1, 0},
   {&__pyx_kp_s_3, __pyx_k_3, sizeof(__pyx_k_3), 0, 0, 1, 0},
   {&__pyx_kp_s_30, __pyx_k_30, sizeof(__pyx_k_30), 0, 0, 1, 0},
   {&__pyx_kp_s_31, __pyx_k_31, sizeof(__pyx_k_31), 0, 0, 1, 0},
+  {&__pyx_kp_s_32, __pyx_k_32, sizeof(__pyx_k_32), 0, 0, 1, 0},
   {&__pyx_kp_s_34, __pyx_k_34, sizeof(__pyx_k_34), 0, 0, 1, 0},
   {&__pyx_kp_s_35, __pyx_k_35, sizeof(__pyx_k_35), 0, 0, 1, 0},
-  {&__pyx_kp_s_37, __pyx_k_37, sizeof(__pyx_k_37), 0, 0, 1, 0},
+  {&__pyx_kp_s_38, __pyx_k_38, sizeof(__pyx_k_38), 0, 0, 1, 0},
   {&__pyx_kp_s_39, __pyx_k_39, sizeof(__pyx_k_39), 0, 0, 1, 0},
   {&__pyx_kp_s_4, __pyx_k_4, sizeof(__pyx_k_4), 0, 0, 1, 0},
-  {&__pyx_kp_s_40, __pyx_k_40, sizeof(__pyx_k_40), 0, 0, 1, 0},
-  {&__pyx_kp_s_42, __pyx_k_42, sizeof(__pyx_k_42), 0, 0, 1, 0},
+  {&__pyx_kp_s_41, __pyx_k_41, sizeof(__pyx_k_41), 0, 0, 1, 0},
   {&__pyx_kp_s_43, __pyx_k_43, sizeof(__pyx_k_43), 0, 0, 1, 0},
   {&__pyx_kp_s_44, __pyx_k_44, sizeof(__pyx_k_44), 0, 0, 1, 0},
+  {&__pyx_kp_s_46, __pyx_k_46, sizeof(__pyx_k_46), 0, 0, 1, 0},
+  {&__pyx_kp_s_47, __pyx_k_47, sizeof(__pyx_k_47), 0, 0, 1, 0},
   {&__pyx_kp_s_48, __pyx_k_48, sizeof(__pyx_k_48), 0, 0, 1, 0},
   {&__pyx_kp_s_51, __pyx_k_51, sizeof(__pyx_k_51), 0, 0, 1, 0},
-  {&__pyx_kp_s_56, __pyx_k_56, sizeof(__pyx_k_56), 0, 0, 1, 0},
-  {&__pyx_n_s_6, __pyx_k_6, sizeof(__pyx_k_6), 0, 0, 1, 1},
+  {&__pyx_kp_s_54, __pyx_k_54, sizeof(__pyx_k_54), 0, 0, 1, 0},
+  {&__pyx_kp_s_59, __pyx_k_59, sizeof(__pyx_k_59), 0, 0, 1, 0},
   {&__pyx_kp_s_7, __pyx_k_7, sizeof(__pyx_k_7), 0, 0, 1, 0},
   {&__pyx_kp_s_8, __pyx_k_8, sizeof(__pyx_k_8), 0, 0, 1, 0},
+  {&__pyx_kp_s_9, __pyx_k_9, sizeof(__pyx_k_9), 0, 0, 1, 0},
   {&__pyx_n_s__BLEU, __pyx_k__BLEU, sizeof(__pyx_k__BLEU), 0, 0, 1, 1},
   {&__pyx_n_s__Exception, __pyx_k__Exception, sizeof(__pyx_k__Exception), 0, 0, 1, 1},
   {&__pyx_n_s__IBM_BLEU, __pyx_k__IBM_BLEU, sizeof(__pyx_k__IBM_BLEU), 0, 0, 1, 1},
@@ -21253,6 +25217,7 @@ static __Pyx_StringTabEntry __pyx_string_tab[] = {
   {&__pyx_n_s__ParseFailed, __pyx_k__ParseFailed, sizeof(__pyx_k__ParseFailed), 0, 0, 1, 1},
   {&__pyx_n_s__TER, __pyx_k__TER, sizeof(__pyx_k__TER), 0, 0, 1, 1},
   {&__pyx_n_s__TypeError, __pyx_k__TypeError, sizeof(__pyx_k__TypeError), 0, 0, 1, 1},
+  {&__pyx_n_s__ValueError, __pyx_k__ValueError, sizeof(__pyx_k__ValueError), 0, 0, 1, 1},
   {&__pyx_n_s____enter__, __pyx_k____enter__, sizeof(__pyx_k____enter__), 0, 0, 1, 1},
   {&__pyx_n_s____exit__, __pyx_k____exit__, sizeof(__pyx_k____exit__), 0, 0, 1, 1},
   {&__pyx_n_s____main__, __pyx_k____main__, sizeof(__pyx_k____main__), 0, 0, 1, 1},
@@ -21260,7 +25225,9 @@ static __Pyx_StringTabEntry __pyx_string_tab[] = {
   {&__pyx_n_s___cdec, __pyx_k___cdec, sizeof(__pyx_k___cdec), 0, 0, 1, 1},
   {&__pyx_n_s___make_config, __pyx_k___make_config, sizeof(__pyx_k___make_config), 0, 0, 1, 1},
   {&__pyx_n_s___phrase, __pyx_k___phrase, sizeof(__pyx_k___phrase), 0, 0, 1, 1},
+  {&__pyx_n_s__a, __pyx_k__a, sizeof(__pyx_k__a), 0, 0, 1, 1},
   {&__pyx_n_s__beam_alpha, __pyx_k__beam_alpha, sizeof(__pyx_k__beam_alpha), 0, 0, 1, 1},
+  {&__pyx_n_s__cat, __pyx_k__cat, sizeof(__pyx_k__cat), 0, 0, 1, 1},
   {&__pyx_n_s__config, __pyx_k__config, sizeof(__pyx_k__config), 0, 0, 1, 1},
   {&__pyx_n_s__config_str, __pyx_k__config_str, sizeof(__pyx_k__config_str), 0, 0, 1, 1},
   {&__pyx_n_s__csplit, __pyx_k__csplit, sizeof(__pyx_k__csplit), 0, 0, 1, 1},
@@ -21299,8 +25266,10 @@ static __Pyx_StringTabEntry __pyx_string_tab[] = {
   {&__pyx_n_s__phrase, __pyx_k__phrase, sizeof(__pyx_k__phrase), 0, 0, 1, 1},
   {&__pyx_n_s__plf, __pyx_k__plf, sizeof(__pyx_k__plf), 0, 0, 1, 1},
   {&__pyx_n_s__range, __pyx_k__range, sizeof(__pyx_k__range), 0, 0, 1, 1},
+  {&__pyx_n_s__ref, __pyx_k__ref, sizeof(__pyx_k__ref), 0, 0, 1, 1},
   {&__pyx_n_s__refs, __pyx_k__refs, sizeof(__pyx_k__refs), 0, 0, 1, 1},
   {&__pyx_n_s__replace, __pyx_k__replace, sizeof(__pyx_k__replace), 0, 0, 1, 1},
+  {&__pyx_n_s__rules, __pyx_k__rules, sizeof(__pyx_k__rules), 0, 0, 1, 1},
   {&__pyx_n_s__scfg, __pyx_k__scfg, sizeof(__pyx_k__scfg), 0, 0, 1, 1},
   {&__pyx_n_s__scores, __pyx_k__scores, sizeof(__pyx_k__scores), 0, 0, 1, 1},
   {&__pyx_n_s__self, __pyx_k__self, sizeof(__pyx_k__self), 0, 0, 1, 1},
@@ -21316,15 +25285,16 @@ static __Pyx_StringTabEntry __pyx_string_tab[] = {
   {0, 0, 0, 0, 0, 0, 0}
 };
 static int __Pyx_InitCachedBuiltins(void) {
-  __pyx_builtin_Exception = __Pyx_GetName(__pyx_b, __pyx_n_s__Exception); if (!__pyx_builtin_Exception) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 24; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_builtin_Exception = __Pyx_GetName(__pyx_b, __pyx_n_s__Exception); if (!__pyx_builtin_Exception) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 25; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __pyx_builtin_TypeError = __Pyx_GetName(__pyx_b, __pyx_n_s__TypeError); if (!__pyx_builtin_TypeError) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 13; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __pyx_builtin_KeyError = __Pyx_GetName(__pyx_b, __pyx_n_s__KeyError); if (!__pyx_builtin_KeyError) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 13; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __pyx_builtin_range = __Pyx_GetName(__pyx_b, __pyx_n_s__range); if (!__pyx_builtin_range) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 24; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __pyx_builtin_NotImplemented = __Pyx_GetName(__pyx_b, __pyx_n_s__NotImplemented); if (!__pyx_builtin_NotImplemented) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 76; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __pyx_builtin_eval = __Pyx_GetName(__pyx_b, __pyx_n_s__eval); if (!__pyx_builtin_eval) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 102; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __pyx_builtin_enumerate = __Pyx_GetName(__pyx_b, __pyx_n_s__enumerate); if (!__pyx_builtin_enumerate) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 9; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __pyx_builtin_IndexError = __Pyx_GetName(__pyx_b, __pyx_n_s__IndexError); if (!__pyx_builtin_IndexError) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 21; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __pyx_builtin_open = __Pyx_GetName(__pyx_b, __pyx_n_s__open); if (!__pyx_builtin_open) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 85; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_builtin_NotImplemented = __Pyx_GetName(__pyx_b, __pyx_n_s__NotImplemented); if (!__pyx_builtin_NotImplemented) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 77; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_builtin_ValueError = __Pyx_GetName(__pyx_b, __pyx_n_s__ValueError); if (!__pyx_builtin_ValueError) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 175; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_builtin_eval = __Pyx_GetName(__pyx_b, __pyx_n_s__eval); if (!__pyx_builtin_eval) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 102; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_builtin_enumerate = __Pyx_GetName(__pyx_b, __pyx_n_s__enumerate); if (!__pyx_builtin_enumerate) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 9; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_builtin_IndexError = __Pyx_GetName(__pyx_b, __pyx_n_s__IndexError); if (!__pyx_builtin_IndexError) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 21; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_builtin_open = __Pyx_GetName(__pyx_b, __pyx_n_s__open); if (!__pyx_builtin_open) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 86; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   return 0;
   __pyx_L1_error:;
   return -1;
@@ -21336,10 +25306,10 @@ static int __Pyx_InitCachedConstants(void) {
 
   /* "_cdec.pyx":9
  *     cdef bytes ret
- *     if isinstance(sentence, unicode):
- *         ret = sentence.encode('utf8')             # <<<<<<<<<<<<<<
- *     elif isinstance(sentence, str):
- *         ret = sentence
+ *     if isinstance(data, unicode):
+ *         ret = data.encode('utf8')             # <<<<<<<<<<<<<<
+ *     elif isinstance(data, str):
+ *         ret = data
  */
   __pyx_k_tuple_2 = PyTuple_New(1); if (unlikely(!__pyx_k_tuple_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 9; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __Pyx_GOTREF(__pyx_k_tuple_2);
@@ -21348,58 +25318,72 @@ static int __Pyx_InitCachedConstants(void) {
   __Pyx_GIVEREF(((PyObject *)__pyx_n_s__utf8));
   __Pyx_GIVEREF(((PyObject *)__pyx_k_tuple_2));
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":76
+  /* "/Users/vchahun/Sandbox/cdec/python/src/vectors.pxi":77
  *         elif op == 3: # !=
  *             return not (x == y)
  *         raise NotImplemented('comparison not implemented for SparseVector')             # <<<<<<<<<<<<<<
  * 
  *     def __len__(self):
  */
-  __pyx_k_tuple_5 = PyTuple_New(1); if (unlikely(!__pyx_k_tuple_5)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 76; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_k_tuple_5 = PyTuple_New(1); if (unlikely(!__pyx_k_tuple_5)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 77; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __Pyx_GOTREF(__pyx_k_tuple_5);
   __Pyx_INCREF(((PyObject *)__pyx_kp_s_4));
   PyTuple_SET_ITEM(__pyx_k_tuple_5, 0, ((PyObject *)__pyx_kp_s_4));
   __Pyx_GIVEREF(((PyObject *)__pyx_kp_s_4));
   __Pyx_GIVEREF(((PyObject *)__pyx_k_tuple_5));
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/trule.pxi":2
+  /* "/Users/vchahun/Sandbox/cdec/python/src/grammar.pxi":4
+ * 
  * def _phrase(phrase):
- *     return ' '.join('[%s,%d]' % w if isinstance(w, tuple) else w.encode('utf8') for w in phrase)             # <<<<<<<<<<<<<<
+ *     return ' '.join(w.encode('utf8') if isinstance(w, unicode) else str(w) for w in phrase)             # <<<<<<<<<<<<<<
  * 
- * cdef class TRule:
+ * cdef class NT:
  */
-  __pyx_k_tuple_9 = PyTuple_New(1); if (unlikely(!__pyx_k_tuple_9)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 2; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __Pyx_GOTREF(__pyx_k_tuple_9);
+  __pyx_k_tuple_6 = PyTuple_New(1); if (unlikely(!__pyx_k_tuple_6)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 4; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_k_tuple_6);
   __Pyx_INCREF(((PyObject *)__pyx_n_s__utf8));
-  PyTuple_SET_ITEM(__pyx_k_tuple_9, 0, ((PyObject *)__pyx_n_s__utf8));
+  PyTuple_SET_ITEM(__pyx_k_tuple_6, 0, ((PyObject *)__pyx_n_s__utf8));
   __Pyx_GIVEREF(((PyObject *)__pyx_n_s__utf8));
-  __Pyx_GIVEREF(((PyObject *)__pyx_k_tuple_9));
+  __Pyx_GIVEREF(((PyObject *)__pyx_k_tuple_6));
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":177
- *         elif op == 3: # !=
- *             return not (x == y)
- *         raise NotImplemented('comparison not implemented for HypergraphEdge')             # <<<<<<<<<<<<<<
- * 
- * cdef class HypergraphNode:
+  /* "/Users/vchahun/Sandbox/cdec/python/src/grammar.pxi":175
+ *         for trule in rules:
+ *             if not isinstance(trule, BaseTRule):
+ *                 raise ValueError('the grammar should contain TRule objects')             # <<<<<<<<<<<<<<
+ *             _g.AddRule((<TRule> trule).rule[0])
  */
-  __pyx_k_tuple_14 = PyTuple_New(1); if (unlikely(!__pyx_k_tuple_14)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 177; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_k_tuple_14 = PyTuple_New(1); if (unlikely(!__pyx_k_tuple_14)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 175; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __Pyx_GOTREF(__pyx_k_tuple_14);
   __Pyx_INCREF(((PyObject *)__pyx_kp_s_13));
   PyTuple_SET_ITEM(__pyx_k_tuple_14, 0, ((PyObject *)__pyx_kp_s_13));
   __Pyx_GIVEREF(((PyObject *)__pyx_kp_s_13));
   __Pyx_GIVEREF(((PyObject *)__pyx_k_tuple_14));
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":214
+  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":191
+ *         elif op == 3: # !=
+ *             return not (x == y)
+ *         raise NotImplemented('comparison not implemented for HypergraphEdge')             # <<<<<<<<<<<<<<
+ * 
+ * cdef class HypergraphNode:
+ */
+  __pyx_k_tuple_18 = PyTuple_New(1); if (unlikely(!__pyx_k_tuple_18)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 191; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_k_tuple_18);
+  __Pyx_INCREF(((PyObject *)__pyx_kp_s_17));
+  PyTuple_SET_ITEM(__pyx_k_tuple_18, 0, ((PyObject *)__pyx_kp_s_17));
+  __Pyx_GIVEREF(((PyObject *)__pyx_kp_s_17));
+  __Pyx_GIVEREF(((PyObject *)__pyx_k_tuple_18));
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/hypergraph.pxi":228
  *         elif op == 3: # !=
  *             return not (x == y)
  *         raise NotImplemented('comparison not implemented for HypergraphNode')             # <<<<<<<<<<<<<<
  */
-  __pyx_k_tuple_16 = PyTuple_New(1); if (unlikely(!__pyx_k_tuple_16)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 214; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __Pyx_GOTREF(__pyx_k_tuple_16);
-  __Pyx_INCREF(((PyObject *)__pyx_kp_s_15));
-  PyTuple_SET_ITEM(__pyx_k_tuple_16, 0, ((PyObject *)__pyx_kp_s_15));
-  __Pyx_GIVEREF(((PyObject *)__pyx_kp_s_15));
-  __Pyx_GIVEREF(((PyObject *)__pyx_k_tuple_16));
+  __pyx_k_tuple_20 = PyTuple_New(1); if (unlikely(!__pyx_k_tuple_20)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 228; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_k_tuple_20);
+  __Pyx_INCREF(((PyObject *)__pyx_kp_s_19));
+  PyTuple_SET_ITEM(__pyx_k_tuple_20, 0, ((PyObject *)__pyx_kp_s_19));
+  __Pyx_GIVEREF(((PyObject *)__pyx_kp_s_19));
+  __Pyx_GIVEREF(((PyObject *)__pyx_k_tuple_20));
 
   /* "/Users/vchahun/Sandbox/cdec/python/src/lattice.pxi":13
  *         else:
@@ -21408,12 +25392,12 @@ static int __Pyx_InitCachedConstants(void) {
  *             if not isinstance(inp, str):
  *                 raise TypeError('Cannot create lattice from %s' % type(inp))
  */
-  __pyx_k_tuple_17 = PyTuple_New(1); if (unlikely(!__pyx_k_tuple_17)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 13; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __Pyx_GOTREF(__pyx_k_tuple_17);
+  __pyx_k_tuple_21 = PyTuple_New(1); if (unlikely(!__pyx_k_tuple_21)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 13; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_k_tuple_21);
   __Pyx_INCREF(((PyObject *)__pyx_n_s__utf8));
-  PyTuple_SET_ITEM(__pyx_k_tuple_17, 0, ((PyObject *)__pyx_n_s__utf8));
+  PyTuple_SET_ITEM(__pyx_k_tuple_21, 0, ((PyObject *)__pyx_n_s__utf8));
   __Pyx_GIVEREF(((PyObject *)__pyx_n_s__utf8));
-  __Pyx_GIVEREF(((PyObject *)__pyx_k_tuple_17));
+  __Pyx_GIVEREF(((PyObject *)__pyx_k_tuple_21));
 
   /* "/Users/vchahun/Sandbox/cdec/python/src/lattice.pxi":21
  *     def __getitem__(self, int index):
@@ -21422,12 +25406,12 @@ static int __Pyx_InitCachedConstants(void) {
  *         arcs = []
  *         cdef vector[lattice.LatticeArc] arc_vector = self.lattice[0][index]
  */
-  __pyx_k_tuple_20 = PyTuple_New(1); if (unlikely(!__pyx_k_tuple_20)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 21; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __Pyx_GOTREF(__pyx_k_tuple_20);
-  __Pyx_INCREF(((PyObject *)__pyx_kp_s_19));
-  PyTuple_SET_ITEM(__pyx_k_tuple_20, 0, ((PyObject *)__pyx_kp_s_19));
-  __Pyx_GIVEREF(((PyObject *)__pyx_kp_s_19));
-  __Pyx_GIVEREF(((PyObject *)__pyx_k_tuple_20));
+  __pyx_k_tuple_24 = PyTuple_New(1); if (unlikely(!__pyx_k_tuple_24)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 21; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_k_tuple_24);
+  __Pyx_INCREF(((PyObject *)__pyx_kp_s_23));
+  PyTuple_SET_ITEM(__pyx_k_tuple_24, 0, ((PyObject *)__pyx_kp_s_23));
+  __Pyx_GIVEREF(((PyObject *)__pyx_kp_s_23));
+  __Pyx_GIVEREF(((PyObject *)__pyx_k_tuple_24));
 
   /* "/Users/vchahun/Sandbox/cdec/python/src/lattice.pxi":34
  *     def __setitem__(self, int index, tuple arcs):
@@ -21436,12 +25420,12 @@ static int __Pyx_InitCachedConstants(void) {
  *         cdef lattice.LatticeArc* arc
  *         for (label, cost, dist2next) in arcs:
  */
-  __pyx_k_tuple_21 = PyTuple_New(1); if (unlikely(!__pyx_k_tuple_21)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 34; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __Pyx_GOTREF(__pyx_k_tuple_21);
-  __Pyx_INCREF(((PyObject *)__pyx_kp_s_19));
-  PyTuple_SET_ITEM(__pyx_k_tuple_21, 0, ((PyObject *)__pyx_kp_s_19));
-  __Pyx_GIVEREF(((PyObject *)__pyx_kp_s_19));
-  __Pyx_GIVEREF(((PyObject *)__pyx_k_tuple_21));
+  __pyx_k_tuple_25 = PyTuple_New(1); if (unlikely(!__pyx_k_tuple_25)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 34; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_k_tuple_25);
+  __Pyx_INCREF(((PyObject *)__pyx_kp_s_23));
+  PyTuple_SET_ITEM(__pyx_k_tuple_25, 0, ((PyObject *)__pyx_kp_s_23));
+  __Pyx_GIVEREF(((PyObject *)__pyx_kp_s_23));
+  __Pyx_GIVEREF(((PyObject *)__pyx_k_tuple_25));
 
   /* "/Users/vchahun/Sandbox/cdec/python/src/lattice.pxi":38
  *         for (label, cost, dist2next) in arcs:
@@ -21450,12 +25434,12 @@ static int __Pyx_InitCachedConstants(void) {
  *             arc = new lattice.LatticeArc(TDConvert(<char *>label), cost, dist2next)
  *             self.lattice[0][index].push_back(arc[0])
  */
-  __pyx_k_tuple_22 = PyTuple_New(1); if (unlikely(!__pyx_k_tuple_22)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 38; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __Pyx_GOTREF(__pyx_k_tuple_22);
+  __pyx_k_tuple_26 = PyTuple_New(1); if (unlikely(!__pyx_k_tuple_26)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 38; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_k_tuple_26);
   __Pyx_INCREF(((PyObject *)__pyx_n_s__utf8));
-  PyTuple_SET_ITEM(__pyx_k_tuple_22, 0, ((PyObject *)__pyx_n_s__utf8));
+  PyTuple_SET_ITEM(__pyx_k_tuple_26, 0, ((PyObject *)__pyx_n_s__utf8));
   __Pyx_GIVEREF(((PyObject *)__pyx_n_s__utf8));
-  __Pyx_GIVEREF(((PyObject *)__pyx_k_tuple_22));
+  __Pyx_GIVEREF(((PyObject *)__pyx_k_tuple_26));
 
   /* "/Users/vchahun/Sandbox/cdec/python/src/lattice.pxi":64
  *             for i in range(len(self)):
@@ -21464,15 +25448,15 @@ static int __Pyx_InitCachedConstants(void) {
  *             yield '%d [shape=doublecircle]' % len(self)
  *             yield '}'
  */
-  __pyx_k_tuple_29 = PyTuple_New(2); if (unlikely(!__pyx_k_tuple_29)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 64; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __Pyx_GOTREF(__pyx_k_tuple_29);
-  __Pyx_INCREF(((PyObject *)__pyx_kp_s_27));
-  PyTuple_SET_ITEM(__pyx_k_tuple_29, 0, ((PyObject *)__pyx_kp_s_27));
-  __Pyx_GIVEREF(((PyObject *)__pyx_kp_s_27));
-  __Pyx_INCREF(((PyObject *)__pyx_kp_s_28));
-  PyTuple_SET_ITEM(__pyx_k_tuple_29, 1, ((PyObject *)__pyx_kp_s_28));
-  __Pyx_GIVEREF(((PyObject *)__pyx_kp_s_28));
-  __Pyx_GIVEREF(((PyObject *)__pyx_k_tuple_29));
+  __pyx_k_tuple_33 = PyTuple_New(2); if (unlikely(!__pyx_k_tuple_33)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 64; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_k_tuple_33);
+  __Pyx_INCREF(((PyObject *)__pyx_kp_s_31));
+  PyTuple_SET_ITEM(__pyx_k_tuple_33, 0, ((PyObject *)__pyx_kp_s_31));
+  __Pyx_GIVEREF(((PyObject *)__pyx_kp_s_31));
+  __Pyx_INCREF(((PyObject *)__pyx_kp_s_32));
+  PyTuple_SET_ITEM(__pyx_k_tuple_33, 1, ((PyObject *)__pyx_kp_s_32));
+  __Pyx_GIVEREF(((PyObject *)__pyx_kp_s_32));
+  __Pyx_GIVEREF(((PyObject *)__pyx_k_tuple_33));
 
   /* "/Users/vchahun/Sandbox/cdec/python/src/lattice.pxi":58
  * 
@@ -21481,34 +25465,34 @@ static int __Pyx_InitCachedConstants(void) {
  *             yield 'digraph lattice {'
  *             yield 'rankdir = LR;'
  */
-  __pyx_k_tuple_32 = PyTuple_New(4); if (unlikely(!__pyx_k_tuple_32)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 58; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __Pyx_GOTREF(__pyx_k_tuple_32);
+  __pyx_k_tuple_36 = PyTuple_New(4); if (unlikely(!__pyx_k_tuple_36)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 58; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_k_tuple_36);
   __Pyx_INCREF(((PyObject *)__pyx_n_s__i));
-  PyTuple_SET_ITEM(__pyx_k_tuple_32, 0, ((PyObject *)__pyx_n_s__i));
+  PyTuple_SET_ITEM(__pyx_k_tuple_36, 0, ((PyObject *)__pyx_n_s__i));
   __Pyx_GIVEREF(((PyObject *)__pyx_n_s__i));
   __Pyx_INCREF(((PyObject *)__pyx_n_s__label));
-  PyTuple_SET_ITEM(__pyx_k_tuple_32, 1, ((PyObject *)__pyx_n_s__label));
+  PyTuple_SET_ITEM(__pyx_k_tuple_36, 1, ((PyObject *)__pyx_n_s__label));
   __Pyx_GIVEREF(((PyObject *)__pyx_n_s__label));
   __Pyx_INCREF(((PyObject *)__pyx_n_s__weight));
-  PyTuple_SET_ITEM(__pyx_k_tuple_32, 2, ((PyObject *)__pyx_n_s__weight));
+  PyTuple_SET_ITEM(__pyx_k_tuple_36, 2, ((PyObject *)__pyx_n_s__weight));
   __Pyx_GIVEREF(((PyObject *)__pyx_n_s__weight));
   __Pyx_INCREF(((PyObject *)__pyx_n_s__delta));
-  PyTuple_SET_ITEM(__pyx_k_tuple_32, 3, ((PyObject *)__pyx_n_s__delta));
+  PyTuple_SET_ITEM(__pyx_k_tuple_36, 3, ((PyObject *)__pyx_n_s__delta));
   __Pyx_GIVEREF(((PyObject *)__pyx_n_s__delta));
-  __Pyx_GIVEREF(((PyObject *)__pyx_k_tuple_32));
-  __pyx_k_codeobj_33 = (PyObject*)__Pyx_PyCode_New(0, 0, 4, 0, 0, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_k_tuple_32, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_34, __pyx_n_s__lines, 58, __pyx_empty_bytes); if (unlikely(!__pyx_k_codeobj_33)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 58; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GIVEREF(((PyObject *)__pyx_k_tuple_36));
+  __pyx_k_codeobj_37 = (PyObject*)__Pyx_PyCode_New(0, 0, 4, 0, 0, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_k_tuple_36, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_38, __pyx_n_s__lines, 58, __pyx_empty_bytes); if (unlikely(!__pyx_k_codeobj_37)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 58; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
 
   /* "/Users/vchahun/Sandbox/cdec/python/src/lattice.pxi":67
  *             yield '%d [shape=doublecircle]' % len(self)
  *             yield '}'
  *         return '\n'.join(lines()).encode('utf8')             # <<<<<<<<<<<<<<
  */
-  __pyx_k_tuple_36 = PyTuple_New(1); if (unlikely(!__pyx_k_tuple_36)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 67; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __Pyx_GOTREF(__pyx_k_tuple_36);
+  __pyx_k_tuple_40 = PyTuple_New(1); if (unlikely(!__pyx_k_tuple_40)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 67; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_k_tuple_40);
   __Pyx_INCREF(((PyObject *)__pyx_n_s__utf8));
-  PyTuple_SET_ITEM(__pyx_k_tuple_36, 0, ((PyObject *)__pyx_n_s__utf8));
+  PyTuple_SET_ITEM(__pyx_k_tuple_40, 0, ((PyObject *)__pyx_n_s__utf8));
   __Pyx_GIVEREF(((PyObject *)__pyx_n_s__utf8));
-  __Pyx_GIVEREF(((PyObject *)__pyx_k_tuple_36));
+  __Pyx_GIVEREF(((PyObject *)__pyx_k_tuple_40));
 
   /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":79
  *     def __getitem__(self,int k):
@@ -21517,96 +25501,84 @@ static int __Pyx_InitCachedConstants(void) {
  *         cdef Candidate candidate = Candidate()
  *         candidate.candidate = &self.cs[0][k]
  */
-  __pyx_k_tuple_38 = PyTuple_New(1); if (unlikely(!__pyx_k_tuple_38)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 79; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __Pyx_GOTREF(__pyx_k_tuple_38);
-  __Pyx_INCREF(((PyObject *)__pyx_kp_s_37));
-  PyTuple_SET_ITEM(__pyx_k_tuple_38, 0, ((PyObject *)__pyx_kp_s_37));
-  __Pyx_GIVEREF(((PyObject *)__pyx_kp_s_37));
-  __Pyx_GIVEREF(((PyObject *)__pyx_k_tuple_38));
+  __pyx_k_tuple_42 = PyTuple_New(1); if (unlikely(!__pyx_k_tuple_42)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 79; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_k_tuple_42);
+  __Pyx_INCREF(((PyObject *)__pyx_kp_s_41));
+  PyTuple_SET_ITEM(__pyx_k_tuple_42, 0, ((PyObject *)__pyx_kp_s_41));
+  __Pyx_GIVEREF(((PyObject *)__pyx_kp_s_41));
+  __Pyx_GIVEREF(((PyObject *)__pyx_k_tuple_42));
 
-  /* "_cdec.pyx":49
+  /* "_cdec.pyx":50
  *         """
  *         if config_str is None:
  *             formalism = config.get('formalism', None)             # <<<<<<<<<<<<<<
  *             if formalism not in ('scfg', 'fst', 'lextrans', 'pb',
  *                     'csplit', 'tagger', 'lexalign'):
  */
-  __pyx_k_tuple_41 = PyTuple_New(2); if (unlikely(!__pyx_k_tuple_41)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 49; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __Pyx_GOTREF(__pyx_k_tuple_41);
+  __pyx_k_tuple_45 = PyTuple_New(2); if (unlikely(!__pyx_k_tuple_45)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 50; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_k_tuple_45);
   __Pyx_INCREF(((PyObject *)__pyx_n_s__formalism));
-  PyTuple_SET_ITEM(__pyx_k_tuple_41, 0, ((PyObject *)__pyx_n_s__formalism));
+  PyTuple_SET_ITEM(__pyx_k_tuple_45, 0, ((PyObject *)__pyx_n_s__formalism));
   __Pyx_GIVEREF(((PyObject *)__pyx_n_s__formalism));
   __Pyx_INCREF(Py_None);
-  PyTuple_SET_ITEM(__pyx_k_tuple_41, 1, Py_None);
+  PyTuple_SET_ITEM(__pyx_k_tuple_45, 1, Py_None);
   __Pyx_GIVEREF(Py_None);
-  __Pyx_GIVEREF(((PyObject *)__pyx_k_tuple_41));
+  __Pyx_GIVEREF(((PyObject *)__pyx_k_tuple_45));
 
-  /* "_cdec.pyx":87
+  /* "_cdec.pyx":88
  *         with open(weights) as fp:
  *             for line in fp:
  *                 if line.strip().startswith('#'): continue             # <<<<<<<<<<<<<<
  *                 fname, value = line.split()
  *                 self.weights[fname.strip()] = float(value)
  */
-  __pyx_k_tuple_45 = PyTuple_New(1); if (unlikely(!__pyx_k_tuple_45)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 87; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __Pyx_GOTREF(__pyx_k_tuple_45);
-  __Pyx_INCREF(((PyObject *)__pyx_kp_s_44));
-  PyTuple_SET_ITEM(__pyx_k_tuple_45, 0, ((PyObject *)__pyx_kp_s_44));
-  __Pyx_GIVEREF(((PyObject *)__pyx_kp_s_44));
-  __Pyx_GIVEREF(((PyObject *)__pyx_k_tuple_45));
+  __pyx_k_tuple_49 = PyTuple_New(1); if (unlikely(!__pyx_k_tuple_49)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 88; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_k_tuple_49);
+  __Pyx_INCREF(((PyObject *)__pyx_kp_s_48));
+  PyTuple_SET_ITEM(__pyx_k_tuple_49, 0, ((PyObject *)__pyx_kp_s_48));
+  __Pyx_GIVEREF(((PyObject *)__pyx_kp_s_48));
+  __Pyx_GIVEREF(((PyObject *)__pyx_k_tuple_49));
 
-  /* "_cdec.pyx":85
+  /* "_cdec.pyx":86
  * 
  *     def read_weights(self, weights):
  *         with open(weights) as fp:             # <<<<<<<<<<<<<<
  *             for line in fp:
  *                 if line.strip().startswith('#'): continue
  */
-  __pyx_k_tuple_46 = PyTuple_New(3); if (unlikely(!__pyx_k_tuple_46)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 85; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __Pyx_GOTREF(__pyx_k_tuple_46);
+  __pyx_k_tuple_50 = PyTuple_New(3); if (unlikely(!__pyx_k_tuple_50)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 86; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_k_tuple_50);
   __Pyx_INCREF(Py_None);
-  PyTuple_SET_ITEM(__pyx_k_tuple_46, 0, Py_None);
+  PyTuple_SET_ITEM(__pyx_k_tuple_50, 0, Py_None);
   __Pyx_GIVEREF(Py_None);
   __Pyx_INCREF(Py_None);
-  PyTuple_SET_ITEM(__pyx_k_tuple_46, 1, Py_None);
+  PyTuple_SET_ITEM(__pyx_k_tuple_50, 1, Py_None);
   __Pyx_GIVEREF(Py_None);
   __Pyx_INCREF(Py_None);
-  PyTuple_SET_ITEM(__pyx_k_tuple_46, 2, Py_None);
+  PyTuple_SET_ITEM(__pyx_k_tuple_50, 2, Py_None);
   __Pyx_GIVEREF(Py_None);
-  __Pyx_GIVEREF(((PyObject *)__pyx_k_tuple_46));
-
-  /* "_cdec.pyx":93
- *     def translate(self, sentence, grammar=None):
- *         if isinstance(sentence, unicode):
- *             inp = sentence.strip().encode('utf8')             # <<<<<<<<<<<<<<
- *         elif isinstance(sentence, str):
- *             inp = sentence.strip()
- */
-  __pyx_k_tuple_47 = PyTuple_New(1); if (unlikely(!__pyx_k_tuple_47)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 93; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __Pyx_GOTREF(__pyx_k_tuple_47);
-  __Pyx_INCREF(((PyObject *)__pyx_n_s__utf8));
-  PyTuple_SET_ITEM(__pyx_k_tuple_47, 0, ((PyObject *)__pyx_n_s__utf8));
-  __Pyx_GIVEREF(((PyObject *)__pyx_n_s__utf8));
-  __Pyx_GIVEREF(((PyObject *)__pyx_k_tuple_47));
+  __Pyx_GIVEREF(((PyObject *)__pyx_k_tuple_50));
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/trule.pxi":1
+  /* "/Users/vchahun/Sandbox/cdec/python/src/grammar.pxi":3
+ * cimport grammar
+ * 
  * def _phrase(phrase):             # <<<<<<<<<<<<<<
- *     return ' '.join('[%s,%d]' % w if isinstance(w, tuple) else w.encode('utf8') for w in phrase)
+ *     return ' '.join(w.encode('utf8') if isinstance(w, unicode) else str(w) for w in phrase)
  * 
  */
-  __pyx_k_tuple_49 = PyTuple_New(3); if (unlikely(!__pyx_k_tuple_49)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __Pyx_GOTREF(__pyx_k_tuple_49);
+  __pyx_k_tuple_52 = PyTuple_New(3); if (unlikely(!__pyx_k_tuple_52)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 3; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_k_tuple_52);
   __Pyx_INCREF(((PyObject *)__pyx_n_s__phrase));
-  PyTuple_SET_ITEM(__pyx_k_tuple_49, 0, ((PyObject *)__pyx_n_s__phrase));
+  PyTuple_SET_ITEM(__pyx_k_tuple_52, 0, ((PyObject *)__pyx_n_s__phrase));
   __Pyx_GIVEREF(((PyObject *)__pyx_n_s__phrase));
   __Pyx_INCREF(((PyObject *)__pyx_n_s__genexpr));
-  PyTuple_SET_ITEM(__pyx_k_tuple_49, 1, ((PyObject *)__pyx_n_s__genexpr));
+  PyTuple_SET_ITEM(__pyx_k_tuple_52, 1, ((PyObject *)__pyx_n_s__genexpr));
   __Pyx_GIVEREF(((PyObject *)__pyx_n_s__genexpr));
   __Pyx_INCREF(((PyObject *)__pyx_n_s__genexpr));
-  PyTuple_SET_ITEM(__pyx_k_tuple_49, 2, ((PyObject *)__pyx_n_s__genexpr));
+  PyTuple_SET_ITEM(__pyx_k_tuple_52, 2, ((PyObject *)__pyx_n_s__genexpr));
   __Pyx_GIVEREF(((PyObject *)__pyx_n_s__genexpr));
-  __Pyx_GIVEREF(((PyObject *)__pyx_k_tuple_49));
-  __pyx_k_codeobj_50 = (PyObject*)__Pyx_PyCode_New(1, 0, 3, 0, 0, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_k_tuple_49, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_51, __pyx_n_s___phrase, 1, __pyx_empty_bytes); if (unlikely(!__pyx_k_codeobj_50)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GIVEREF(((PyObject *)__pyx_k_tuple_52));
+  __pyx_k_codeobj_53 = (PyObject*)__Pyx_PyCode_New(1, 0, 3, 0, 0, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_k_tuple_52, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_54, __pyx_n_s___phrase, 3, __pyx_empty_bytes); if (unlikely(!__pyx_k_codeobj_53)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 3; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
 
   /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":143
  *         return self.name.c_str()
@@ -21614,51 +25586,51 @@ static int __Pyx_InitCachedConstants(void) {
  * BLEU = Scorer('IBM_BLEU')             # <<<<<<<<<<<<<<
  * TER = Scorer('TER')
  */
-  __pyx_k_tuple_52 = PyTuple_New(1); if (unlikely(!__pyx_k_tuple_52)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 143; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __Pyx_GOTREF(__pyx_k_tuple_52);
+  __pyx_k_tuple_55 = PyTuple_New(1); if (unlikely(!__pyx_k_tuple_55)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 143; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_k_tuple_55);
   __Pyx_INCREF(((PyObject *)__pyx_n_s__IBM_BLEU));
-  PyTuple_SET_ITEM(__pyx_k_tuple_52, 0, ((PyObject *)__pyx_n_s__IBM_BLEU));
+  PyTuple_SET_ITEM(__pyx_k_tuple_55, 0, ((PyObject *)__pyx_n_s__IBM_BLEU));
   __Pyx_GIVEREF(((PyObject *)__pyx_n_s__IBM_BLEU));
-  __Pyx_GIVEREF(((PyObject *)__pyx_k_tuple_52));
+  __Pyx_GIVEREF(((PyObject *)__pyx_k_tuple_55));
 
   /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":144
  * 
  * BLEU = Scorer('IBM_BLEU')
  * TER = Scorer('TER')             # <<<<<<<<<<<<<<
  */
-  __pyx_k_tuple_53 = PyTuple_New(1); if (unlikely(!__pyx_k_tuple_53)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 144; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __Pyx_GOTREF(__pyx_k_tuple_53);
+  __pyx_k_tuple_56 = PyTuple_New(1); if (unlikely(!__pyx_k_tuple_56)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 144; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_k_tuple_56);
   __Pyx_INCREF(((PyObject *)__pyx_n_s__TER));
-  PyTuple_SET_ITEM(__pyx_k_tuple_53, 0, ((PyObject *)__pyx_n_s__TER));
+  PyTuple_SET_ITEM(__pyx_k_tuple_56, 0, ((PyObject *)__pyx_n_s__TER));
   __Pyx_GIVEREF(((PyObject *)__pyx_n_s__TER));
-  __Pyx_GIVEREF(((PyObject *)__pyx_k_tuple_53));
+  __Pyx_GIVEREF(((PyObject *)__pyx_k_tuple_56));
 
-  /* "_cdec.pyx":27
+  /* "_cdec.pyx":28
  * class ParseFailed(Exception): pass
  * 
  * def _make_config(config):             # <<<<<<<<<<<<<<
  *     for key, value in config.items():
  *         if isinstance(value, dict):
  */
-  __pyx_k_tuple_54 = PyTuple_New(5); if (unlikely(!__pyx_k_tuple_54)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 27; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __Pyx_GOTREF(__pyx_k_tuple_54);
+  __pyx_k_tuple_57 = PyTuple_New(5); if (unlikely(!__pyx_k_tuple_57)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 28; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_k_tuple_57);
   __Pyx_INCREF(((PyObject *)__pyx_n_s__config));
-  PyTuple_SET_ITEM(__pyx_k_tuple_54, 0, ((PyObject *)__pyx_n_s__config));
+  PyTuple_SET_ITEM(__pyx_k_tuple_57, 0, ((PyObject *)__pyx_n_s__config));
   __Pyx_GIVEREF(((PyObject *)__pyx_n_s__config));
   __Pyx_INCREF(((PyObject *)__pyx_n_s__key));
-  PyTuple_SET_ITEM(__pyx_k_tuple_54, 1, ((PyObject *)__pyx_n_s__key));
+  PyTuple_SET_ITEM(__pyx_k_tuple_57, 1, ((PyObject *)__pyx_n_s__key));
   __Pyx_GIVEREF(((PyObject *)__pyx_n_s__key));
   __Pyx_INCREF(((PyObject *)__pyx_n_s__value));
-  PyTuple_SET_ITEM(__pyx_k_tuple_54, 2, ((PyObject *)__pyx_n_s__value));
+  PyTuple_SET_ITEM(__pyx_k_tuple_57, 2, ((PyObject *)__pyx_n_s__value));
   __Pyx_GIVEREF(((PyObject *)__pyx_n_s__value));
   __Pyx_INCREF(((PyObject *)__pyx_n_s__name));
-  PyTuple_SET_ITEM(__pyx_k_tuple_54, 3, ((PyObject *)__pyx_n_s__name));
+  PyTuple_SET_ITEM(__pyx_k_tuple_57, 3, ((PyObject *)__pyx_n_s__name));
   __Pyx_GIVEREF(((PyObject *)__pyx_n_s__name));
   __Pyx_INCREF(((PyObject *)__pyx_n_s__info));
-  PyTuple_SET_ITEM(__pyx_k_tuple_54, 4, ((PyObject *)__pyx_n_s__info));
+  PyTuple_SET_ITEM(__pyx_k_tuple_57, 4, ((PyObject *)__pyx_n_s__info));
   __Pyx_GIVEREF(((PyObject *)__pyx_n_s__info));
-  __Pyx_GIVEREF(((PyObject *)__pyx_k_tuple_54));
-  __pyx_k_codeobj_55 = (PyObject*)__Pyx_PyCode_New(1, 0, 5, 0, 0, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_k_tuple_54, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_56, __pyx_n_s___make_config, 27, __pyx_empty_bytes); if (unlikely(!__pyx_k_codeobj_55)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 27; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GIVEREF(((PyObject *)__pyx_k_tuple_57));
+  __pyx_k_codeobj_58 = (PyObject*)__Pyx_PyCode_New(1, 0, 5, 0, 0, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_k_tuple_57, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_59, __pyx_n_s___make_config, 28, __pyx_empty_bytes); if (unlikely(!__pyx_k_codeobj_58)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 28; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __Pyx_RefNannyFinishContext();
   return 0;
   __pyx_L1_error:;
@@ -21748,26 +25720,43 @@ PyMODINIT_FUNC PyInit__cdec(void)
   if (PyType_Ready(&__pyx_type_5_cdec_SparseVector) < 0) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 36; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   if (__Pyx_SetAttrString(__pyx_m, "SparseVector", (PyObject *)&__pyx_type_5_cdec_SparseVector) < 0) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 36; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __pyx_ptype_5_cdec_SparseVector = &__pyx_type_5_cdec_SparseVector;
-  if (PyType_Ready(&__pyx_type_5_cdec_Hypergraph) < 0) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 4; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  if (__Pyx_SetAttrString(__pyx_m, "Hypergraph", (PyObject *)&__pyx_type_5_cdec_Hypergraph) < 0) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 4; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __pyx_ptype_5_cdec_Hypergraph = &__pyx_type_5_cdec_Hypergraph;
-  if (PyType_Ready(&__pyx_type_5_cdec_TRule) < 0) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 4; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  if (__Pyx_SetAttrString(__pyx_m, "TRule", (PyObject *)&__pyx_type_5_cdec_TRule) < 0) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 4; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (PyType_Ready(&__pyx_type_5_cdec_NT) < 0) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 6; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (__Pyx_SetAttrString(__pyx_m, "NT", (PyObject *)&__pyx_type_5_cdec_NT) < 0) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 6; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_ptype_5_cdec_NT = &__pyx_type_5_cdec_NT;
+  if (PyType_Ready(&__pyx_type_5_cdec_NTRef) < 0) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 18; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (__Pyx_SetAttrString(__pyx_m, "NTRef", (PyObject *)&__pyx_type_5_cdec_NTRef) < 0) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 18; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_ptype_5_cdec_NTRef = &__pyx_type_5_cdec_NTRef;
+  if (PyType_Ready(&__pyx_type_5_cdec_BaseTRule) < 0) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 26; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (__Pyx_SetAttrString(__pyx_m, "BaseTRule", (PyObject *)&__pyx_type_5_cdec_BaseTRule) < 0) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 26; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_ptype_5_cdec_BaseTRule = &__pyx_type_5_cdec_BaseTRule;
+  __pyx_type_5_cdec_TRule.tp_base = __pyx_ptype_5_cdec_BaseTRule;
+  if (PyType_Ready(&__pyx_type_5_cdec_TRule) < 0) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 135; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (__Pyx_SetAttrString(__pyx_m, "TRule", (PyObject *)&__pyx_type_5_cdec_TRule) < 0) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 135; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __pyx_ptype_5_cdec_TRule = &__pyx_type_5_cdec_TRule;
+  if (PyType_Ready(&__pyx_type_5_cdec_Grammar) < 0) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 146; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (__Pyx_SetAttrString(__pyx_m, "Grammar", (PyObject *)&__pyx_type_5_cdec_Grammar) < 0) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 146; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_ptype_5_cdec_Grammar = &__pyx_type_5_cdec_Grammar;
+  __pyx_type_5_cdec_TextGrammar.tp_base = __pyx_ptype_5_cdec_Grammar;
+  if (PyType_Ready(&__pyx_type_5_cdec_TextGrammar) < 0) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 169; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (__Pyx_SetAttrString(__pyx_m, "TextGrammar", (PyObject *)&__pyx_type_5_cdec_TextGrammar) < 0) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 169; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_ptype_5_cdec_TextGrammar = &__pyx_type_5_cdec_TextGrammar;
+  if (PyType_Ready(&__pyx_type_5_cdec_Hypergraph) < 0) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 4; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (__Pyx_SetAttrString(__pyx_m, "Hypergraph", (PyObject *)&__pyx_type_5_cdec_Hypergraph) < 0) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 4; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_ptype_5_cdec_Hypergraph = &__pyx_type_5_cdec_Hypergraph;
   __pyx_vtabptr_5_cdec_HypergraphEdge = &__pyx_vtable_5_cdec_HypergraphEdge;
   __pyx_vtable_5_cdec_HypergraphEdge.init = (PyObject *(*)(struct __pyx_obj_5_cdec_HypergraphEdge *, Hypergraph *, unsigned int))__pyx_f_5_cdec_14HypergraphEdge_init;
-  if (PyType_Ready(&__pyx_type_5_cdec_HypergraphEdge) < 0) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 133; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  if (__Pyx_SetVtable(__pyx_type_5_cdec_HypergraphEdge.tp_dict, __pyx_vtabptr_5_cdec_HypergraphEdge) < 0) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 133; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  if (__Pyx_SetAttrString(__pyx_m, "HypergraphEdge", (PyObject *)&__pyx_type_5_cdec_HypergraphEdge) < 0) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 133; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (PyType_Ready(&__pyx_type_5_cdec_HypergraphEdge) < 0) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 147; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (__Pyx_SetVtable(__pyx_type_5_cdec_HypergraphEdge.tp_dict, __pyx_vtabptr_5_cdec_HypergraphEdge) < 0) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 147; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (__Pyx_SetAttrString(__pyx_m, "HypergraphEdge", (PyObject *)&__pyx_type_5_cdec_HypergraphEdge) < 0) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 147; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __pyx_ptype_5_cdec_HypergraphEdge = &__pyx_type_5_cdec_HypergraphEdge;
   __pyx_vtabptr_5_cdec_HypergraphNode = &__pyx_vtable_5_cdec_HypergraphNode;
   __pyx_vtable_5_cdec_HypergraphNode.init = (PyObject *(*)(struct __pyx_obj_5_cdec_HypergraphNode *, Hypergraph *, unsigned int))__pyx_f_5_cdec_14HypergraphNode_init;
-  if (PyType_Ready(&__pyx_type_5_cdec_HypergraphNode) < 0) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 179; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  if (__Pyx_SetVtable(__pyx_type_5_cdec_HypergraphNode.tp_dict, __pyx_vtabptr_5_cdec_HypergraphNode) < 0) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 179; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  if (__Pyx_SetAttrString(__pyx_m, "HypergraphNode", (PyObject *)&__pyx_type_5_cdec_HypergraphNode) < 0) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 179; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (PyType_Ready(&__pyx_type_5_cdec_HypergraphNode) < 0) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 193; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (__Pyx_SetVtable(__pyx_type_5_cdec_HypergraphNode.tp_dict, __pyx_vtabptr_5_cdec_HypergraphNode) < 0) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 193; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (__Pyx_SetAttrString(__pyx_m, "HypergraphNode", (PyObject *)&__pyx_type_5_cdec_HypergraphNode) < 0) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 193; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __pyx_ptype_5_cdec_HypergraphNode = &__pyx_type_5_cdec_HypergraphNode;
-  if (PyType_Ready(&__pyx_type_5_cdec_Lattice) < 0) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 3; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  if (__Pyx_SetAttrString(__pyx_m, "Lattice", (PyObject *)&__pyx_type_5_cdec_Lattice) < 0) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 3; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (PyType_Ready(&__pyx_type_5_cdec_Lattice) < 0) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 3; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (__Pyx_SetAttrString(__pyx_m, "Lattice", (PyObject *)&__pyx_type_5_cdec_Lattice) < 0) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 3; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __pyx_ptype_5_cdec_Lattice = &__pyx_type_5_cdec_Lattice;
   if (PyType_Ready(&__pyx_type_5_cdec_Candidate) < 0) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 12; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   if (__Pyx_SetAttrString(__pyx_m, "Candidate", (PyObject *)&__pyx_type_5_cdec_Candidate) < 0) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 12; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
@@ -21784,68 +25773,74 @@ PyMODINIT_FUNC PyInit__cdec(void)
   if (PyType_Ready(&__pyx_type_5_cdec_Scorer) < 0) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 112; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   if (__Pyx_SetAttrString(__pyx_m, "Scorer", (PyObject *)&__pyx_type_5_cdec_Scorer) < 0) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 112; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __pyx_ptype_5_cdec_Scorer = &__pyx_type_5_cdec_Scorer;
-  if (PyType_Ready(&__pyx_type_5_cdec_Decoder) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 38; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  if (__Pyx_SetAttrString(__pyx_m, "Decoder", (PyObject *)&__pyx_type_5_cdec_Decoder) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 38; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (PyType_Ready(&__pyx_type_5_cdec_Decoder) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 39; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (__Pyx_SetAttrString(__pyx_m, "Decoder", (PyObject *)&__pyx_type_5_cdec_Decoder) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 39; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __pyx_ptype_5_cdec_Decoder = &__pyx_type_5_cdec_Decoder;
   if (PyType_Ready(&__pyx_type_5_cdec___pyx_scope_struct____iter__) < 0) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 22; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __pyx_ptype_5_cdec___pyx_scope_struct____iter__ = &__pyx_type_5_cdec___pyx_scope_struct____iter__;
   if (PyType_Ready(&__pyx_type_5_cdec___pyx_scope_struct_1___iter__) < 0) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 55; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __pyx_ptype_5_cdec___pyx_scope_struct_1___iter__ = &__pyx_type_5_cdec___pyx_scope_struct_1___iter__;
-  if (PyType_Ready(&__pyx_type_5_cdec___pyx_scope_struct_2_kbest) < 0) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 31; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __pyx_ptype_5_cdec___pyx_scope_struct_2_kbest = &__pyx_type_5_cdec___pyx_scope_struct_2_kbest;
-  if (PyType_Ready(&__pyx_type_5_cdec___pyx_scope_struct_3_kbest_trees) < 0) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 43; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __pyx_ptype_5_cdec___pyx_scope_struct_3_kbest_trees = &__pyx_type_5_cdec___pyx_scope_struct_3_kbest_trees;
-  if (PyType_Ready(&__pyx_type_5_cdec___pyx_scope_struct_4_kbest_features) < 0) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 61; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __pyx_ptype_5_cdec___pyx_scope_struct_4_kbest_features = &__pyx_type_5_cdec___pyx_scope_struct_4_kbest_features;
-  if (PyType_Ready(&__pyx_type_5_cdec___pyx_scope_struct_5_sample) < 0) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 76; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __pyx_ptype_5_cdec___pyx_scope_struct_5_sample = &__pyx_type_5_cdec___pyx_scope_struct_5_sample;
-  if (PyType_Ready(&__pyx_type_5_cdec___pyx_scope_struct_6___get__) < 0) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 115; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __pyx_ptype_5_cdec___pyx_scope_struct_6___get__ = &__pyx_type_5_cdec___pyx_scope_struct_6___get__;
-  if (PyType_Ready(&__pyx_type_5_cdec___pyx_scope_struct_7___get__) < 0) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 121; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __pyx_ptype_5_cdec___pyx_scope_struct_7___get__ = &__pyx_type_5_cdec___pyx_scope_struct_7___get__;
-  if (PyType_Ready(&__pyx_type_5_cdec___pyx_scope_struct_8__phrase) < 0) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __pyx_ptype_5_cdec___pyx_scope_struct_8__phrase = &__pyx_type_5_cdec___pyx_scope_struct_8__phrase;
-  if (PyType_Ready(&__pyx_type_5_cdec___pyx_scope_struct_9_genexpr) < 0) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 2; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __pyx_ptype_5_cdec___pyx_scope_struct_9_genexpr = &__pyx_type_5_cdec___pyx_scope_struct_9_genexpr;
-  if (PyType_Ready(&__pyx_type_5_cdec___pyx_scope_struct_10___str__) < 0) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 53; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __pyx_ptype_5_cdec___pyx_scope_struct_10___str__ = &__pyx_type_5_cdec___pyx_scope_struct_10___str__;
-  if (PyType_Ready(&__pyx_type_5_cdec___pyx_scope_struct_11_genexpr) < 0) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 54; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __pyx_ptype_5_cdec___pyx_scope_struct_11_genexpr = &__pyx_type_5_cdec___pyx_scope_struct_11_genexpr;
-  if (PyType_Ready(&__pyx_type_5_cdec___pyx_scope_struct_12___get__) < 0) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 153; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (PyType_Ready(&__pyx_type_5_cdec___pyx_scope_struct_2__phrase) < 0) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 3; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_ptype_5_cdec___pyx_scope_struct_2__phrase = &__pyx_type_5_cdec___pyx_scope_struct_2__phrase;
+  if (PyType_Ready(&__pyx_type_5_cdec___pyx_scope_struct_3_genexpr) < 0) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 4; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_ptype_5_cdec___pyx_scope_struct_3_genexpr = &__pyx_type_5_cdec___pyx_scope_struct_3_genexpr;
+  if (PyType_Ready(&__pyx_type_5_cdec___pyx_scope_struct_4___get__) < 0) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 90; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_ptype_5_cdec___pyx_scope_struct_4___get__ = &__pyx_type_5_cdec___pyx_scope_struct_4___get__;
+  if (PyType_Ready(&__pyx_type_5_cdec___pyx_scope_struct_5___str__) < 0) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 130; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_ptype_5_cdec___pyx_scope_struct_5___str__ = &__pyx_type_5_cdec___pyx_scope_struct_5___str__;
+  if (PyType_Ready(&__pyx_type_5_cdec___pyx_scope_struct_6_genexpr) < 0) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 131; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_ptype_5_cdec___pyx_scope_struct_6_genexpr = &__pyx_type_5_cdec___pyx_scope_struct_6_genexpr;
+  if (PyType_Ready(&__pyx_type_5_cdec___pyx_scope_struct_7___iter__) < 0) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 152; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_ptype_5_cdec___pyx_scope_struct_7___iter__ = &__pyx_type_5_cdec___pyx_scope_struct_7___iter__;
+  if (PyType_Ready(&__pyx_type_5_cdec___pyx_scope_struct_8_kbest) < 0) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 31; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_ptype_5_cdec___pyx_scope_struct_8_kbest = &__pyx_type_5_cdec___pyx_scope_struct_8_kbest;
+  if (PyType_Ready(&__pyx_type_5_cdec___pyx_scope_struct_9_kbest_trees) < 0) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 43; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_ptype_5_cdec___pyx_scope_struct_9_kbest_trees = &__pyx_type_5_cdec___pyx_scope_struct_9_kbest_trees;
+  if (PyType_Ready(&__pyx_type_5_cdec___pyx_scope_struct_10_kbest_features) < 0) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 61; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_ptype_5_cdec___pyx_scope_struct_10_kbest_features = &__pyx_type_5_cdec___pyx_scope_struct_10_kbest_features;
+  if (PyType_Ready(&__pyx_type_5_cdec___pyx_scope_struct_11_sample) < 0) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 76; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_ptype_5_cdec___pyx_scope_struct_11_sample = &__pyx_type_5_cdec___pyx_scope_struct_11_sample;
+  if (PyType_Ready(&__pyx_type_5_cdec___pyx_scope_struct_12___get__) < 0) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 113; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __pyx_ptype_5_cdec___pyx_scope_struct_12___get__ = &__pyx_type_5_cdec___pyx_scope_struct_12___get__;
-  if (PyType_Ready(&__pyx_type_5_cdec___pyx_scope_struct_13___get__) < 0) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 189; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (PyType_Ready(&__pyx_type_5_cdec___pyx_scope_struct_13___get__) < 0) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 119; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __pyx_ptype_5_cdec___pyx_scope_struct_13___get__ = &__pyx_type_5_cdec___pyx_scope_struct_13___get__;
-  if (PyType_Ready(&__pyx_type_5_cdec___pyx_scope_struct_14___get__) < 0) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 195; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (PyType_Ready(&__pyx_type_5_cdec___pyx_scope_struct_14___get__) < 0) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 167; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __pyx_ptype_5_cdec___pyx_scope_struct_14___get__ = &__pyx_type_5_cdec___pyx_scope_struct_14___get__;
-  if (PyType_Ready(&__pyx_type_5_cdec___pyx_scope_struct_15___iter__) < 0) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 49; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __pyx_ptype_5_cdec___pyx_scope_struct_15___iter__ = &__pyx_type_5_cdec___pyx_scope_struct_15___iter__;
-  if (PyType_Ready(&__pyx_type_5_cdec___pyx_scope_struct_16_todot) < 0) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 57; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __pyx_ptype_5_cdec___pyx_scope_struct_16_todot = &__pyx_type_5_cdec___pyx_scope_struct_16_todot;
-  if (PyType_Ready(&__pyx_type_5_cdec___pyx_scope_struct_17_lines) < 0) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 58; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __pyx_ptype_5_cdec___pyx_scope_struct_17_lines = &__pyx_type_5_cdec___pyx_scope_struct_17_lines;
-  if (PyType_Ready(&__pyx_type_5_cdec___pyx_scope_struct_18___iter__) < 0) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 44; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __pyx_ptype_5_cdec___pyx_scope_struct_18___iter__ = &__pyx_type_5_cdec___pyx_scope_struct_18___iter__;
-  if (PyType_Ready(&__pyx_type_5_cdec___pyx_scope_struct_19___iter__) < 0) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 85; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __pyx_ptype_5_cdec___pyx_scope_struct_19___iter__ = &__pyx_type_5_cdec___pyx_scope_struct_19___iter__;
-  if (PyType_Ready(&__pyx_type_5_cdec___pyx_scope_struct_20__make_config) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 27; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __pyx_ptype_5_cdec___pyx_scope_struct_20__make_config = &__pyx_type_5_cdec___pyx_scope_struct_20__make_config;
-  if (PyType_Ready(&__pyx_type_5_cdec___pyx_scope_struct_21___cinit__) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 42; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __pyx_ptype_5_cdec___pyx_scope_struct_21___cinit__ = &__pyx_type_5_cdec___pyx_scope_struct_21___cinit__;
-  if (PyType_Ready(&__pyx_type_5_cdec___pyx_scope_struct_22_genexpr) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 53; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __pyx_ptype_5_cdec___pyx_scope_struct_22_genexpr = &__pyx_type_5_cdec___pyx_scope_struct_22_genexpr;
+  if (PyType_Ready(&__pyx_type_5_cdec___pyx_scope_struct_15___get__) < 0) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 203; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_ptype_5_cdec___pyx_scope_struct_15___get__ = &__pyx_type_5_cdec___pyx_scope_struct_15___get__;
+  if (PyType_Ready(&__pyx_type_5_cdec___pyx_scope_struct_16___get__) < 0) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 209; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_ptype_5_cdec___pyx_scope_struct_16___get__ = &__pyx_type_5_cdec___pyx_scope_struct_16___get__;
+  if (PyType_Ready(&__pyx_type_5_cdec___pyx_scope_struct_17___iter__) < 0) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 49; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_ptype_5_cdec___pyx_scope_struct_17___iter__ = &__pyx_type_5_cdec___pyx_scope_struct_17___iter__;
+  if (PyType_Ready(&__pyx_type_5_cdec___pyx_scope_struct_18_todot) < 0) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 57; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_ptype_5_cdec___pyx_scope_struct_18_todot = &__pyx_type_5_cdec___pyx_scope_struct_18_todot;
+  if (PyType_Ready(&__pyx_type_5_cdec___pyx_scope_struct_19_lines) < 0) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 58; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_ptype_5_cdec___pyx_scope_struct_19_lines = &__pyx_type_5_cdec___pyx_scope_struct_19_lines;
+  if (PyType_Ready(&__pyx_type_5_cdec___pyx_scope_struct_20___iter__) < 0) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 44; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_ptype_5_cdec___pyx_scope_struct_20___iter__ = &__pyx_type_5_cdec___pyx_scope_struct_20___iter__;
+  if (PyType_Ready(&__pyx_type_5_cdec___pyx_scope_struct_21___iter__) < 0) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 85; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_ptype_5_cdec___pyx_scope_struct_21___iter__ = &__pyx_type_5_cdec___pyx_scope_struct_21___iter__;
+  if (PyType_Ready(&__pyx_type_5_cdec___pyx_scope_struct_22__make_config) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 28; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_ptype_5_cdec___pyx_scope_struct_22__make_config = &__pyx_type_5_cdec___pyx_scope_struct_22__make_config;
+  if (PyType_Ready(&__pyx_type_5_cdec___pyx_scope_struct_23___cinit__) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 43; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_ptype_5_cdec___pyx_scope_struct_23___cinit__ = &__pyx_type_5_cdec___pyx_scope_struct_23___cinit__;
+  if (PyType_Ready(&__pyx_type_5_cdec___pyx_scope_struct_24_genexpr) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 54; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_ptype_5_cdec___pyx_scope_struct_24_genexpr = &__pyx_type_5_cdec___pyx_scope_struct_24_genexpr;
   /*--- Type import code ---*/
   /*--- Variable import code ---*/
   /*--- Function import code ---*/
   /*--- Execution code ---*/
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/trule.pxi":1
+  /* "/Users/vchahun/Sandbox/cdec/python/src/grammar.pxi":3
+ * cimport grammar
+ * 
  * def _phrase(phrase):             # <<<<<<<<<<<<<<
- *     return ' '.join('[%s,%d]' % w if isinstance(w, tuple) else w.encode('utf8') for w in phrase)
+ *     return ' '.join(w.encode('utf8') if isinstance(w, unicode) else str(w) for w in phrase)
  * 
  */
-  __pyx_t_1 = PyCFunction_NewEx(&__pyx_mdef_5_cdec_1_phrase, NULL, __pyx_n_s___cdec); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_1 = PyCFunction_NewEx(&__pyx_mdef_5_cdec_1_phrase, NULL, __pyx_n_s___cdec); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 3; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __Pyx_GOTREF(__pyx_t_1);
-  if (PyObject_SetAttr(__pyx_m, __pyx_n_s___phrase, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (PyObject_SetAttr(__pyx_m, __pyx_n_s___phrase, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 3; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
 
   /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":143
@@ -21854,7 +25849,7 @@ PyMODINIT_FUNC PyInit__cdec(void)
  * BLEU = Scorer('IBM_BLEU')             # <<<<<<<<<<<<<<
  * TER = Scorer('TER')
  */
-  __pyx_t_1 = PyObject_Call(((PyObject *)((PyObject*)__pyx_ptype_5_cdec_Scorer)), ((PyObject *)__pyx_k_tuple_52), NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 143; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_1 = PyObject_Call(((PyObject *)((PyObject*)__pyx_ptype_5_cdec_Scorer)), ((PyObject *)__pyx_k_tuple_55), NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 143; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __Pyx_GOTREF(__pyx_t_1);
   if (PyObject_SetAttr(__pyx_m, __pyx_n_s__BLEU, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 143; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
@@ -21864,12 +25859,12 @@ PyMODINIT_FUNC PyInit__cdec(void)
  * BLEU = Scorer('IBM_BLEU')
  * TER = Scorer('TER')             # <<<<<<<<<<<<<<
  */
-  __pyx_t_1 = PyObject_Call(((PyObject *)((PyObject*)__pyx_ptype_5_cdec_Scorer)), ((PyObject *)__pyx_k_tuple_53), NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 144; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_1 = PyObject_Call(((PyObject *)((PyObject*)__pyx_ptype_5_cdec_Scorer)), ((PyObject *)__pyx_k_tuple_56), NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 144; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __Pyx_GOTREF(__pyx_t_1);
   if (PyObject_SetAttr(__pyx_m, __pyx_n_s__TER, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 144; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
 
-  /* "_cdec.pyx":21
+  /* "_cdec.pyx":22
  * include "mteval.pxi"
  * 
  * SetSilent(True)             # <<<<<<<<<<<<<<
@@ -21878,7 +25873,7 @@ PyMODINIT_FUNC PyInit__cdec(void)
  */
   SetSilent(1);
 
-  /* "_cdec.pyx":22
+  /* "_cdec.pyx":23
  * 
  * SetSilent(True)
  * decoder.register_feature_functions()             # <<<<<<<<<<<<<<
@@ -21887,58 +25882,58 @@ PyMODINIT_FUNC PyInit__cdec(void)
  */
   register_feature_functions();
 
-  /* "_cdec.pyx":24
+  /* "_cdec.pyx":25
  * decoder.register_feature_functions()
  * 
  * class InvalidConfig(Exception): pass             # <<<<<<<<<<<<<<
  * class ParseFailed(Exception): pass
  * 
  */
-  __pyx_t_1 = PyDict_New(); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 24; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_1 = PyDict_New(); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 25; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __Pyx_GOTREF(((PyObject *)__pyx_t_1));
-  __pyx_t_2 = PyTuple_New(1); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 24; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_2 = PyTuple_New(1); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 25; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __Pyx_GOTREF(__pyx_t_2);
   __Pyx_INCREF(__pyx_builtin_Exception);
   PyTuple_SET_ITEM(__pyx_t_2, 0, __pyx_builtin_Exception);
   __Pyx_GIVEREF(__pyx_builtin_Exception);
-  __pyx_t_3 = __Pyx_CreateClass(((PyObject *)__pyx_t_2), ((PyObject *)__pyx_t_1), __pyx_n_s__InvalidConfig, __pyx_n_s___cdec); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 24; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_3 = __Pyx_CreateClass(((PyObject *)__pyx_t_2), ((PyObject *)__pyx_t_1), __pyx_n_s__InvalidConfig, __pyx_n_s___cdec); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 25; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __Pyx_GOTREF(__pyx_t_3);
   __Pyx_DECREF(((PyObject *)__pyx_t_2)); __pyx_t_2 = 0;
-  if (PyObject_SetAttr(__pyx_m, __pyx_n_s__InvalidConfig, __pyx_t_3) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 24; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (PyObject_SetAttr(__pyx_m, __pyx_n_s__InvalidConfig, __pyx_t_3) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 25; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
   __Pyx_DECREF(((PyObject *)__pyx_t_1)); __pyx_t_1 = 0;
 
-  /* "_cdec.pyx":25
+  /* "_cdec.pyx":26
  * 
  * class InvalidConfig(Exception): pass
  * class ParseFailed(Exception): pass             # <<<<<<<<<<<<<<
  * 
  * def _make_config(config):
  */
-  __pyx_t_1 = PyDict_New(); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 25; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_1 = PyDict_New(); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 26; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __Pyx_GOTREF(((PyObject *)__pyx_t_1));
-  __pyx_t_3 = PyTuple_New(1); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 25; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_3 = PyTuple_New(1); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 26; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __Pyx_GOTREF(__pyx_t_3);
   __Pyx_INCREF(__pyx_builtin_Exception);
   PyTuple_SET_ITEM(__pyx_t_3, 0, __pyx_builtin_Exception);
   __Pyx_GIVEREF(__pyx_builtin_Exception);
-  __pyx_t_2 = __Pyx_CreateClass(((PyObject *)__pyx_t_3), ((PyObject *)__pyx_t_1), __pyx_n_s__ParseFailed, __pyx_n_s___cdec); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 25; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_2 = __Pyx_CreateClass(((PyObject *)__pyx_t_3), ((PyObject *)__pyx_t_1), __pyx_n_s__ParseFailed, __pyx_n_s___cdec); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 26; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __Pyx_GOTREF(__pyx_t_2);
   __Pyx_DECREF(((PyObject *)__pyx_t_3)); __pyx_t_3 = 0;
-  if (PyObject_SetAttr(__pyx_m, __pyx_n_s__ParseFailed, __pyx_t_2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 25; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (PyObject_SetAttr(__pyx_m, __pyx_n_s__ParseFailed, __pyx_t_2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 26; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
   __Pyx_DECREF(((PyObject *)__pyx_t_1)); __pyx_t_1 = 0;
 
-  /* "_cdec.pyx":27
+  /* "_cdec.pyx":28
  * class ParseFailed(Exception): pass
  * 
  * def _make_config(config):             # <<<<<<<<<<<<<<
  *     for key, value in config.items():
  *         if isinstance(value, dict):
  */
-  __pyx_t_1 = PyCFunction_NewEx(&__pyx_mdef_5_cdec_3_make_config, NULL, __pyx_n_s___cdec); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 27; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_1 = PyCFunction_NewEx(&__pyx_mdef_5_cdec_3_make_config, NULL, __pyx_n_s___cdec); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 28; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __Pyx_GOTREF(__pyx_t_1);
-  if (PyObject_SetAttr(__pyx_m, __pyx_n_s___make_config, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 27; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (PyObject_SetAttr(__pyx_m, __pyx_n_s___make_config, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 28; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
 
   /* "_cdec.pyx":1
@@ -22187,6 +26182,10 @@ static CYTHON_INLINE int __Pyx_TypeTest(PyObject *obj, PyTypeObject *type) {
     return 0;
 }
 
+static CYTHON_INLINE void __Pyx_RaiseClosureNameError(const char *varname) {
+    PyErr_Format(PyExc_NameError, "free variable '%s' referenced before assignment in enclosing scope", varname);
+}
+
 static void __Pyx_RaiseDoubleKeywordsError(
     const char* func_name,
     PyObject* kw_name)
@@ -22302,35 +26301,7 @@ static void __Pyx_RaiseArgtupleInvalid(
                  (num_expected == 1) ? "" : "s", num_found);
 }
 
-static CYTHON_INLINE void __Pyx_RaiseClosureNameError(const char *varname) {
-    PyErr_Format(PyExc_NameError, "free variable '%s' referenced before assignment in enclosing scope", varname);
-}
 
-static CYTHON_INLINE PyObject *__Pyx_PyIter_Next2(PyObject* iterator, PyObject* defval) {
-    PyObject* next;
-    if (unlikely(!PyIter_Check(iterator))) {
-        PyErr_Format(PyExc_TypeError,
-            "%.200s object is not an iterator", iterator->ob_type->tp_name);
-        return NULL;
-    }
-    next = (*(Py_TYPE(iterator)->tp_iternext))(iterator);
-    if (likely(next)) {
-        return next;
-    } else if (defval) {
-        if (PyErr_Occurred()) {
-            if(!PyErr_ExceptionMatches(PyExc_StopIteration))
-                return NULL;
-            PyErr_Clear();
-        }
-        Py_INCREF(defval);
-        return defval;
-    } else if (PyErr_Occurred()) {
-        return NULL;
-    } else {
-        PyErr_SetNone(PyExc_StopIteration);
-        return NULL;
-    }
-}
 
 static CYTHON_INLINE void __Pyx_RaiseNeedMoreValuesError(Py_ssize_t index) {
     PyErr_Format(PyExc_ValueError,
@@ -22359,7 +26330,31 @@ static int __Pyx_IternextUnpackEndCheck(PyObject *retval, Py_ssize_t expected) {
     return 0;
 }
 
-
+static CYTHON_INLINE PyObject *__Pyx_PyIter_Next2(PyObject* iterator, PyObject* defval) {
+    PyObject* next;
+    if (unlikely(!PyIter_Check(iterator))) {
+        PyErr_Format(PyExc_TypeError,
+            "%.200s object is not an iterator", iterator->ob_type->tp_name);
+        return NULL;
+    }
+    next = (*(Py_TYPE(iterator)->tp_iternext))(iterator);
+    if (likely(next)) {
+        return next;
+    } else if (defval) {
+        if (PyErr_Occurred()) {
+            if(!PyErr_ExceptionMatches(PyExc_StopIteration))
+                return NULL;
+            PyErr_Clear();
+        }
+        Py_INCREF(defval);
+        return defval;
+    } else if (PyErr_Occurred()) {
+        return NULL;
+    } else {
+        PyErr_SetNone(PyExc_StopIteration);
+        return NULL;
+    }
+}
 
 static double __Pyx__PyObject_AsDouble(PyObject* obj) {
     PyObject* float_value;
@@ -22500,6 +26495,58 @@ static PyObject *__Pyx_CreateClass(PyObject *bases, PyObject *dict, PyObject *na
     return result;
 }
 
+static CYTHON_INLINE WordID __Pyx_PyInt_from_py_WordID(PyObject* x) {
+    const WordID neg_one = (WordID)-1, const_zero = (WordID)0;
+    const int is_unsigned = const_zero < neg_one;
+    if (sizeof(WordID) == sizeof(char)) {
+        if (is_unsigned)
+            return (WordID)__Pyx_PyInt_AsUnsignedChar(x);
+        else
+            return (WordID)__Pyx_PyInt_AsSignedChar(x);
+    } else if (sizeof(WordID) == sizeof(short)) {
+        if (is_unsigned)
+            return (WordID)__Pyx_PyInt_AsUnsignedShort(x);
+        else
+            return (WordID)__Pyx_PyInt_AsSignedShort(x);
+    } else if (sizeof(WordID) == sizeof(int)) {
+        if (is_unsigned)
+            return (WordID)__Pyx_PyInt_AsUnsignedInt(x);
+        else
+            return (WordID)__Pyx_PyInt_AsSignedInt(x);
+    } else if (sizeof(WordID) == sizeof(long)) {
+        if (is_unsigned)
+            return (WordID)__Pyx_PyInt_AsUnsignedLong(x);
+        else
+            return (WordID)__Pyx_PyInt_AsSignedLong(x);
+    } else if (sizeof(WordID) == sizeof(PY_LONG_LONG)) {
+        if (is_unsigned)
+            return (WordID)__Pyx_PyInt_AsUnsignedLongLong(x);
+        else
+            return (WordID)__Pyx_PyInt_AsSignedLongLong(x);
+    }  else {
+        WordID val;
+        PyObject *v = __Pyx_PyNumber_Int(x);
+        #if PY_VERSION_HEX < 0x03000000
+        if (likely(v) && !PyLong_Check(v)) {
+            PyObject *tmp = v;
+            v = PyNumber_Long(tmp);
+            Py_DECREF(tmp);
+        }
+        #endif
+        if (likely(v)) {
+            int one = 1; int is_little = (int)*(unsigned char *)&one;
+            unsigned char *bytes = (unsigned char *)&val;
+            int ret = _PyLong_AsByteArray((PyLongObject *)v,
+                                          bytes, sizeof(val),
+                                          is_little, !is_unsigned);
+            Py_DECREF(v);
+            if (likely(!ret))
+                return val;
+        }
+        return (WordID)-1;
+    }
+}
+
 static PyObject* __Pyx_Globals() {
     Py_ssize_t i;
     /*PyObject *d;*/
diff --git a/python/src/_cdec.pyx b/python/src/_cdec.pyx
index 164d6570..c60f342f 100644
--- a/python/src/_cdec.pyx
+++ b/python/src/_cdec.pyx
@@ -3,17 +3,18 @@ from libcpp.vector cimport vector
 from utils cimport *
 cimport decoder
 
-cdef char* as_str(sentence, error_msg='Cannot convert type %s to str'):
+cdef char* as_str(data, error_msg='Cannot convert type %s to str'):
     cdef bytes ret
-    if isinstance(sentence, unicode):
-        ret = sentence.encode('utf8')
-    elif isinstance(sentence, str):
-        ret = sentence
+    if isinstance(data, unicode):
+        ret = data.encode('utf8')
+    elif isinstance(data, str):
+        ret = data
     else:
-        raise TypeError(error_msg % type(sentence))
+        raise TypeError(error_msg % type(data))
     return ret
 
 include "vectors.pxi"
+include "grammar.pxi"
 include "hypergraph.pxi"
 include "lattice.pxi"
 include "mteval.pxi"
@@ -89,18 +90,20 @@ cdef class Decoder:
                 self.weights[fname.strip()] = float(value)
 
     def translate(self, sentence, grammar=None):
-        if isinstance(sentence, unicode):
-            inp = sentence.strip().encode('utf8')
-        elif isinstance(sentence, str):
-            inp = sentence.strip()
+        cdef bytes input_str
+        if isinstance(sentence, unicode) or isinstance(sentence, str):
+            input_str = as_str(sentence.strip())
         elif isinstance(sentence, Lattice):
-            inp = str(sentence) # PLF format
+            input_str = str(sentence) # PLF format
         else:
             raise TypeError('Cannot translate input type %s' % type(sentence))
         if grammar:
-            self.dec.AddSupplementalGrammarFromString(string(<char *> grammar))
+            if isinstance(grammar, str) or isinstance(grammar, unicode):
+                self.dec.AddSupplementalGrammarFromString(string(as_str(grammar)))
+            else:
+                self.dec.AddSupplementalGrammar(TextGrammar(grammar).grammar[0])
         cdef decoder.BasicObserver observer = decoder.BasicObserver()
-        self.dec.Decode(string(<char *>inp), &observer)
+        self.dec.Decode(string(input_str), &observer)
         if observer.hypergraph == NULL:
             raise ParseFailed()
         cdef Hypergraph hg = Hypergraph()
diff --git a/python/src/decoder.pxd b/python/src/decoder.pxd
index 660bcb39..d2065579 100644
--- a/python/src/decoder.pxd
+++ b/python/src/decoder.pxd
@@ -1,7 +1,8 @@
 from libcpp.string cimport string
 from libcpp.vector cimport vector
 from hypergraph cimport Hypergraph
-from utils cimport istream, weight_t, variables_map
+from grammar cimport Grammar
+from utils cimport *
 
 cdef extern from "decoder/ff_register.h":
     void register_feature_functions()
@@ -28,8 +29,8 @@ cdef extern from "decoder/decoder.h":
         # add grammar rules (currently only supported by SCFG decoders)
         # that will be used on subsequent calls to Decode. rules should be in standard
         # text format. This function does NOT read from a file.
-        void SetSupplementalGrammar(string& grammar)
-        void SetSentenceGrammarFromString(string& grammar_str)
+        void AddSupplementalGrammarFromString(string& grammar_str)
+        void AddSupplementalGrammar(shared_ptr[Grammar] grammar)
 
 cdef extern from "observer.h":
     cdef cppclass BasicObserver(DecoderObserver):
diff --git a/python/src/grammar.pxd b/python/src/grammar.pxd
new file mode 100644
index 00000000..43806f71
--- /dev/null
+++ b/python/src/grammar.pxd
@@ -0,0 +1,43 @@
+from libcpp.vector cimport vector
+from libcpp.string cimport string
+from utils cimport *
+
+cdef extern from "decoder/trule.h":
+
+    cdef cppclass AlignmentPoint:
+        AlignmentPoint(int s, int t)
+        AlignmentPoint Inverted()
+        short s_
+        short t_
+
+    cdef cppclass TRule:
+        vector[WordID] f_
+        vector[WordID] e_
+        vector[AlignmentPoint] a_
+        FastSparseVector[weight_t] scores_
+        WordID lhs_
+        int arity_
+        bint IsUnary()
+        bint IsGoal()
+        void ComputeArity()
+
+cdef extern from "decoder/grammar.h":
+    cdef cppclass RuleBin "const RuleBin":
+        int GetNumRules()
+        shared_ptr[TRule] GetIthRule(int i)
+        int Arity()
+
+    cdef cppclass GrammarIter "const GrammarIter":
+        RuleBin* GetRules()
+        GrammarIter* Extend(int symbol)
+
+    cdef cppclass Grammar:
+        GrammarIter* GetRoot()
+        bint HasRuleForSpan(int i, int j, int distance)
+        unsigned GetCTFLevels()
+        string GetGrammarName()
+        void SetGrammarName(string)
+
+    cdef cppclass TextGrammar(Grammar):
+        TextGrammar()
+        void AddRule(shared_ptr[TRule]& rule)
diff --git a/python/src/grammar.pxi b/python/src/grammar.pxi
new file mode 100644
index 00000000..80d9fbf5
--- /dev/null
+++ b/python/src/grammar.pxi
@@ -0,0 +1,176 @@
+cimport grammar
+
+def _phrase(phrase):
+    return ' '.join(w.encode('utf8') if isinstance(w, unicode) else str(w) for w in phrase)
+
+cdef class NT:
+    cdef public char* cat
+    cdef public unsigned ref
+    def __init__(self, cat, ref=0):
+        self.cat = cat
+        self.ref = ref
+
+    def __str__(self):
+        if self.ref > 0:
+            return '[%s,%d]' % (self.cat, self.ref)
+        return '[%s]' % self.cat
+
+cdef class NTRef:
+    cdef public unsigned ref
+    def __init__(self, ref):
+        self.ref = ref
+
+    def __str__(self):
+        return '[%d]' % self.ref
+
+cdef class BaseTRule:
+    cdef shared_ptr[grammar.TRule]* rule
+
+    def __dealloc__(self):
+        del self.rule
+
+    property arity:
+        def __get__(self):
+            return self.rule.get().arity_
+
+    property f:
+        def __get__(self):
+            cdef vector[WordID]* f_ = &self.rule.get().f_
+            cdef WordID w
+            cdef f = []
+            cdef unsigned i
+            cdef int idx = 0
+            for i in range(f_.size()):
+                w = f_[0][i]
+                if w < 0:
+                    idx += 1
+                    f.append(NT(TDConvert(-w), idx))
+                else:
+                    f.append(unicode(TDConvert(w), encoding='utf8'))
+            return f
+
+        def __set__(self, f):
+            cdef vector[WordID]* f_ = &self.rule.get().f_
+            f_.resize(len(f))
+            cdef unsigned i
+            cdef int idx = 0
+            for i in range(len(f)):
+                if isinstance(f[i], NT):
+                    f_[0][i] = -TDConvert(<char *>f[i].cat)
+                else:
+                    f_[0][i] = TDConvert(<char *>as_str(f[i]))
+
+    property e:
+        def __get__(self):
+            cdef vector[WordID]* e_ = &self.rule.get().e_
+            cdef WordID w
+            cdef e = []
+            cdef unsigned i
+            cdef int idx = 0
+            for i in range(e_.size()):
+                w = e_[0][i]
+                if w < 1:
+                    idx += 1
+                    e.append(NTRef(1-w))
+                else:
+                    e.append(unicode(TDConvert(w), encoding='utf8'))
+            return e
+
+        def __set__(self, e):
+            cdef vector[WordID]* e_ = &self.rule.get().e_
+            e_.resize(len(e))
+            cdef unsigned i
+            for i in range(len(e)):
+                if isinstance(e[i], NTRef):
+                    e_[0][i] = 1-e[i].ref
+                else:
+                    e_[0][i] = TDConvert(<char *>as_str(e[i]))
+
+    property a:
+        def __get__(self):
+            cdef unsigned i
+            cdef vector[grammar.AlignmentPoint]* a = &self.rule.get().a_
+            for i in range(a.size()):
+                yield (a[0][i].s_, a[0][i].t_)
+
+        def __set__(self, a):
+            cdef vector[grammar.AlignmentPoint]* a_ = &self.rule.get().a_
+            a_.resize(len(a))
+            cdef unsigned i
+            cdef int s, t
+            for i in range(len(a)):
+                s, t = a[i]
+                a_[0][i] = grammar.AlignmentPoint(s, t)
+
+    property scores:
+        def __get__(self):
+            cdef SparseVector scores = SparseVector()
+            scores.vector = new FastSparseVector[double](self.rule.get().scores_)
+            return scores
+
+        def __set__(self, scores):
+            cdef FastSparseVector[double]* scores_ = &self.rule.get().scores_
+            scores_.clear()
+            cdef int fid
+            cdef float fval
+            for fname, fval in scores.items():
+                fid = FDConvert(<char *>as_str(fname))
+                if fid < 0: raise KeyError(fname)
+                scores_.set_value(fid, fval)
+
+    property lhs:
+        def __get__(self):
+            return NT(TDConvert(-self.rule.get().lhs_))
+
+        def __set__(self, lhs):
+            if not isinstance(lhs, NT):
+                lhs = NT(lhs)
+            self.rule.get().lhs_ = -TDConvert(<char *>lhs.cat)
+
+    def __str__(self):
+        scores = ' '.join('%s=%s' % feat for feat in self.scores)
+        return '%s ||| %s ||| %s ||| %s' % (self.lhs,
+                _phrase(self.f), _phrase(self.e), scores)
+
+cdef class TRule(BaseTRule):
+    def __cinit__(self, lhs, f, e, scores, a=None):
+        self.rule = new shared_ptr[grammar.TRule](new grammar.TRule())
+        self.lhs = lhs
+        self.e = e
+        self.f = f
+        self.scores = scores
+        if a:
+            self.a = a
+        self.rule.get().ComputeArity()
+
+cdef class Grammar:
+    cdef shared_ptr[grammar.Grammar]* grammar
+    
+    def __dealloc__(self):
+        del self.grammar
+    
+    def __iter__(self):
+        cdef grammar.GrammarIter* root = self.grammar.get().GetRoot()
+        cdef grammar.RuleBin* rbin = root.GetRules()
+        cdef TRule trule
+        cdef unsigned i
+        for i in range(rbin.GetNumRules()):
+            trule = TRule()
+            trule.rule = new shared_ptr[grammar.TRule](rbin.GetIthRule(i))
+            yield trule
+
+    property name:
+        def __get__(self):
+            self.grammar.get().GetGrammarName().c_str()
+
+        def __set__(self, name):
+            self.grammar.get().SetGrammarName(string(<char *>name))
+
+cdef class TextGrammar(Grammar):
+    def __cinit__(self, rules):
+        self.grammar = new shared_ptr[grammar.Grammar](new grammar.TextGrammar())
+        cdef grammar.TextGrammar* _g = <grammar.TextGrammar*> self.grammar.get()
+        for trule in rules:
+            if not isinstance(trule, BaseTRule):
+                raise ValueError('the grammar should contain TRule objects')
+            _g.AddRule((<BaseTRule> trule).rule[0])
diff --git a/python/src/hypergraph.pxd b/python/src/hypergraph.pxd
index 14c60dd0..e51ccf5c 100644
--- a/python/src/hypergraph.pxd
+++ b/python/src/hypergraph.pxd
@@ -1,18 +1,9 @@
 from libcpp.string cimport string
 from libcpp.vector cimport vector
 from utils cimport *
+from grammar cimport TRule
 from lattice cimport Lattice
 
-cdef extern from "decoder/trule.h":
-    cdef cppclass TRule:
-        vector[WordID] f_
-        vector[WordID] e_
-        FastSparseVector[weight_t] scores_
-        WordID lhs_
-        int arity_
-        bint IsUnary()
-        bint IsGoal()
-
 cdef extern from "decoder/hg.h":
     cdef cppclass EdgeMask "std::vector<bool>":
         EdgeMask(int size)
@@ -40,6 +31,7 @@ cdef extern from "decoder/hg.h":
         vector[HypergraphNode] nodes_
         vector[HypergraphEdge] edges_
         int GoalNode()
+        double NumberOfPaths()
         void Reweight(vector[weight_t]& weights)
         void Reweight(FastSparseVector& weights)
         bint PruneInsideOutside(double beam_alpha,
@@ -83,3 +75,6 @@ cdef extern from "decoder/hg_sampler.h" namespace "HypergraphSampler":
 
 cdef extern from "decoder/csplit.h" namespace "CompoundSplit":
     int GetFullWordEdgeIndex(Hypergraph& forest)
+
+cdef extern from "decoder/inside_outside.h":
+    LogVal[double] InsideOutside "InsideOutside<prob_t, EdgeProb, SparseVector<prob_t>, EdgeFeaturesAndProbWeightFunction>" (Hypergraph& hg, FastSparseVector[LogVal[double]]* result)
diff --git a/python/src/hypergraph.pxi b/python/src/hypergraph.pxi
index 2e2c04a2..86751cc9 100644
--- a/python/src/hypergraph.pxi
+++ b/python/src/hypergraph.pxi
@@ -109,8 +109,6 @@ cdef class Hypergraph:
         else:
             raise TypeError('cannot reweight hypergraph with %s' % type(weights))
 
-    # TODO get feature expectations, get partition function ("inside" score)
-
     property edges:
         def __get__(self):
             cdef unsigned i
@@ -127,19 +125,35 @@ cdef class Hypergraph:
         def __get__(self):
             return HypergraphNode().init(self.hg, self.hg.GoalNode())
 
-
-include "trule.pxi"
+    property npaths:
+        def __get__(self):
+            return self.hg.NumberOfPaths()
+
+    def inside_outside(self):
+        cdef FastSparseVector[LogVal[double]]* result = new FastSparseVector[LogVal[double]]()
+        cdef LogVal[double] z = hypergraph.InsideOutside(self.hg[0], result)
+        result[0] /= z
+        cdef SparseVector vector = SparseVector()
+        vector.vector = new FastSparseVector[double]()
+        cdef FastSparseVector[LogVal[double]].const_iterator* it = new FastSparseVector[LogVal[double]].const_iterator(result[0], False)
+        cdef unsigned i
+        for i in range(result.size()):
+            vector.vector.set_value(it[0].ptr().first, log(it[0].ptr().second))
+            pinc(it[0]) # ++it
+        del it
+        del result
+        return vector
 
 cdef class HypergraphEdge:
     cdef hypergraph.Hypergraph* hg
     cdef hypergraph.HypergraphEdge* edge
-    cdef public TRule trule
+    cdef public BaseTRule trule
 
     cdef init(self, hypergraph.Hypergraph* hg, unsigned i):
         self.hg = hg
         self.edge = &hg.edges_[i]
-        self.trule = TRule()
-        self.trule.rule = self.edge.rule_.get()
+        self.trule = BaseTRule()
+        self.trule.rule = new shared_ptr[grammar.TRule](self.edge.rule_)
         return self
 
     def __len__(self):
diff --git a/python/src/lattice.pxi b/python/src/lattice.pxi
index c6b29e8b..08405188 100644
--- a/python/src/lattice.pxi
+++ b/python/src/lattice.pxi
@@ -3,7 +3,7 @@ cimport lattice
 cdef class Lattice:
     cdef lattice.Lattice* lattice
 
-    def __init__(self, inp):
+    def __cinit__(self, inp):
         if isinstance(inp, tuple):
             self.lattice = new lattice.Lattice(len(inp))
             for i, arcs in enumerate(inp):
diff --git a/python/src/trule.pxi b/python/src/trule.pxi
deleted file mode 100644
index 6168014d..00000000
--- a/python/src/trule.pxi
+++ /dev/null
@@ -1,55 +0,0 @@
-def _phrase(phrase):
-    return ' '.join('[%s,%d]' % w if isinstance(w, tuple) else w.encode('utf8') for w in phrase)
-
-cdef class TRule:
-    cdef hypergraph.TRule* rule
-
-    property arity:
-        def __get__(self):
-            return self.rule.arity_
-
-    property f:
-        def __get__(self):
-            cdef vector[WordID]* f = &self.rule.f_
-            cdef WordID w
-            cdef words = []
-            cdef unsigned i
-            cdef int idx = 0
-            for i in range(f.size()):
-                w = f[0][i]
-                if w < 0:
-                    idx += 1
-                    words.append((TDConvert(-w), idx))
-                else:
-                    words.append(unicode(TDConvert(w), encoding='utf8'))
-            return words
-
-    property e:
-        def __get__(self):
-            cdef vector[WordID]* e = &self.rule.e_
-            cdef WordID w
-            cdef words = []
-            cdef unsigned i
-            cdef int idx = 0
-            for i in range(e.size()):
-                w = e[0][i]
-                if w < 1:
-                    idx += 1
-                    words.append((TDConvert(1-w), idx))
-                else:
-                    words.append(unicode(TDConvert(w), encoding='utf8'))
-            return words
-
-    property scores:
-        def __get__(self):
-            cdef SparseVector scores = SparseVector()
-            scores.vector = new FastSparseVector[double](self.rule.scores_)
-            return scores
-
-    property lhs:
-        def __get__(self):
-            return TDConvert(-self.rule.lhs_)
-
-    def __str__(self):
-        scores = ' '.join('%s=%s' % feat for feat in self.scores)
-        return '[%s] ||| %s ||| %s ||| %s' % (self.lhs, _phrase(self.f), _phrase(self.e), scores)
diff --git a/python/src/utils.pxd b/python/src/utils.pxd
index 15e77c49..f4da686b 100644
--- a/python/src/utils.pxd
+++ b/python/src/utils.pxd
@@ -47,6 +47,7 @@ cdef extern from "utils/sparse_vector.h":
         bint operator==(FastSparseVector[T]&)
         T dot(vector[weight_t]&) # cython bug when [T]
         T dot(FastSparseVector[T]&)
+        void clear()
 
     FastSparseVector[weight_t] operator+(FastSparseVector[weight_t]&, FastSparseVector[weight_t]&)
     FastSparseVector[weight_t] operator-(FastSparseVector[weight_t]&, FastSparseVector[weight_t]&)
@@ -82,6 +83,7 @@ cdef extern from "utils/sampler.h":
 
 cdef extern from "<boost/shared_ptr.hpp>" namespace "boost":
     cdef cppclass shared_ptr[T]:
+        shared_ptr(T* ptr)
         shared_ptr(shared_ptr& r)
         T* get()
 
diff --git a/python/src/vectors.pxi b/python/src/vectors.pxi
index ce95968c..cd1c2598 100644
--- a/python/src/vectors.pxi
+++ b/python/src/vectors.pxi
@@ -54,6 +54,7 @@ cdef class SparseVector:
 
     def __iter__(self):
         cdef FastSparseVector[weight_t].const_iterator* it = new FastSparseVector[weight_t].const_iterator(self.vector[0], False)
+        cdef unsigned i
         try:
             for i in range(self.vector.size()):
                 yield (FDConvert(it[0].ptr().first).c_str(), it[0].ptr().second)
diff --git a/python/test.py b/python/test.py
index 54859e81..eb9e6a95 100644
--- a/python/test.py
+++ b/python/test.py
@@ -45,6 +45,9 @@ for sentence in forest.sample(5):
 # Get feature vector for 1best
 fsrc = forest.viterbi_features()
 
+# Feature expectations
+print 'Feature expectations:', dict(forest.inside_outside())
+
 # Reference lattice
 lattice = ((('australia',0,1),),(('is',0,1),),(('one',0,1),),(('of',0,1),),(('the',0,4),('a',0,4),('a',0,1),('the',0,1),),(('small',0,1),('tiny',0,1),('miniscule',0,1),('handful',0,2),),(('number',0,1),('group',0,1),),(('of',0,2),),(('few',0,1),),(('countries',0,1),),(('that',0,1),),(('has',0,1),('have',0,1),),(('diplomatic',0,1),),(('relations',0,1),),(('with',0,1),),(('north',0,1),),(('korea',0,1),),(('.',0,1),),)
 
-- 
cgit v1.2.3


From eeef93717fed2901f6fcd2e3fd11118e0e309af7 Mon Sep 17 00:00:00 2001
From: Victor Chahuneau <vchahune@cs.cmu.edu>
Date: Mon, 23 Jul 2012 19:59:44 -0400
Subject: [python] Evaluation metrics in Python

---
 python/cdec/__init__.py |    2 +-
 python/cdec/score.py    |    2 +-
 python/src/_cdec.cpp    | 1685 +++++++++++++++++++++++++++++++++++++----------
 python/src/decoder.pxd  |    2 -
 python/src/grammar.pxd  |    1 -
 python/src/mteval.pxd   |   13 +-
 python/src/mteval.pxi   |   59 +-
 python/src/observer.h   |    1 -
 python/src/py_scorer.h  |   44 ++
 sa-extract/Makefile     |   10 +-
 10 files changed, 1462 insertions(+), 357 deletions(-)
 create mode 100644 python/src/py_scorer.h

(limited to 'python/cdec/__init__.py')

diff --git a/python/cdec/__init__.py b/python/cdec/__init__.py
index 89c323ba..19058493 100644
--- a/python/cdec/__init__.py
+++ b/python/cdec/__init__.py
@@ -1 +1 @@
-from _cdec import Decoder, Lattice, TRule, NT, NTRef
+from _cdec import Decoder, Lattice, TRule, NT, NTRef, ParseFailed, InvalidConfig
diff --git a/python/cdec/score.py b/python/cdec/score.py
index c107446f..d9486ef2 100644
--- a/python/cdec/score.py
+++ b/python/cdec/score.py
@@ -1 +1 @@
-from _cdec import BLEU, TER
+from _cdec import BLEU, TER, Metric
diff --git a/python/src/_cdec.cpp b/python/src/_cdec.cpp
index 3c95ca50..6d704b1d 100644
--- a/python/src/_cdec.cpp
+++ b/python/src/_cdec.cpp
@@ -1,4 +1,4 @@
-/* Generated by Cython 0.16 on Fri Jul 20 18:16:48 2012 */
+/* Generated by Cython 0.16 on Mon Jul 23 19:56:55 2012 */
 
 #define PY_SSIZE_T_CLEAN
 #include "Python.h"
@@ -301,6 +301,7 @@
 #include "observer.h"
 #include "decoder/kbest.h"
 #include "mteval/ns.h"
+#include "py_scorer.h"
 #include "training/candidate_set.h"
 #ifdef _OPENMP
 #include <omp.h>
@@ -423,6 +424,7 @@ struct __pyx_obj_5_cdec___pyx_scope_struct_12___get__;
 struct __pyx_obj_5_cdec___pyx_scope_struct_21___iter__;
 struct __pyx_obj_5_cdec_DenseVector;
 struct __pyx_obj_5_cdec___pyx_scope_struct_7___iter__;
+struct __pyx_obj_5_cdec_Metric;
 struct __pyx_obj_5_cdec_SufficientStats;
 struct __pyx_obj_5_cdec___pyx_scope_struct_8_kbest;
 struct __pyx_obj_5_cdec___pyx_scope_struct_10_kbest_features;
@@ -450,16 +452,17 @@ struct __pyx_opt_args_5_cdec_as_str {
   PyObject *error_msg;
 };
 
-/* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":112
+/* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":117
  *         return CandidateSet(self)
  * 
  * cdef class Scorer:             # <<<<<<<<<<<<<<
  *     cdef string* name
- * 
+ *     cdef mteval.EvaluationMetric* metric
  */
 struct __pyx_obj_5_cdec_Scorer {
   PyObject_HEAD
   std::string *name;
+  EvaluationMetric *metric;
 };
 
 
@@ -561,7 +564,7 @@ struct __pyx_obj_5_cdec___pyx_scope_struct_2__phrase {
 };
 
 
-/* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":60
+/* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":65
  *         return result
  * 
  * cdef class CandidateSet:             # <<<<<<<<<<<<<<
@@ -634,7 +637,7 @@ struct __pyx_obj_5_cdec___pyx_scope_struct_3_genexpr {
 };
 
 
-/* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":93
+/* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":98
  *         self.cs.AddKBestCandidates(hypergraph.hg[0], k, self.scorer.get())
  * 
  * cdef class SegmentEvaluator:             # <<<<<<<<<<<<<<
@@ -653,7 +656,7 @@ struct __pyx_obj_5_cdec_SegmentEvaluator {
  * 
  *     def __iter__(self):             # <<<<<<<<<<<<<<
  *         for i in range(len(self)):
- *             yield self.stats[0][i]
+ *             yield self[i]
  */
 struct __pyx_obj_5_cdec___pyx_scope_struct_20___iter__ {
   PyObject_HEAD
@@ -850,7 +853,7 @@ struct __pyx_obj_5_cdec___pyx_scope_struct_12___get__ {
 };
 
 
-/* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":85
+/* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":90
  *         return candidate
  * 
  *     def __iter__(self):             # <<<<<<<<<<<<<<
@@ -898,6 +901,19 @@ struct __pyx_obj_5_cdec___pyx_scope_struct_7___iter__ {
 };
 
 
+/* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":173
+ *         out.fields[i] = ss[i]
+ * 
+ * cdef class Metric:             # <<<<<<<<<<<<<<
+ *     cdef Scorer scorer
+ *     def __cinit__(self):
+ */
+struct __pyx_obj_5_cdec_Metric {
+  PyObject_HEAD
+  struct __pyx_obj_5_cdec_Scorer *scorer;
+};
+
+
 /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":26
  *             return fmap
  * 
@@ -1330,6 +1346,8 @@ static CYTHON_INLINE PyObject* __Pyx_PyBoolOrNull_FromLong(long b) {
 #define __Pyx_PyIter_Next(obj) __Pyx_PyIter_Next2(obj, NULL);
 static CYTHON_INLINE PyObject *__Pyx_PyIter_Next2(PyObject *, PyObject *); /*proto*/
 
+static CYTHON_INLINE int __Pyx_CheckKeywordStrings(PyObject *kwdict, const char* function_name, int kw_allowed); /*proto*/
+
 static double __Pyx__PyObject_AsDouble(PyObject* obj); /* proto */
 #define __Pyx_PyObject_AsDouble(obj) \
 ((likely(PyFloat_CheckExact(obj))) ? \
@@ -1523,6 +1541,7 @@ static PyTypeObject *__pyx_ptype_5_cdec_SufficientStats = 0;
 static PyTypeObject *__pyx_ptype_5_cdec_CandidateSet = 0;
 static PyTypeObject *__pyx_ptype_5_cdec_SegmentEvaluator = 0;
 static PyTypeObject *__pyx_ptype_5_cdec_Scorer = 0;
+static PyTypeObject *__pyx_ptype_5_cdec_Metric = 0;
 static PyTypeObject *__pyx_ptype_5_cdec_Decoder = 0;
 static PyTypeObject *__pyx_ptype_5_cdec___pyx_scope_struct____iter__ = 0;
 static PyTypeObject *__pyx_ptype_5_cdec___pyx_scope_struct_1___iter__ = 0;
@@ -1551,6 +1570,8 @@ static PyTypeObject *__pyx_ptype_5_cdec___pyx_scope_struct_23___cinit__ = 0;
 static PyTypeObject *__pyx_ptype_5_cdec___pyx_scope_struct_24_genexpr = 0;
 static char *__pyx_f_5_cdec_as_str(PyObject *, struct __pyx_opt_args_5_cdec_as_str *__pyx_optional_args); /*proto*/
 static struct __pyx_obj_5_cdec_SufficientStats *__pyx_f_5_cdec_as_stats(PyObject *, PyObject *); /*proto*/
+static float __pyx_f_5_cdec__compute_score(void *, SufficientStats *); /*proto*/
+static void __pyx_f_5_cdec__compute_sufficient_stats(void *, std::string *, std::vector<std::string> *, SufficientStats *); /*proto*/
 #define __Pyx_MODULE_NAME "_cdec"
 int __pyx_module_is_main__cdec = 0;
 
@@ -1676,8 +1697,9 @@ static PyObject *__pyx_pf_5_cdec_15SufficientStats_5score___get__(struct __pyx_o
 static PyObject *__pyx_pf_5_cdec_15SufficientStats_6detail___get__(struct __pyx_obj_5_cdec_SufficientStats *__pyx_v_self); /* proto */
 static Py_ssize_t __pyx_pf_5_cdec_15SufficientStats_2__len__(struct __pyx_obj_5_cdec_SufficientStats *__pyx_v_self); /* proto */
 static PyObject *__pyx_pf_5_cdec_15SufficientStats_4__iter__(struct __pyx_obj_5_cdec_SufficientStats *__pyx_v_self); /* proto */
-static PyObject *__pyx_pf_5_cdec_15SufficientStats_7__iadd__(struct __pyx_obj_5_cdec_SufficientStats *__pyx_v_self, struct __pyx_obj_5_cdec_SufficientStats *__pyx_v_other); /* proto */
-static PyObject *__pyx_pf_5_cdec_15SufficientStats_9__add__(PyObject *__pyx_v_x, PyObject *__pyx_v_y); /* proto */
+static PyObject *__pyx_pf_5_cdec_15SufficientStats_7__getitem__(struct __pyx_obj_5_cdec_SufficientStats *__pyx_v_self, int __pyx_v_index); /* proto */
+static PyObject *__pyx_pf_5_cdec_15SufficientStats_9__iadd__(struct __pyx_obj_5_cdec_SufficientStats *__pyx_v_self, struct __pyx_obj_5_cdec_SufficientStats *__pyx_v_other); /* proto */
+static PyObject *__pyx_pf_5_cdec_15SufficientStats_11__add__(PyObject *__pyx_v_x, PyObject *__pyx_v_y); /* proto */
 static int __pyx_pf_5_cdec_12CandidateSet___cinit__(struct __pyx_obj_5_cdec_CandidateSet *__pyx_v_self, struct __pyx_obj_5_cdec_SegmentEvaluator *__pyx_v_evaluator); /* proto */
 static void __pyx_pf_5_cdec_12CandidateSet_2__dealloc__(CYTHON_UNUSED struct __pyx_obj_5_cdec_CandidateSet *__pyx_v_self); /* proto */
 static Py_ssize_t __pyx_pf_5_cdec_12CandidateSet_4__len__(struct __pyx_obj_5_cdec_CandidateSet *__pyx_v_self); /* proto */
@@ -1687,10 +1709,14 @@ static PyObject *__pyx_pf_5_cdec_12CandidateSet_11add_kbest(struct __pyx_obj_5_c
 static void __pyx_pf_5_cdec_16SegmentEvaluator___dealloc__(CYTHON_UNUSED struct __pyx_obj_5_cdec_SegmentEvaluator *__pyx_v_self); /* proto */
 static PyObject *__pyx_pf_5_cdec_16SegmentEvaluator_2evaluate(struct __pyx_obj_5_cdec_SegmentEvaluator *__pyx_v_self, PyObject *__pyx_v_sentence); /* proto */
 static PyObject *__pyx_pf_5_cdec_16SegmentEvaluator_4candidate_set(struct __pyx_obj_5_cdec_SegmentEvaluator *__pyx_v_self); /* proto */
-static int __pyx_pf_5_cdec_6Scorer___cinit__(struct __pyx_obj_5_cdec_Scorer *__pyx_v_self, char *__pyx_v_name); /* proto */
+static int __pyx_pf_5_cdec_6Scorer___cinit__(struct __pyx_obj_5_cdec_Scorer *__pyx_v_self, PyObject *__pyx_v_name); /* proto */
 static void __pyx_pf_5_cdec_6Scorer_2__dealloc__(CYTHON_UNUSED struct __pyx_obj_5_cdec_Scorer *__pyx_v_self); /* proto */
 static PyObject *__pyx_pf_5_cdec_6Scorer_4__call__(struct __pyx_obj_5_cdec_Scorer *__pyx_v_self, PyObject *__pyx_v_refs); /* proto */
 static PyObject *__pyx_pf_5_cdec_6Scorer_6__str__(struct __pyx_obj_5_cdec_Scorer *__pyx_v_self); /* proto */
+static int __pyx_pf_5_cdec_6Metric___cinit__(struct __pyx_obj_5_cdec_Metric *__pyx_v_self); /* proto */
+static PyObject *__pyx_pf_5_cdec_6Metric_2__call__(struct __pyx_obj_5_cdec_Metric *__pyx_v_self, PyObject *__pyx_v_refs); /* proto */
+static PyObject *__pyx_pf_5_cdec_6Metric_4score(CYTHON_UNUSED struct __pyx_obj_5_cdec_Metric *__pyx_v_stats); /* proto */
+static PyObject *__pyx_pf_5_cdec_6Metric_6evaluate(CYTHON_UNUSED struct __pyx_obj_5_cdec_Metric *__pyx_v_self, CYTHON_UNUSED PyObject *__pyx_v_hyp, CYTHON_UNUSED PyObject *__pyx_v_refs); /* proto */
 static PyObject *__pyx_pf_5_cdec_2_make_config(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_config); /* proto */
 static PyObject *__pyx_pf_5_cdec_7Decoder_9__cinit___genexpr(PyObject *__pyx_self); /* proto */
 static int __pyx_pf_5_cdec_7Decoder___cinit__(struct __pyx_obj_5_cdec_Decoder *__pyx_v_self, PyObject *__pyx_v_config_str, PyObject *__pyx_v_config); /* proto */
@@ -1726,15 +1752,16 @@ static char __pyx_k_27[] = "digraph lattice {";
 static char __pyx_k_35[] = "}";
 static char __pyx_k_38[] = "/Users/vchahun/Sandbox/cdec/python/src/lattice.pxi";
 static char __pyx_k_39[] = "\n";
-static char __pyx_k_41[] = "candidate set index out of range";
-static char __pyx_k_43[] = "%s %s";
-static char __pyx_k_44[] = "%s = %s";
-static char __pyx_k_46[] = "formalism \"%s\" unknown";
-static char __pyx_k_47[] = "cannot initialize weights with %s";
-static char __pyx_k_48[] = "#";
-static char __pyx_k_51[] = "Cannot translate input type %s";
-static char __pyx_k_54[] = "/Users/vchahun/Sandbox/cdec/python/src/grammar.pxi";
-static char __pyx_k_59[] = "/Users/vchahun/Sandbox/cdec/python/src/_cdec.pyx";
+static char __pyx_k_41[] = "sufficient stats vector index out of range";
+static char __pyx_k_43[] = "candidate set index out of range";
+static char __pyx_k_45[] = "%s %s";
+static char __pyx_k_46[] = "%s = %s";
+static char __pyx_k_48[] = "formalism \"%s\" unknown";
+static char __pyx_k_49[] = "cannot initialize weights with %s";
+static char __pyx_k_50[] = "#";
+static char __pyx_k_53[] = "Cannot translate input type %s";
+static char __pyx_k_56[] = "/Users/vchahun/Sandbox/cdec/python/src/grammar.pxi";
+static char __pyx_k_61[] = "/Users/vchahun/Sandbox/cdec/python/src/_cdec.pyx";
 static char __pyx_k__a[] = "a";
 static char __pyx_k__e[] = "e";
 static char __pyx_k__f[] = "f";
@@ -1746,6 +1773,7 @@ static char __pyx_k__cat[] = "cat";
 static char __pyx_k__dot[] = "dot";
 static char __pyx_k__fst[] = "fst";
 static char __pyx_k__get[] = "get";
+static char __pyx_k__hyp[] = "hyp";
 static char __pyx_k__inp[] = "inp";
 static char __pyx_k__key[] = "key";
 static char __pyx_k__lhs[] = "lhs";
@@ -1769,6 +1797,7 @@ static char __pyx_k__label[] = "label";
 static char __pyx_k__lines[] = "lines";
 static char __pyx_k__range[] = "range";
 static char __pyx_k__rules[] = "rules";
+static char __pyx_k__score[] = "score";
 static char __pyx_k__split[] = "split";
 static char __pyx_k__strip[] = "strip";
 static char __pyx_k__value[] = "value";
@@ -1788,14 +1817,17 @@ static char __pyx_k__IBM_BLEU[] = "IBM_BLEU";
 static char __pyx_k__KeyError[] = "KeyError";
 static char __pyx_k____exit__[] = "__exit__";
 static char __pyx_k____main__[] = "__main__";
+static char __pyx_k____name__[] = "__name__";
 static char __pyx_k____test__[] = "__test__";
 static char __pyx_k__encoding[] = "encoding";
+static char __pyx_k__evaluate[] = "evaluate";
 static char __pyx_k__in_edges[] = "in_edges";
 static char __pyx_k__lexalign[] = "lexalign";
 static char __pyx_k__lextrans[] = "lextrans";
 static char __pyx_k__sentence[] = "sentence";
 static char __pyx_k__Exception[] = "Exception";
 static char __pyx_k__TypeError[] = "TypeError";
+static char __pyx_k____class__[] = "__class__";
 static char __pyx_k____enter__[] = "__enter__";
 static char __pyx_k__enumerate[] = "enumerate";
 static char __pyx_k__evaluator[] = "evaluator";
@@ -1835,13 +1867,14 @@ static PyObject *__pyx_kp_s_39;
 static PyObject *__pyx_kp_s_4;
 static PyObject *__pyx_kp_s_41;
 static PyObject *__pyx_kp_s_43;
-static PyObject *__pyx_kp_s_44;
+static PyObject *__pyx_kp_s_45;
 static PyObject *__pyx_kp_s_46;
-static PyObject *__pyx_kp_s_47;
 static PyObject *__pyx_kp_s_48;
-static PyObject *__pyx_kp_s_51;
-static PyObject *__pyx_kp_s_54;
-static PyObject *__pyx_kp_s_59;
+static PyObject *__pyx_kp_s_49;
+static PyObject *__pyx_kp_s_50;
+static PyObject *__pyx_kp_s_53;
+static PyObject *__pyx_kp_s_56;
+static PyObject *__pyx_kp_s_61;
 static PyObject *__pyx_kp_s_7;
 static PyObject *__pyx_kp_s_8;
 static PyObject *__pyx_kp_s_9;
@@ -1856,9 +1889,11 @@ static PyObject *__pyx_n_s__ParseFailed;
 static PyObject *__pyx_n_s__TER;
 static PyObject *__pyx_n_s__TypeError;
 static PyObject *__pyx_n_s__ValueError;
+static PyObject *__pyx_n_s____class__;
 static PyObject *__pyx_n_s____enter__;
 static PyObject *__pyx_n_s____exit__;
 static PyObject *__pyx_n_s____main__;
+static PyObject *__pyx_n_s____name__;
 static PyObject *__pyx_n_s____test__;
 static PyObject *__pyx_n_s___cdec;
 static PyObject *__pyx_n_s___make_config;
@@ -1877,6 +1912,7 @@ static PyObject *__pyx_n_s__encode;
 static PyObject *__pyx_n_s__encoding;
 static PyObject *__pyx_n_s__enumerate;
 static PyObject *__pyx_n_s__eval;
+static PyObject *__pyx_n_s__evaluate;
 static PyObject *__pyx_n_s__evaluator;
 static PyObject *__pyx_n_s__f;
 static PyObject *__pyx_n_s__formalism;
@@ -1884,6 +1920,7 @@ static PyObject *__pyx_n_s__fst;
 static PyObject *__pyx_n_s__genexpr;
 static PyObject *__pyx_n_s__get;
 static PyObject *__pyx_n_s__grammar;
+static PyObject *__pyx_n_s__hyp;
 static PyObject *__pyx_n_s__hypergraph;
 static PyObject *__pyx_n_s__i;
 static PyObject *__pyx_n_s__in_edges;
@@ -1909,6 +1946,7 @@ static PyObject *__pyx_n_s__refs;
 static PyObject *__pyx_n_s__replace;
 static PyObject *__pyx_n_s__rules;
 static PyObject *__pyx_n_s__scfg;
+static PyObject *__pyx_n_s__score;
 static PyObject *__pyx_n_s__scores;
 static PyObject *__pyx_n_s__self;
 static PyObject *__pyx_n_s__sentence;
@@ -1936,16 +1974,17 @@ static PyObject *__pyx_k_tuple_33;
 static PyObject *__pyx_k_tuple_36;
 static PyObject *__pyx_k_tuple_40;
 static PyObject *__pyx_k_tuple_42;
-static PyObject *__pyx_k_tuple_45;
-static PyObject *__pyx_k_tuple_49;
-static PyObject *__pyx_k_tuple_50;
+static PyObject *__pyx_k_tuple_44;
+static PyObject *__pyx_k_tuple_47;
+static PyObject *__pyx_k_tuple_51;
 static PyObject *__pyx_k_tuple_52;
-static PyObject *__pyx_k_tuple_55;
-static PyObject *__pyx_k_tuple_56;
+static PyObject *__pyx_k_tuple_54;
 static PyObject *__pyx_k_tuple_57;
+static PyObject *__pyx_k_tuple_58;
+static PyObject *__pyx_k_tuple_59;
 static PyObject *__pyx_k_codeobj_37;
-static PyObject *__pyx_k_codeobj_53;
-static PyObject *__pyx_k_codeobj_58;
+static PyObject *__pyx_k_codeobj_55;
+static PyObject *__pyx_k_codeobj_60;
 
 /* "_cdec.pyx":6
  * cimport decoder
@@ -7390,7 +7429,7 @@ static int __pyx_pf_5_cdec_11TextGrammar___cinit__(struct __pyx_obj_5_cdec_TextG
  *         for trule in rules:
  *             if not isinstance(trule, BaseTRule):             # <<<<<<<<<<<<<<
  *                 raise ValueError('the grammar should contain TRule objects')
- *             _g.AddRule((<TRule> trule).rule[0])
+ *             _g.AddRule((<BaseTRule> trule).rule[0])
  */
     __pyx_t_4 = ((PyObject *)((PyObject*)__pyx_ptype_5_cdec_BaseTRule));
     __Pyx_INCREF(__pyx_t_4);
@@ -7403,7 +7442,7 @@ static int __pyx_pf_5_cdec_11TextGrammar___cinit__(struct __pyx_obj_5_cdec_TextG
  *         for trule in rules:
  *             if not isinstance(trule, BaseTRule):
  *                 raise ValueError('the grammar should contain TRule objects')             # <<<<<<<<<<<<<<
- *             _g.AddRule((<TRule> trule).rule[0])
+ *             _g.AddRule((<BaseTRule> trule).rule[0])
  */
       __pyx_t_4 = PyObject_Call(__pyx_builtin_ValueError, ((PyObject *)__pyx_k_tuple_14), NULL); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 175; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
       __Pyx_GOTREF(__pyx_t_4);
@@ -7417,9 +7456,9 @@ static int __pyx_pf_5_cdec_11TextGrammar___cinit__(struct __pyx_obj_5_cdec_TextG
     /* "/Users/vchahun/Sandbox/cdec/python/src/grammar.pxi":176
  *             if not isinstance(trule, BaseTRule):
  *                 raise ValueError('the grammar should contain TRule objects')
- *             _g.AddRule((<TRule> trule).rule[0])             # <<<<<<<<<<<<<<
+ *             _g.AddRule((<BaseTRule> trule).rule[0])             # <<<<<<<<<<<<<<
  */
-    __pyx_v__g->AddRule((((struct __pyx_obj_5_cdec_TRule *)__pyx_v_trule)->__pyx_base.rule[0]));
+    __pyx_v__g->AddRule((((struct __pyx_obj_5_cdec_BaseTRule *)__pyx_v_trule)->rule[0]));
   }
   __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
 
@@ -13071,7 +13110,7 @@ static PyObject *__pyx_pw_5_cdec_15SufficientStats_5__iter__(PyObject *__pyx_v_s
  * 
  *     def __iter__(self):             # <<<<<<<<<<<<<<
  *         for i in range(len(self)):
- *             yield self.stats[0][i]
+ *             yield self[i]
  */
 
 static PyObject *__pyx_pf_5_cdec_15SufficientStats_4__iter__(struct __pyx_obj_5_cdec_SufficientStats *__pyx_v_self) {
@@ -13118,7 +13157,6 @@ static PyObject *__pyx_gb_5_cdec_15SufficientStats_6generator14(__pyx_GeneratorO
   PyObject *__pyx_t_2 = NULL;
   PyObject *__pyx_t_3 = NULL;
   PyObject *(*__pyx_t_4)(PyObject *);
-  unsigned int __pyx_t_5;
   __Pyx_RefNannyDeclarations
   __Pyx_RefNannySetupContext("None", 0);
   switch (__pyx_generator->resume_label) {
@@ -13135,7 +13173,7 @@ static PyObject *__pyx_gb_5_cdec_15SufficientStats_6generator14(__pyx_GeneratorO
  * 
  *     def __iter__(self):
  *         for i in range(len(self)):             # <<<<<<<<<<<<<<
- *             yield self.stats[0][i]
+ *             yield self[i]
  * 
  */
   __pyx_t_1 = PyObject_Length(((PyObject *)__pyx_cur_scope->__pyx_v_self)); if (unlikely(__pyx_t_1 == -1)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 45; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
@@ -13185,12 +13223,11 @@ static PyObject *__pyx_gb_5_cdec_15SufficientStats_6generator14(__pyx_GeneratorO
     /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":46
  *     def __iter__(self):
  *         for i in range(len(self)):
- *             yield self.stats[0][i]             # <<<<<<<<<<<<<<
+ *             yield self[i]             # <<<<<<<<<<<<<<
  * 
- *     def __iadd__(SufficientStats self, SufficientStats other):
+ *     def __getitem__(self, int index):
  */
-    __pyx_t_5 = __Pyx_PyInt_AsUnsignedInt(__pyx_cur_scope->__pyx_v_i); if (unlikely((__pyx_t_5 == (unsigned int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 46; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-    __pyx_t_2 = PyFloat_FromDouble(((__pyx_cur_scope->__pyx_v_self->stats[0])[__pyx_t_5])); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 46; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_t_2 = PyObject_GetItem(((PyObject *)__pyx_cur_scope->__pyx_v_self), __pyx_cur_scope->__pyx_v_i); if (!__pyx_t_2) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 46; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
     __Pyx_GOTREF(__pyx_t_2);
     __pyx_r = __pyx_t_2;
     __pyx_t_2 = 0;
@@ -13226,13 +13263,111 @@ static PyObject *__pyx_gb_5_cdec_15SufficientStats_6generator14(__pyx_GeneratorO
 }
 
 /* Python wrapper */
-static PyObject *__pyx_pw_5_cdec_15SufficientStats_8__iadd__(PyObject *__pyx_v_self, PyObject *__pyx_v_other); /*proto*/
-static PyObject *__pyx_pw_5_cdec_15SufficientStats_8__iadd__(PyObject *__pyx_v_self, PyObject *__pyx_v_other) {
+static PyObject *__pyx_pw_5_cdec_15SufficientStats_8__getitem__(PyObject *__pyx_v_self, PyObject *__pyx_arg_index); /*proto*/
+static PyObject *__pyx_pw_5_cdec_15SufficientStats_8__getitem__(PyObject *__pyx_v_self, PyObject *__pyx_arg_index) {
+  int __pyx_v_index;
+  PyObject *__pyx_r = 0;
+  __Pyx_RefNannyDeclarations
+  __Pyx_RefNannySetupContext("__getitem__ (wrapper)", 0);
+  assert(__pyx_arg_index); {
+    __pyx_v_index = __Pyx_PyInt_AsInt(__pyx_arg_index); if (unlikely((__pyx_v_index == (int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 48; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+  }
+  goto __pyx_L4_argument_unpacking_done;
+  __pyx_L3_error:;
+  __Pyx_AddTraceback("_cdec.SufficientStats.__getitem__", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __Pyx_RefNannyFinishContext();
+  return NULL;
+  __pyx_L4_argument_unpacking_done:;
+  __pyx_r = __pyx_pf_5_cdec_15SufficientStats_7__getitem__(((struct __pyx_obj_5_cdec_SufficientStats *)__pyx_v_self), ((int)__pyx_v_index));
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+/* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":48
+ *             yield self[i]
+ * 
+ *     def __getitem__(self, int index):             # <<<<<<<<<<<<<<
+ *         if not 0 <= index < len(self):
+ *             raise IndexError('sufficient stats vector index out of range')
+ */
+
+static PyObject *__pyx_pf_5_cdec_15SufficientStats_7__getitem__(struct __pyx_obj_5_cdec_SufficientStats *__pyx_v_self, int __pyx_v_index) {
+  PyObject *__pyx_r = NULL;
+  __Pyx_RefNannyDeclarations
+  int __pyx_t_1;
+  Py_ssize_t __pyx_t_2;
+  int __pyx_t_3;
+  PyObject *__pyx_t_4 = NULL;
+  int __pyx_lineno = 0;
+  const char *__pyx_filename = NULL;
+  int __pyx_clineno = 0;
+  __Pyx_RefNannySetupContext("__getitem__", 0);
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":49
+ * 
+ *     def __getitem__(self, int index):
+ *         if not 0 <= index < len(self):             # <<<<<<<<<<<<<<
+ *             raise IndexError('sufficient stats vector index out of range')
+ *         return self.stats[0][index]
+ */
+  __pyx_t_1 = (0 <= __pyx_v_index);
+  if (__pyx_t_1) {
+    __pyx_t_2 = PyObject_Length(((PyObject *)__pyx_v_self)); if (unlikely(__pyx_t_2 == -1)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 49; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_t_1 = (__pyx_v_index < __pyx_t_2);
+  }
+  __pyx_t_3 = (!__pyx_t_1);
+  if (__pyx_t_3) {
+
+    /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":50
+ *     def __getitem__(self, int index):
+ *         if not 0 <= index < len(self):
+ *             raise IndexError('sufficient stats vector index out of range')             # <<<<<<<<<<<<<<
+ *         return self.stats[0][index]
+ * 
+ */
+    __pyx_t_4 = PyObject_Call(__pyx_builtin_IndexError, ((PyObject *)__pyx_k_tuple_42), NULL); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 50; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_4);
+    __Pyx_Raise(__pyx_t_4, 0, 0, 0);
+    __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
+    {__pyx_filename = __pyx_f[5]; __pyx_lineno = 50; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    goto __pyx_L3;
+  }
+  __pyx_L3:;
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":51
+ *         if not 0 <= index < len(self):
+ *             raise IndexError('sufficient stats vector index out of range')
+ *         return self.stats[0][index]             # <<<<<<<<<<<<<<
+ * 
+ *     def __iadd__(SufficientStats self, SufficientStats other):
+ */
+  __Pyx_XDECREF(__pyx_r);
+  __pyx_t_4 = PyFloat_FromDouble(((__pyx_v_self->stats[0])[__pyx_v_index])); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 51; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_4);
+  __pyx_r = __pyx_t_4;
+  __pyx_t_4 = 0;
+  goto __pyx_L0;
+
+  __pyx_r = Py_None; __Pyx_INCREF(Py_None);
+  goto __pyx_L0;
+  __pyx_L1_error:;
+  __Pyx_XDECREF(__pyx_t_4);
+  __Pyx_AddTraceback("_cdec.SufficientStats.__getitem__", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __pyx_r = NULL;
+  __pyx_L0:;
+  __Pyx_XGIVEREF(__pyx_r);
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+/* Python wrapper */
+static PyObject *__pyx_pw_5_cdec_15SufficientStats_10__iadd__(PyObject *__pyx_v_self, PyObject *__pyx_v_other); /*proto*/
+static PyObject *__pyx_pw_5_cdec_15SufficientStats_10__iadd__(PyObject *__pyx_v_self, PyObject *__pyx_v_other) {
   PyObject *__pyx_r = 0;
   __Pyx_RefNannyDeclarations
   __Pyx_RefNannySetupContext("__iadd__ (wrapper)", 0);
-  if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_other), __pyx_ptype_5_cdec_SufficientStats, 1, "other", 0))) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 48; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __pyx_r = __pyx_pf_5_cdec_15SufficientStats_7__iadd__(((struct __pyx_obj_5_cdec_SufficientStats *)__pyx_v_self), ((struct __pyx_obj_5_cdec_SufficientStats *)__pyx_v_other));
+  if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_other), __pyx_ptype_5_cdec_SufficientStats, 1, "other", 0))) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 53; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_r = __pyx_pf_5_cdec_15SufficientStats_9__iadd__(((struct __pyx_obj_5_cdec_SufficientStats *)__pyx_v_self), ((struct __pyx_obj_5_cdec_SufficientStats *)__pyx_v_other));
   goto __pyx_L0;
   __pyx_L1_error:;
   __pyx_r = NULL;
@@ -13241,20 +13376,20 @@ static PyObject *__pyx_pw_5_cdec_15SufficientStats_8__iadd__(PyObject *__pyx_v_s
   return __pyx_r;
 }
 
-/* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":48
- *             yield self.stats[0][i]
+/* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":53
+ *         return self.stats[0][index]
  * 
  *     def __iadd__(SufficientStats self, SufficientStats other):             # <<<<<<<<<<<<<<
  *         self.stats[0] += other.stats[0]
  *         return self
  */
 
-static PyObject *__pyx_pf_5_cdec_15SufficientStats_7__iadd__(struct __pyx_obj_5_cdec_SufficientStats *__pyx_v_self, struct __pyx_obj_5_cdec_SufficientStats *__pyx_v_other) {
+static PyObject *__pyx_pf_5_cdec_15SufficientStats_9__iadd__(struct __pyx_obj_5_cdec_SufficientStats *__pyx_v_self, struct __pyx_obj_5_cdec_SufficientStats *__pyx_v_other) {
   PyObject *__pyx_r = NULL;
   __Pyx_RefNannyDeclarations
   __Pyx_RefNannySetupContext("__iadd__", 0);
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":49
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":54
  * 
  *     def __iadd__(SufficientStats self, SufficientStats other):
  *         self.stats[0] += other.stats[0]             # <<<<<<<<<<<<<<
@@ -13263,7 +13398,7 @@ static PyObject *__pyx_pf_5_cdec_15SufficientStats_7__iadd__(struct __pyx_obj_5_
  */
   (__pyx_v_self->stats[0]) += (__pyx_v_other->stats[0]);
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":50
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":55
  *     def __iadd__(SufficientStats self, SufficientStats other):
  *         self.stats[0] += other.stats[0]
  *         return self             # <<<<<<<<<<<<<<
@@ -13283,17 +13418,17 @@ static PyObject *__pyx_pf_5_cdec_15SufficientStats_7__iadd__(struct __pyx_obj_5_
 }
 
 /* Python wrapper */
-static PyObject *__pyx_pw_5_cdec_15SufficientStats_10__add__(PyObject *__pyx_v_x, PyObject *__pyx_v_y); /*proto*/
-static PyObject *__pyx_pw_5_cdec_15SufficientStats_10__add__(PyObject *__pyx_v_x, PyObject *__pyx_v_y) {
+static PyObject *__pyx_pw_5_cdec_15SufficientStats_12__add__(PyObject *__pyx_v_x, PyObject *__pyx_v_y); /*proto*/
+static PyObject *__pyx_pw_5_cdec_15SufficientStats_12__add__(PyObject *__pyx_v_x, PyObject *__pyx_v_y) {
   PyObject *__pyx_r = 0;
   __Pyx_RefNannyDeclarations
   __Pyx_RefNannySetupContext("__add__ (wrapper)", 0);
-  __pyx_r = __pyx_pf_5_cdec_15SufficientStats_9__add__(((PyObject *)__pyx_v_x), ((PyObject *)__pyx_v_y));
+  __pyx_r = __pyx_pf_5_cdec_15SufficientStats_11__add__(((PyObject *)__pyx_v_x), ((PyObject *)__pyx_v_y));
   __Pyx_RefNannyFinishContext();
   return __pyx_r;
 }
 
-/* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":52
+/* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":57
  *         return self
  * 
  *     def __add__(x, y):             # <<<<<<<<<<<<<<
@@ -13301,7 +13436,7 @@ static PyObject *__pyx_pw_5_cdec_15SufficientStats_10__add__(PyObject *__pyx_v_x
  *         cdef SufficientStats sy = as_stats(y, x)
  */
 
-static PyObject *__pyx_pf_5_cdec_15SufficientStats_9__add__(PyObject *__pyx_v_x, PyObject *__pyx_v_y) {
+static PyObject *__pyx_pf_5_cdec_15SufficientStats_11__add__(PyObject *__pyx_v_x, PyObject *__pyx_v_y) {
   struct __pyx_obj_5_cdec_SufficientStats *__pyx_v_sx = 0;
   struct __pyx_obj_5_cdec_SufficientStats *__pyx_v_sy = 0;
   struct __pyx_obj_5_cdec_SufficientStats *__pyx_v_result = 0;
@@ -13313,43 +13448,43 @@ static PyObject *__pyx_pf_5_cdec_15SufficientStats_9__add__(PyObject *__pyx_v_x,
   int __pyx_clineno = 0;
   __Pyx_RefNannySetupContext("__add__", 0);
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":53
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":58
  * 
  *     def __add__(x, y):
  *         cdef SufficientStats sx = as_stats(x, y)             # <<<<<<<<<<<<<<
  *         cdef SufficientStats sy = as_stats(y, x)
  *         cdef SufficientStats result = SufficientStats()
  */
-  __pyx_t_1 = ((PyObject *)__pyx_f_5_cdec_as_stats(__pyx_v_x, __pyx_v_y)); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 53; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_1 = ((PyObject *)__pyx_f_5_cdec_as_stats(__pyx_v_x, __pyx_v_y)); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 58; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __Pyx_GOTREF(__pyx_t_1);
   __pyx_v_sx = ((struct __pyx_obj_5_cdec_SufficientStats *)__pyx_t_1);
   __pyx_t_1 = 0;
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":54
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":59
  *     def __add__(x, y):
  *         cdef SufficientStats sx = as_stats(x, y)
  *         cdef SufficientStats sy = as_stats(y, x)             # <<<<<<<<<<<<<<
  *         cdef SufficientStats result = SufficientStats()
  *         result.stats = new mteval.SufficientStats(mteval.add(sx.stats[0], sy.stats[0]))
  */
-  __pyx_t_1 = ((PyObject *)__pyx_f_5_cdec_as_stats(__pyx_v_y, __pyx_v_x)); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 54; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_1 = ((PyObject *)__pyx_f_5_cdec_as_stats(__pyx_v_y, __pyx_v_x)); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 59; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __Pyx_GOTREF(__pyx_t_1);
   __pyx_v_sy = ((struct __pyx_obj_5_cdec_SufficientStats *)__pyx_t_1);
   __pyx_t_1 = 0;
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":55
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":60
  *         cdef SufficientStats sx = as_stats(x, y)
  *         cdef SufficientStats sy = as_stats(y, x)
  *         cdef SufficientStats result = SufficientStats()             # <<<<<<<<<<<<<<
  *         result.stats = new mteval.SufficientStats(mteval.add(sx.stats[0], sy.stats[0]))
  *         result.metric = sx.metric
  */
-  __pyx_t_1 = PyObject_Call(((PyObject *)((PyObject*)__pyx_ptype_5_cdec_SufficientStats)), ((PyObject *)__pyx_empty_tuple), NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 55; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_1 = PyObject_Call(((PyObject *)((PyObject*)__pyx_ptype_5_cdec_SufficientStats)), ((PyObject *)__pyx_empty_tuple), NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 60; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __Pyx_GOTREF(__pyx_t_1);
   __pyx_v_result = ((struct __pyx_obj_5_cdec_SufficientStats *)__pyx_t_1);
   __pyx_t_1 = 0;
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":56
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":61
  *         cdef SufficientStats sy = as_stats(y, x)
  *         cdef SufficientStats result = SufficientStats()
  *         result.stats = new mteval.SufficientStats(mteval.add(sx.stats[0], sy.stats[0]))             # <<<<<<<<<<<<<<
@@ -13358,7 +13493,7 @@ static PyObject *__pyx_pf_5_cdec_15SufficientStats_9__add__(PyObject *__pyx_v_x,
  */
   __pyx_v_result->stats = new SufficientStats(operator+((__pyx_v_sx->stats[0]), (__pyx_v_sy->stats[0])));
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":57
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":62
  *         cdef SufficientStats result = SufficientStats()
  *         result.stats = new mteval.SufficientStats(mteval.add(sx.stats[0], sy.stats[0]))
  *         result.metric = sx.metric             # <<<<<<<<<<<<<<
@@ -13367,7 +13502,7 @@ static PyObject *__pyx_pf_5_cdec_15SufficientStats_9__add__(PyObject *__pyx_v_x,
  */
   __pyx_v_result->metric = __pyx_v_sx->metric;
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":58
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":63
  *         result.stats = new mteval.SufficientStats(mteval.add(sx.stats[0], sy.stats[0]))
  *         result.metric = sx.metric
  *         return result             # <<<<<<<<<<<<<<
@@ -13420,7 +13555,7 @@ static int __pyx_pw_5_cdec_12CandidateSet_1__cinit__(PyObject *__pyx_v_self, PyO
         else goto __pyx_L5_argtuple_error;
       }
       if (unlikely(kw_args > 0)) {
-        if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "__cinit__") < 0)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 65; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+        if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "__cinit__") < 0)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 70; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
       }
     } else if (PyTuple_GET_SIZE(__pyx_args) != 1) {
       goto __pyx_L5_argtuple_error;
@@ -13431,13 +13566,13 @@ static int __pyx_pw_5_cdec_12CandidateSet_1__cinit__(PyObject *__pyx_v_self, PyO
   }
   goto __pyx_L4_argument_unpacking_done;
   __pyx_L5_argtuple_error:;
-  __Pyx_RaiseArgtupleInvalid("__cinit__", 1, 1, 1, PyTuple_GET_SIZE(__pyx_args)); {__pyx_filename = __pyx_f[5]; __pyx_lineno = 65; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+  __Pyx_RaiseArgtupleInvalid("__cinit__", 1, 1, 1, PyTuple_GET_SIZE(__pyx_args)); {__pyx_filename = __pyx_f[5]; __pyx_lineno = 70; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
   __pyx_L3_error:;
   __Pyx_AddTraceback("_cdec.CandidateSet.__cinit__", __pyx_clineno, __pyx_lineno, __pyx_filename);
   __Pyx_RefNannyFinishContext();
   return -1;
   __pyx_L4_argument_unpacking_done:;
-  if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_evaluator), __pyx_ptype_5_cdec_SegmentEvaluator, 1, "evaluator", 0))) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 65; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_evaluator), __pyx_ptype_5_cdec_SegmentEvaluator, 1, "evaluator", 0))) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 70; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __pyx_r = __pyx_pf_5_cdec_12CandidateSet___cinit__(((struct __pyx_obj_5_cdec_CandidateSet *)__pyx_v_self), __pyx_v_evaluator);
   goto __pyx_L0;
   __pyx_L1_error:;
@@ -13447,7 +13582,7 @@ static int __pyx_pw_5_cdec_12CandidateSet_1__cinit__(PyObject *__pyx_v_self, PyO
   return __pyx_r;
 }
 
-/* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":65
+/* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":70
  *     cdef mteval.CandidateSet* cs
  * 
  *     def __cinit__(self, SegmentEvaluator evaluator):             # <<<<<<<<<<<<<<
@@ -13460,7 +13595,7 @@ static int __pyx_pf_5_cdec_12CandidateSet___cinit__(struct __pyx_obj_5_cdec_Cand
   __Pyx_RefNannyDeclarations
   __Pyx_RefNannySetupContext("__cinit__", 0);
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":66
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":71
  * 
  *     def __cinit__(self, SegmentEvaluator evaluator):
  *         self.scorer = new shared_ptr[mteval.SegmentEvaluator](evaluator.scorer[0])             # <<<<<<<<<<<<<<
@@ -13469,7 +13604,7 @@ static int __pyx_pf_5_cdec_12CandidateSet___cinit__(struct __pyx_obj_5_cdec_Cand
  */
   __pyx_v_self->scorer = new boost::shared_ptr<SegmentEvaluator>((__pyx_v_evaluator->scorer[0]));
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":67
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":72
  *     def __cinit__(self, SegmentEvaluator evaluator):
  *         self.scorer = new shared_ptr[mteval.SegmentEvaluator](evaluator.scorer[0])
  *         self.metric = evaluator.metric             # <<<<<<<<<<<<<<
@@ -13478,7 +13613,7 @@ static int __pyx_pf_5_cdec_12CandidateSet___cinit__(struct __pyx_obj_5_cdec_Cand
  */
   __pyx_v_self->metric = __pyx_v_evaluator->metric;
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":68
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":73
  *         self.scorer = new shared_ptr[mteval.SegmentEvaluator](evaluator.scorer[0])
  *         self.metric = evaluator.metric
  *         self.cs = new mteval.CandidateSet()             # <<<<<<<<<<<<<<
@@ -13501,7 +13636,7 @@ static void __pyx_pw_5_cdec_12CandidateSet_3__dealloc__(PyObject *__pyx_v_self)
   __Pyx_RefNannyFinishContext();
 }
 
-/* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":70
+/* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":75
  *         self.cs = new mteval.CandidateSet()
  * 
  *     def __dealloc__(self):             # <<<<<<<<<<<<<<
@@ -13513,7 +13648,7 @@ static void __pyx_pf_5_cdec_12CandidateSet_2__dealloc__(CYTHON_UNUSED struct __p
   __Pyx_RefNannyDeclarations
   __Pyx_RefNannySetupContext("__dealloc__", 0);
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":71
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":76
  * 
  *     def __dealloc__(self):
  *         del self.scorer             # <<<<<<<<<<<<<<
@@ -13522,7 +13657,7 @@ static void __pyx_pf_5_cdec_12CandidateSet_2__dealloc__(CYTHON_UNUSED struct __p
  */
   delete __pyx_v_self->scorer;
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":72
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":77
  *     def __dealloc__(self):
  *         del self.scorer
  *         del self.cs             # <<<<<<<<<<<<<<
@@ -13545,7 +13680,7 @@ static Py_ssize_t __pyx_pw_5_cdec_12CandidateSet_5__len__(PyObject *__pyx_v_self
   return __pyx_r;
 }
 
-/* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":74
+/* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":79
  *         del self.cs
  * 
  *     def __len__(self):             # <<<<<<<<<<<<<<
@@ -13558,7 +13693,7 @@ static Py_ssize_t __pyx_pf_5_cdec_12CandidateSet_4__len__(struct __pyx_obj_5_cde
   __Pyx_RefNannyDeclarations
   __Pyx_RefNannySetupContext("__len__", 0);
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":75
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":80
  * 
  *     def __len__(self):
  *         return self.cs.size()             # <<<<<<<<<<<<<<
@@ -13582,7 +13717,7 @@ static PyObject *__pyx_pw_5_cdec_12CandidateSet_7__getitem__(PyObject *__pyx_v_s
   __Pyx_RefNannyDeclarations
   __Pyx_RefNannySetupContext("__getitem__ (wrapper)", 0);
   assert(__pyx_arg_k); {
-    __pyx_v_k = __Pyx_PyInt_AsInt(__pyx_arg_k); if (unlikely((__pyx_v_k == (int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 77; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+    __pyx_v_k = __Pyx_PyInt_AsInt(__pyx_arg_k); if (unlikely((__pyx_v_k == (int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 82; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
   }
   goto __pyx_L4_argument_unpacking_done;
   __pyx_L3_error:;
@@ -13595,7 +13730,7 @@ static PyObject *__pyx_pw_5_cdec_12CandidateSet_7__getitem__(PyObject *__pyx_v_s
   return __pyx_r;
 }
 
-/* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":77
+/* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":82
  *         return self.cs.size()
  * 
  *     def __getitem__(self,int k):             # <<<<<<<<<<<<<<
@@ -13615,7 +13750,7 @@ static PyObject *__pyx_pf_5_cdec_12CandidateSet_6__getitem__(struct __pyx_obj_5_
   int __pyx_clineno = 0;
   __Pyx_RefNannySetupContext("__getitem__", 0);
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":78
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":83
  * 
  *     def __getitem__(self,int k):
  *         if not 0 <= k < self.cs.size():             # <<<<<<<<<<<<<<
@@ -13629,35 +13764,35 @@ static PyObject *__pyx_pf_5_cdec_12CandidateSet_6__getitem__(struct __pyx_obj_5_
   __pyx_t_2 = (!__pyx_t_1);
   if (__pyx_t_2) {
 
-    /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":79
+    /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":84
  *     def __getitem__(self,int k):
  *         if not 0 <= k < self.cs.size():
  *             raise IndexError('candidate set index out of range')             # <<<<<<<<<<<<<<
  *         cdef Candidate candidate = Candidate()
  *         candidate.candidate = &self.cs[0][k]
  */
-    __pyx_t_3 = PyObject_Call(__pyx_builtin_IndexError, ((PyObject *)__pyx_k_tuple_42), NULL); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 79; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_t_3 = PyObject_Call(__pyx_builtin_IndexError, ((PyObject *)__pyx_k_tuple_44), NULL); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 84; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
     __Pyx_GOTREF(__pyx_t_3);
     __Pyx_Raise(__pyx_t_3, 0, 0, 0);
     __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
-    {__pyx_filename = __pyx_f[5]; __pyx_lineno = 79; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    {__pyx_filename = __pyx_f[5]; __pyx_lineno = 84; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
     goto __pyx_L3;
   }
   __pyx_L3:;
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":80
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":85
  *         if not 0 <= k < self.cs.size():
  *             raise IndexError('candidate set index out of range')
  *         cdef Candidate candidate = Candidate()             # <<<<<<<<<<<<<<
  *         candidate.candidate = &self.cs[0][k]
  *         candidate.score = self.metric.ComputeScore(self.cs[0][k].eval_feats)
  */
-  __pyx_t_3 = PyObject_Call(((PyObject *)((PyObject*)__pyx_ptype_5_cdec_Candidate)), ((PyObject *)__pyx_empty_tuple), NULL); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 80; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_3 = PyObject_Call(((PyObject *)((PyObject*)__pyx_ptype_5_cdec_Candidate)), ((PyObject *)__pyx_empty_tuple), NULL); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 85; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __Pyx_GOTREF(__pyx_t_3);
   __pyx_v_candidate = ((struct __pyx_obj_5_cdec_Candidate *)__pyx_t_3);
   __pyx_t_3 = 0;
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":81
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":86
  *             raise IndexError('candidate set index out of range')
  *         cdef Candidate candidate = Candidate()
  *         candidate.candidate = &self.cs[0][k]             # <<<<<<<<<<<<<<
@@ -13666,7 +13801,7 @@ static PyObject *__pyx_pf_5_cdec_12CandidateSet_6__getitem__(struct __pyx_obj_5_
  */
   __pyx_v_candidate->candidate = (&((__pyx_v_self->cs[0])[__pyx_v_k]));
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":82
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":87
  *         cdef Candidate candidate = Candidate()
  *         candidate.candidate = &self.cs[0][k]
  *         candidate.score = self.metric.ComputeScore(self.cs[0][k].eval_feats)             # <<<<<<<<<<<<<<
@@ -13675,7 +13810,7 @@ static PyObject *__pyx_pf_5_cdec_12CandidateSet_6__getitem__(struct __pyx_obj_5_
  */
   __pyx_v_candidate->score = __pyx_v_self->metric->ComputeScore(((__pyx_v_self->cs[0])[__pyx_v_k]).eval_feats);
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":83
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":88
  *         candidate.candidate = &self.cs[0][k]
  *         candidate.score = self.metric.ComputeScore(self.cs[0][k].eval_feats)
  *         return candidate             # <<<<<<<<<<<<<<
@@ -13712,7 +13847,7 @@ static PyObject *__pyx_pw_5_cdec_12CandidateSet_9__iter__(PyObject *__pyx_v_self
   return __pyx_r;
 }
 
-/* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":85
+/* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":90
  *         return candidate
  * 
  *     def __iter__(self):             # <<<<<<<<<<<<<<
@@ -13738,7 +13873,7 @@ static PyObject *__pyx_pf_5_cdec_12CandidateSet_8__iter__(struct __pyx_obj_5_cde
   __Pyx_INCREF((PyObject *)__pyx_cur_scope->__pyx_v_self);
   __Pyx_GIVEREF((PyObject *)__pyx_cur_scope->__pyx_v_self);
   {
-    __pyx_GeneratorObject *gen = __Pyx_Generator_New((__pyx_generator_body_t) __pyx_gb_5_cdec_12CandidateSet_10generator15, (PyObject *) __pyx_cur_scope); if (unlikely(!gen)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 85; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_GeneratorObject *gen = __Pyx_Generator_New((__pyx_generator_body_t) __pyx_gb_5_cdec_12CandidateSet_10generator15, (PyObject *) __pyx_cur_scope); if (unlikely(!gen)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 90; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
     __Pyx_DECREF(__pyx_cur_scope);
     __Pyx_RefNannyFinishContext();
     return (PyObject *) gen;
@@ -13773,27 +13908,27 @@ static PyObject *__pyx_gb_5_cdec_12CandidateSet_10generator15(__pyx_GeneratorObj
     return NULL;
   }
   __pyx_L3_first_run:;
-  if (unlikely(!__pyx_sent_value)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 85; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (unlikely(!__pyx_sent_value)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 90; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":87
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":92
  *     def __iter__(self):
  *         cdef unsigned i
  *         for i in range(len(self)):             # <<<<<<<<<<<<<<
  *             yield self[i]
  * 
  */
-  __pyx_t_1 = PyObject_Length(((PyObject *)__pyx_cur_scope->__pyx_v_self)); if (unlikely(__pyx_t_1 == -1)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 87; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_1 = PyObject_Length(((PyObject *)__pyx_cur_scope->__pyx_v_self)); if (unlikely(__pyx_t_1 == -1)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 92; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   for (__pyx_t_2 = 0; __pyx_t_2 < __pyx_t_1; __pyx_t_2+=1) {
     __pyx_cur_scope->__pyx_v_i = __pyx_t_2;
 
-    /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":88
+    /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":93
  *         cdef unsigned i
  *         for i in range(len(self)):
  *             yield self[i]             # <<<<<<<<<<<<<<
  * 
  *     def add_kbest(self, Hypergraph hypergraph, unsigned k):
  */
-    __pyx_t_3 = __Pyx_GetItemInt(((PyObject *)__pyx_cur_scope->__pyx_v_self), __pyx_cur_scope->__pyx_v_i, sizeof(unsigned int)+1, PyLong_FromUnsignedLong); if (!__pyx_t_3) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 88; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_t_3 = __Pyx_GetItemInt(((PyObject *)__pyx_cur_scope->__pyx_v_self), __pyx_cur_scope->__pyx_v_i, sizeof(unsigned int)+1, PyLong_FromUnsignedLong); if (!__pyx_t_3) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 93; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
     __Pyx_GOTREF(__pyx_t_3);
     __pyx_r = __pyx_t_3;
     __pyx_t_3 = 0;
@@ -13807,7 +13942,7 @@ static PyObject *__pyx_gb_5_cdec_12CandidateSet_10generator15(__pyx_GeneratorObj
     __pyx_L6_resume_from_yield:;
     __pyx_t_1 = __pyx_cur_scope->__pyx_t_0;
     __pyx_t_2 = __pyx_cur_scope->__pyx_t_1;
-    if (unlikely(!__pyx_sent_value)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 88; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    if (unlikely(!__pyx_sent_value)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 93; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   }
   PyErr_SetNone(PyExc_StopIteration);
   goto __pyx_L0;
@@ -13851,11 +13986,11 @@ static PyObject *__pyx_pw_5_cdec_12CandidateSet_12add_kbest(PyObject *__pyx_v_se
         values[1] = PyDict_GetItem(__pyx_kwds, __pyx_n_s__k);
         if (likely(values[1])) kw_args--;
         else {
-          __Pyx_RaiseArgtupleInvalid("add_kbest", 1, 2, 2, 1); {__pyx_filename = __pyx_f[5]; __pyx_lineno = 90; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+          __Pyx_RaiseArgtupleInvalid("add_kbest", 1, 2, 2, 1); {__pyx_filename = __pyx_f[5]; __pyx_lineno = 95; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
         }
       }
       if (unlikely(kw_args > 0)) {
-        if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "add_kbest") < 0)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 90; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+        if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "add_kbest") < 0)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 95; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
       }
     } else if (PyTuple_GET_SIZE(__pyx_args) != 2) {
       goto __pyx_L5_argtuple_error;
@@ -13864,17 +13999,17 @@ static PyObject *__pyx_pw_5_cdec_12CandidateSet_12add_kbest(PyObject *__pyx_v_se
       values[1] = PyTuple_GET_ITEM(__pyx_args, 1);
     }
     __pyx_v_hypergraph = ((struct __pyx_obj_5_cdec_Hypergraph *)values[0]);
-    __pyx_v_k = __Pyx_PyInt_AsUnsignedInt(values[1]); if (unlikely((__pyx_v_k == (unsigned int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 90; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+    __pyx_v_k = __Pyx_PyInt_AsUnsignedInt(values[1]); if (unlikely((__pyx_v_k == (unsigned int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 95; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
   }
   goto __pyx_L4_argument_unpacking_done;
   __pyx_L5_argtuple_error:;
-  __Pyx_RaiseArgtupleInvalid("add_kbest", 1, 2, 2, PyTuple_GET_SIZE(__pyx_args)); {__pyx_filename = __pyx_f[5]; __pyx_lineno = 90; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+  __Pyx_RaiseArgtupleInvalid("add_kbest", 1, 2, 2, PyTuple_GET_SIZE(__pyx_args)); {__pyx_filename = __pyx_f[5]; __pyx_lineno = 95; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
   __pyx_L3_error:;
   __Pyx_AddTraceback("_cdec.CandidateSet.add_kbest", __pyx_clineno, __pyx_lineno, __pyx_filename);
   __Pyx_RefNannyFinishContext();
   return NULL;
   __pyx_L4_argument_unpacking_done:;
-  if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_hypergraph), __pyx_ptype_5_cdec_Hypergraph, 1, "hypergraph", 0))) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 90; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_hypergraph), __pyx_ptype_5_cdec_Hypergraph, 1, "hypergraph", 0))) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 95; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __pyx_r = __pyx_pf_5_cdec_12CandidateSet_11add_kbest(((struct __pyx_obj_5_cdec_CandidateSet *)__pyx_v_self), __pyx_v_hypergraph, __pyx_v_k);
   goto __pyx_L0;
   __pyx_L1_error:;
@@ -13884,7 +14019,7 @@ static PyObject *__pyx_pw_5_cdec_12CandidateSet_12add_kbest(PyObject *__pyx_v_se
   return __pyx_r;
 }
 
-/* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":90
+/* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":95
  *             yield self[i]
  * 
  *     def add_kbest(self, Hypergraph hypergraph, unsigned k):             # <<<<<<<<<<<<<<
@@ -13897,7 +14032,7 @@ static PyObject *__pyx_pf_5_cdec_12CandidateSet_11add_kbest(struct __pyx_obj_5_c
   __Pyx_RefNannyDeclarations
   __Pyx_RefNannySetupContext("add_kbest", 0);
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":91
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":96
  * 
  *     def add_kbest(self, Hypergraph hypergraph, unsigned k):
  *         self.cs.AddKBestCandidates(hypergraph.hg[0], k, self.scorer.get())             # <<<<<<<<<<<<<<
@@ -13921,7 +14056,7 @@ static void __pyx_pw_5_cdec_16SegmentEvaluator_1__dealloc__(PyObject *__pyx_v_se
   __Pyx_RefNannyFinishContext();
 }
 
-/* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":97
+/* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":102
  *     cdef mteval.EvaluationMetric* metric
  * 
  *     def __dealloc__(self):             # <<<<<<<<<<<<<<
@@ -13933,7 +14068,7 @@ static void __pyx_pf_5_cdec_16SegmentEvaluator___dealloc__(CYTHON_UNUSED struct
   __Pyx_RefNannyDeclarations
   __Pyx_RefNannySetupContext("__dealloc__", 0);
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":98
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":103
  * 
  *     def __dealloc__(self):
  *         del self.scorer             # <<<<<<<<<<<<<<
@@ -13956,7 +14091,7 @@ static PyObject *__pyx_pw_5_cdec_16SegmentEvaluator_3evaluate(PyObject *__pyx_v_
   return __pyx_r;
 }
 
-/* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":100
+/* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":105
  *         del self.scorer
  * 
  *     def evaluate(self, sentence):             # <<<<<<<<<<<<<<
@@ -13976,19 +14111,19 @@ static PyObject *__pyx_pf_5_cdec_16SegmentEvaluator_2evaluate(struct __pyx_obj_5
   int __pyx_clineno = 0;
   __Pyx_RefNannySetupContext("evaluate", 0);
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":102
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":107
  *     def evaluate(self, sentence):
  *         cdef vector[WordID] hyp
  *         cdef SufficientStats sf = SufficientStats()             # <<<<<<<<<<<<<<
  *         sf.metric = self.metric
  *         sf.stats = new mteval.SufficientStats()
  */
-  __pyx_t_1 = PyObject_Call(((PyObject *)((PyObject*)__pyx_ptype_5_cdec_SufficientStats)), ((PyObject *)__pyx_empty_tuple), NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 102; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_1 = PyObject_Call(((PyObject *)((PyObject*)__pyx_ptype_5_cdec_SufficientStats)), ((PyObject *)__pyx_empty_tuple), NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 107; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __Pyx_GOTREF(__pyx_t_1);
   __pyx_v_sf = ((struct __pyx_obj_5_cdec_SufficientStats *)__pyx_t_1);
   __pyx_t_1 = 0;
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":103
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":108
  *         cdef vector[WordID] hyp
  *         cdef SufficientStats sf = SufficientStats()
  *         sf.metric = self.metric             # <<<<<<<<<<<<<<
@@ -13997,7 +14132,7 @@ static PyObject *__pyx_pf_5_cdec_16SegmentEvaluator_2evaluate(struct __pyx_obj_5
  */
   __pyx_v_sf->metric = __pyx_v_self->metric;
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":104
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":109
  *         cdef SufficientStats sf = SufficientStats()
  *         sf.metric = self.metric
  *         sf.stats = new mteval.SufficientStats()             # <<<<<<<<<<<<<<
@@ -14006,22 +14141,22 @@ static PyObject *__pyx_pf_5_cdec_16SegmentEvaluator_2evaluate(struct __pyx_obj_5
  */
   __pyx_v_sf->stats = new SufficientStats();
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":105
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":110
  *         sf.metric = self.metric
  *         sf.stats = new mteval.SufficientStats()
  *         ConvertSentence(string(as_str(sentence.strip())), &hyp)             # <<<<<<<<<<<<<<
  *         self.scorer.get().Evaluate(hyp, sf.stats)
  *         return sf
  */
-  __pyx_t_1 = PyObject_GetAttr(__pyx_v_sentence, __pyx_n_s__strip); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 105; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_1 = PyObject_GetAttr(__pyx_v_sentence, __pyx_n_s__strip); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 110; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __Pyx_GOTREF(__pyx_t_1);
-  __pyx_t_2 = PyObject_Call(__pyx_t_1, ((PyObject *)__pyx_empty_tuple), NULL); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 105; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_2 = PyObject_Call(__pyx_t_1, ((PyObject *)__pyx_empty_tuple), NULL); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 110; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __Pyx_GOTREF(__pyx_t_2);
   __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
   TD::ConvertSentence(std::string(__pyx_f_5_cdec_as_str(__pyx_t_2, NULL)), (&__pyx_v_hyp));
   __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":106
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":111
  *         sf.stats = new mteval.SufficientStats()
  *         ConvertSentence(string(as_str(sentence.strip())), &hyp)
  *         self.scorer.get().Evaluate(hyp, sf.stats)             # <<<<<<<<<<<<<<
@@ -14030,7 +14165,7 @@ static PyObject *__pyx_pf_5_cdec_16SegmentEvaluator_2evaluate(struct __pyx_obj_5
  */
   __pyx_v_self->scorer->get()->Evaluate(__pyx_v_hyp, __pyx_v_sf->stats);
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":107
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":112
  *         ConvertSentence(string(as_str(sentence.strip())), &hyp)
  *         self.scorer.get().Evaluate(hyp, sf.stats)
  *         return sf             # <<<<<<<<<<<<<<
@@ -14067,7 +14202,7 @@ static PyObject *__pyx_pw_5_cdec_16SegmentEvaluator_5candidate_set(PyObject *__p
   return __pyx_r;
 }
 
-/* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":109
+/* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":114
  *         return sf
  * 
  *     def candidate_set(self):             # <<<<<<<<<<<<<<
@@ -14085,7 +14220,7 @@ static PyObject *__pyx_pf_5_cdec_16SegmentEvaluator_4candidate_set(struct __pyx_
   int __pyx_clineno = 0;
   __Pyx_RefNannySetupContext("candidate_set", 0);
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":110
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":115
  * 
  *     def candidate_set(self):
  *         return CandidateSet(self)             # <<<<<<<<<<<<<<
@@ -14093,12 +14228,12 @@ static PyObject *__pyx_pf_5_cdec_16SegmentEvaluator_4candidate_set(struct __pyx_
  * cdef class Scorer:
  */
   __Pyx_XDECREF(__pyx_r);
-  __pyx_t_1 = PyTuple_New(1); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 110; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_1 = PyTuple_New(1); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 115; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __Pyx_GOTREF(__pyx_t_1);
   __Pyx_INCREF(((PyObject *)__pyx_v_self));
   PyTuple_SET_ITEM(__pyx_t_1, 0, ((PyObject *)__pyx_v_self));
   __Pyx_GIVEREF(((PyObject *)__pyx_v_self));
-  __pyx_t_2 = PyObject_Call(((PyObject *)((PyObject*)__pyx_ptype_5_cdec_CandidateSet)), ((PyObject *)__pyx_t_1), NULL); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 110; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_2 = PyObject_Call(((PyObject *)((PyObject*)__pyx_ptype_5_cdec_CandidateSet)), ((PyObject *)__pyx_t_1), NULL); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 115; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __Pyx_GOTREF(__pyx_t_2);
   __Pyx_DECREF(((PyObject *)__pyx_t_1)); __pyx_t_1 = 0;
   __pyx_r = __pyx_t_2;
@@ -14121,13 +14256,22 @@ static PyObject *__pyx_pf_5_cdec_16SegmentEvaluator_4candidate_set(struct __pyx_
 /* Python wrapper */
 static int __pyx_pw_5_cdec_6Scorer_1__cinit__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/
 static int __pyx_pw_5_cdec_6Scorer_1__cinit__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) {
-  char *__pyx_v_name;
+  PyObject *__pyx_v_name = 0;
   static PyObject **__pyx_pyargnames[] = {&__pyx_n_s__name,0};
   int __pyx_r;
   __Pyx_RefNannyDeclarations
   __Pyx_RefNannySetupContext("__cinit__ (wrapper)", 0);
   {
     PyObject* values[1] = {0};
+
+    /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":121
+ *     cdef mteval.EvaluationMetric* metric
+ * 
+ *     def __cinit__(self, bytes name=None):             # <<<<<<<<<<<<<<
+ *         if name:
+ *             self.name = new string(name)
+ */
+    values[0] = ((PyObject*)Py_None);
     if (unlikely(__pyx_kwds)) {
       Py_ssize_t kw_args;
       const Py_ssize_t pos_args = PyTuple_GET_SIZE(__pyx_args);
@@ -14139,56 +14283,89 @@ static int __pyx_pw_5_cdec_6Scorer_1__cinit__(PyObject *__pyx_v_self, PyObject *
       kw_args = PyDict_Size(__pyx_kwds);
       switch (pos_args) {
         case  0:
-        values[0] = PyDict_GetItem(__pyx_kwds, __pyx_n_s__name);
-        if (likely(values[0])) kw_args--;
-        else goto __pyx_L5_argtuple_error;
+        if (kw_args > 0) {
+          PyObject* value = PyDict_GetItem(__pyx_kwds, __pyx_n_s__name);
+          if (value) { values[0] = value; kw_args--; }
+        }
       }
       if (unlikely(kw_args > 0)) {
-        if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "__cinit__") < 0)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 115; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+        if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "__cinit__") < 0)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 121; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
       }
-    } else if (PyTuple_GET_SIZE(__pyx_args) != 1) {
-      goto __pyx_L5_argtuple_error;
     } else {
-      values[0] = PyTuple_GET_ITEM(__pyx_args, 0);
+      switch (PyTuple_GET_SIZE(__pyx_args)) {
+        case  1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0);
+        case  0: break;
+        default: goto __pyx_L5_argtuple_error;
+      }
     }
-    __pyx_v_name = PyBytes_AsString(values[0]); if (unlikely((!__pyx_v_name) && PyErr_Occurred())) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 115; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+    __pyx_v_name = ((PyObject*)values[0]);
   }
   goto __pyx_L4_argument_unpacking_done;
   __pyx_L5_argtuple_error:;
-  __Pyx_RaiseArgtupleInvalid("__cinit__", 1, 1, 1, PyTuple_GET_SIZE(__pyx_args)); {__pyx_filename = __pyx_f[5]; __pyx_lineno = 115; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+  __Pyx_RaiseArgtupleInvalid("__cinit__", 0, 0, 1, PyTuple_GET_SIZE(__pyx_args)); {__pyx_filename = __pyx_f[5]; __pyx_lineno = 121; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
   __pyx_L3_error:;
   __Pyx_AddTraceback("_cdec.Scorer.__cinit__", __pyx_clineno, __pyx_lineno, __pyx_filename);
   __Pyx_RefNannyFinishContext();
   return -1;
   __pyx_L4_argument_unpacking_done:;
+  if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_name), (&PyBytes_Type), 1, "name", 1))) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 121; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __pyx_r = __pyx_pf_5_cdec_6Scorer___cinit__(((struct __pyx_obj_5_cdec_Scorer *)__pyx_v_self), __pyx_v_name);
+  goto __pyx_L0;
+  __pyx_L1_error:;
+  __pyx_r = -1;
+  __pyx_L0:;
   __Pyx_RefNannyFinishContext();
   return __pyx_r;
 }
 
-/* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":115
- *     cdef string* name
- * 
- *     def __cinit__(self, char* name):             # <<<<<<<<<<<<<<
- *         self.name = new string(name)
- * 
- */
-
-static int __pyx_pf_5_cdec_6Scorer___cinit__(struct __pyx_obj_5_cdec_Scorer *__pyx_v_self, char *__pyx_v_name) {
+static int __pyx_pf_5_cdec_6Scorer___cinit__(struct __pyx_obj_5_cdec_Scorer *__pyx_v_self, PyObject *__pyx_v_name) {
   int __pyx_r;
   __Pyx_RefNannyDeclarations
+  int __pyx_t_1;
+  char *__pyx_t_2;
+  int __pyx_lineno = 0;
+  const char *__pyx_filename = NULL;
+  int __pyx_clineno = 0;
   __Pyx_RefNannySetupContext("__cinit__", 0);
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":116
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":122
+ * 
+ *     def __cinit__(self, bytes name=None):
+ *         if name:             # <<<<<<<<<<<<<<
+ *             self.name = new string(name)
+ *             self.metric = mteval.MetricInstance(self.name[0])
+ */
+  __pyx_t_1 = (((PyObject *)__pyx_v_name) != Py_None) && (PyBytes_GET_SIZE(((PyObject *)__pyx_v_name)) != 0);
+  if (__pyx_t_1) {
+
+    /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":123
+ *     def __cinit__(self, bytes name=None):
+ *         if name:
+ *             self.name = new string(name)             # <<<<<<<<<<<<<<
+ *             self.metric = mteval.MetricInstance(self.name[0])
  * 
- *     def __cinit__(self, char* name):
- *         self.name = new string(name)             # <<<<<<<<<<<<<<
+ */
+    __pyx_t_2 = PyBytes_AsString(((PyObject *)__pyx_v_name)); if (unlikely((!__pyx_t_2) && PyErr_Occurred())) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 123; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_v_self->name = new std::string(__pyx_t_2);
+
+    /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":124
+ *         if name:
+ *             self.name = new string(name)
+ *             self.metric = mteval.MetricInstance(self.name[0])             # <<<<<<<<<<<<<<
  * 
  *     def __dealloc__(self):
  */
-  __pyx_v_self->name = new std::string(__pyx_v_name);
+    __pyx_v_self->metric = EvaluationMetric::Instance((__pyx_v_self->name[0]));
+    goto __pyx_L3;
+  }
+  __pyx_L3:;
 
   __pyx_r = 0;
+  goto __pyx_L0;
+  __pyx_L1_error:;
+  __Pyx_AddTraceback("_cdec.Scorer.__cinit__", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __pyx_r = -1;
+  __pyx_L0:;
   __Pyx_RefNannyFinishContext();
   return __pyx_r;
 }
@@ -14202,8 +14379,8 @@ static void __pyx_pw_5_cdec_6Scorer_3__dealloc__(PyObject *__pyx_v_self) {
   __Pyx_RefNannyFinishContext();
 }
 
-/* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":118
- *         self.name = new string(name)
+/* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":126
+ *             self.metric = mteval.MetricInstance(self.name[0])
  * 
  *     def __dealloc__(self):             # <<<<<<<<<<<<<<
  *         del self.name
@@ -14214,7 +14391,7 @@ static void __pyx_pf_5_cdec_6Scorer_2__dealloc__(CYTHON_UNUSED struct __pyx_obj_
   __Pyx_RefNannyDeclarations
   __Pyx_RefNannySetupContext("__dealloc__", 0);
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":119
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":127
  * 
  *     def __dealloc__(self):
  *         del self.name             # <<<<<<<<<<<<<<
@@ -14252,7 +14429,7 @@ static PyObject *__pyx_pw_5_cdec_6Scorer_5__call__(PyObject *__pyx_v_self, PyObj
         else goto __pyx_L5_argtuple_error;
       }
       if (unlikely(kw_args > 0)) {
-        if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "__call__") < 0)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 121; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+        if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "__call__") < 0)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 129; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
       }
     } else if (PyTuple_GET_SIZE(__pyx_args) != 1) {
       goto __pyx_L5_argtuple_error;
@@ -14263,7 +14440,7 @@ static PyObject *__pyx_pw_5_cdec_6Scorer_5__call__(PyObject *__pyx_v_self, PyObj
   }
   goto __pyx_L4_argument_unpacking_done;
   __pyx_L5_argtuple_error:;
-  __Pyx_RaiseArgtupleInvalid("__call__", 1, 1, 1, PyTuple_GET_SIZE(__pyx_args)); {__pyx_filename = __pyx_f[5]; __pyx_lineno = 121; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+  __Pyx_RaiseArgtupleInvalid("__call__", 1, 1, 1, PyTuple_GET_SIZE(__pyx_args)); {__pyx_filename = __pyx_f[5]; __pyx_lineno = 129; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
   __pyx_L3_error:;
   __Pyx_AddTraceback("_cdec.Scorer.__call__", __pyx_clineno, __pyx_lineno, __pyx_filename);
   __Pyx_RefNannyFinishContext();
@@ -14274,16 +14451,15 @@ static PyObject *__pyx_pw_5_cdec_6Scorer_5__call__(PyObject *__pyx_v_self, PyObj
   return __pyx_r;
 }
 
-/* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":121
+/* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":129
  *         del self.name
  * 
  *     def __call__(self, refs):             # <<<<<<<<<<<<<<
- *         cdef mteval.EvaluationMetric* metric = mteval.Instance(self.name[0])
  *         if isinstance(refs, unicode) or isinstance(refs, str):
+ *             refs = [refs]
  */
 
 static PyObject *__pyx_pf_5_cdec_6Scorer_4__call__(struct __pyx_obj_5_cdec_Scorer *__pyx_v_self, PyObject *__pyx_v_refs) {
-  EvaluationMetric *__pyx_v_metric;
   std::vector<std::vector<WordID> > *__pyx_v_refsv;
   std::vector<WordID> *__pyx_v_refv;
   PyObject *__pyx_v_ref = NULL;
@@ -14304,18 +14480,9 @@ static PyObject *__pyx_pf_5_cdec_6Scorer_4__call__(struct __pyx_obj_5_cdec_Score
   __Pyx_RefNannySetupContext("__call__", 0);
   __Pyx_INCREF(__pyx_v_refs);
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":122
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":130
  * 
  *     def __call__(self, refs):
- *         cdef mteval.EvaluationMetric* metric = mteval.Instance(self.name[0])             # <<<<<<<<<<<<<<
- *         if isinstance(refs, unicode) or isinstance(refs, str):
- *             refs = [refs]
- */
-  __pyx_v_metric = EvaluationMetric::Instance((__pyx_v_self->name[0]));
-
-  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":123
- *     def __call__(self, refs):
- *         cdef mteval.EvaluationMetric* metric = mteval.Instance(self.name[0])
  *         if isinstance(refs, unicode) or isinstance(refs, str):             # <<<<<<<<<<<<<<
  *             refs = [refs]
  *         cdef vector[vector[WordID]]* refsv = new vector[vector[WordID]]()
@@ -14335,14 +14502,14 @@ static PyObject *__pyx_pf_5_cdec_6Scorer_4__call__(struct __pyx_obj_5_cdec_Score
   }
   if (__pyx_t_4) {
 
-    /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":124
- *         cdef mteval.EvaluationMetric* metric = mteval.Instance(self.name[0])
+    /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":131
+ *     def __call__(self, refs):
  *         if isinstance(refs, unicode) or isinstance(refs, str):
  *             refs = [refs]             # <<<<<<<<<<<<<<
  *         cdef vector[vector[WordID]]* refsv = new vector[vector[WordID]]()
  *         cdef vector[WordID]* refv
  */
-    __pyx_t_1 = PyList_New(1); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 124; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_t_1 = PyList_New(1); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 131; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
     __Pyx_GOTREF(__pyx_t_1);
     __Pyx_INCREF(__pyx_v_refs);
     PyList_SET_ITEM(__pyx_t_1, 0, __pyx_v_refs);
@@ -14354,7 +14521,7 @@ static PyObject *__pyx_pf_5_cdec_6Scorer_4__call__(struct __pyx_obj_5_cdec_Score
   }
   __pyx_L3:;
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":125
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":132
  *         if isinstance(refs, unicode) or isinstance(refs, str):
  *             refs = [refs]
  *         cdef vector[vector[WordID]]* refsv = new vector[vector[WordID]]()             # <<<<<<<<<<<<<<
@@ -14363,7 +14530,7 @@ static PyObject *__pyx_pf_5_cdec_6Scorer_4__call__(struct __pyx_obj_5_cdec_Score
  */
   __pyx_v_refsv = new std::vector<std::vector<WordID> >();
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":128
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":135
  *         cdef vector[WordID]* refv
  *         cdef bytes ref_str
  *         for ref in refs:             # <<<<<<<<<<<<<<
@@ -14374,7 +14541,7 @@ static PyObject *__pyx_pf_5_cdec_6Scorer_4__call__(struct __pyx_obj_5_cdec_Score
     __pyx_t_1 = __pyx_v_refs; __Pyx_INCREF(__pyx_t_1); __pyx_t_5 = 0;
     __pyx_t_6 = NULL;
   } else {
-    __pyx_t_5 = -1; __pyx_t_1 = PyObject_GetIter(__pyx_v_refs); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 128; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_t_5 = -1; __pyx_t_1 = PyObject_GetIter(__pyx_v_refs); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 135; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
     __Pyx_GOTREF(__pyx_t_1);
     __pyx_t_6 = Py_TYPE(__pyx_t_1)->tp_iternext;
   }
@@ -14390,7 +14557,7 @@ static PyObject *__pyx_pf_5_cdec_6Scorer_4__call__(struct __pyx_obj_5_cdec_Score
       if (unlikely(!__pyx_t_7)) {
         if (PyErr_Occurred()) {
           if (likely(PyErr_ExceptionMatches(PyExc_StopIteration))) PyErr_Clear();
-          else {__pyx_filename = __pyx_f[5]; __pyx_lineno = 128; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+          else {__pyx_filename = __pyx_f[5]; __pyx_lineno = 135; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
         }
         break;
       }
@@ -14400,7 +14567,7 @@ static PyObject *__pyx_pf_5_cdec_6Scorer_4__call__(struct __pyx_obj_5_cdec_Score
     __pyx_v_ref = __pyx_t_7;
     __pyx_t_7 = 0;
 
-    /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":129
+    /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":136
  *         cdef bytes ref_str
  *         for ref in refs:
  *             refv = new vector[WordID]()             # <<<<<<<<<<<<<<
@@ -14409,22 +14576,22 @@ static PyObject *__pyx_pf_5_cdec_6Scorer_4__call__(struct __pyx_obj_5_cdec_Score
  */
     __pyx_v_refv = new std::vector<WordID>();
 
-    /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":130
+    /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":137
  *         for ref in refs:
  *             refv = new vector[WordID]()
  *             ConvertSentence(string(as_str(ref.strip())), refv)             # <<<<<<<<<<<<<<
  *             refsv.push_back(refv[0])
  *             del refv
  */
-    __pyx_t_7 = PyObject_GetAttr(__pyx_v_ref, __pyx_n_s__strip); if (unlikely(!__pyx_t_7)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 130; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_t_7 = PyObject_GetAttr(__pyx_v_ref, __pyx_n_s__strip); if (unlikely(!__pyx_t_7)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 137; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
     __Pyx_GOTREF(__pyx_t_7);
-    __pyx_t_8 = PyObject_Call(__pyx_t_7, ((PyObject *)__pyx_empty_tuple), NULL); if (unlikely(!__pyx_t_8)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 130; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_t_8 = PyObject_Call(__pyx_t_7, ((PyObject *)__pyx_empty_tuple), NULL); if (unlikely(!__pyx_t_8)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 137; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
     __Pyx_GOTREF(__pyx_t_8);
     __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;
     TD::ConvertSentence(std::string(__pyx_f_5_cdec_as_str(__pyx_t_8, NULL)), __pyx_v_refv);
     __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0;
 
-    /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":131
+    /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":138
  *             refv = new vector[WordID]()
  *             ConvertSentence(string(as_str(ref.strip())), refv)
  *             refsv.push_back(refv[0])             # <<<<<<<<<<<<<<
@@ -14433,7 +14600,7 @@ static PyObject *__pyx_pf_5_cdec_6Scorer_4__call__(struct __pyx_obj_5_cdec_Score
  */
     __pyx_v_refsv->push_back((__pyx_v_refv[0]));
 
-    /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":132
+    /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":139
  *             ConvertSentence(string(as_str(ref.strip())), refv)
  *             refsv.push_back(refv[0])
  *             del refv             # <<<<<<<<<<<<<<
@@ -14444,47 +14611,47 @@ static PyObject *__pyx_pf_5_cdec_6Scorer_4__call__(struct __pyx_obj_5_cdec_Score
   }
   __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":134
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":141
  *             del refv
  *         cdef unsigned i
  *         cdef SegmentEvaluator evaluator = SegmentEvaluator()             # <<<<<<<<<<<<<<
- *         evaluator.metric = metric
- *         evaluator.scorer = new shared_ptr[mteval.SegmentEvaluator](metric.CreateSegmentEvaluator(refsv[0]))
+ *         evaluator.metric = self.metric
+ *         evaluator.scorer = new shared_ptr[mteval.SegmentEvaluator](
  */
-  __pyx_t_1 = PyObject_Call(((PyObject *)((PyObject*)__pyx_ptype_5_cdec_SegmentEvaluator)), ((PyObject *)__pyx_empty_tuple), NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 134; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_1 = PyObject_Call(((PyObject *)((PyObject*)__pyx_ptype_5_cdec_SegmentEvaluator)), ((PyObject *)__pyx_empty_tuple), NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 141; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __Pyx_GOTREF(__pyx_t_1);
   __pyx_v_evaluator = ((struct __pyx_obj_5_cdec_SegmentEvaluator *)__pyx_t_1);
   __pyx_t_1 = 0;
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":135
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":142
  *         cdef unsigned i
  *         cdef SegmentEvaluator evaluator = SegmentEvaluator()
- *         evaluator.metric = metric             # <<<<<<<<<<<<<<
- *         evaluator.scorer = new shared_ptr[mteval.SegmentEvaluator](metric.CreateSegmentEvaluator(refsv[0]))
- *         del refsv # in theory should not delete but store in SegmentEvaluator
+ *         evaluator.metric = self.metric             # <<<<<<<<<<<<<<
+ *         evaluator.scorer = new shared_ptr[mteval.SegmentEvaluator](
+ *                 self.metric.CreateSegmentEvaluator(refsv[0]))
  */
-  __pyx_v_evaluator->metric = __pyx_v_metric;
+  __pyx_v_evaluator->metric = __pyx_v_self->metric;
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":136
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":143
  *         cdef SegmentEvaluator evaluator = SegmentEvaluator()
- *         evaluator.metric = metric
- *         evaluator.scorer = new shared_ptr[mteval.SegmentEvaluator](metric.CreateSegmentEvaluator(refsv[0]))             # <<<<<<<<<<<<<<
+ *         evaluator.metric = self.metric
+ *         evaluator.scorer = new shared_ptr[mteval.SegmentEvaluator](             # <<<<<<<<<<<<<<
+ *                 self.metric.CreateSegmentEvaluator(refsv[0]))
  *         del refsv # in theory should not delete but store in SegmentEvaluator
- *         return evaluator
  */
-  __pyx_v_evaluator->scorer = new boost::shared_ptr<SegmentEvaluator>(__pyx_v_metric->CreateSegmentEvaluator((__pyx_v_refsv[0])));
+  __pyx_v_evaluator->scorer = new boost::shared_ptr<SegmentEvaluator>(__pyx_v_self->metric->CreateSegmentEvaluator((__pyx_v_refsv[0])));
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":137
- *         evaluator.metric = metric
- *         evaluator.scorer = new shared_ptr[mteval.SegmentEvaluator](metric.CreateSegmentEvaluator(refsv[0]))
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":145
+ *         evaluator.scorer = new shared_ptr[mteval.SegmentEvaluator](
+ *                 self.metric.CreateSegmentEvaluator(refsv[0]))
  *         del refsv # in theory should not delete but store in SegmentEvaluator             # <<<<<<<<<<<<<<
  *         return evaluator
  * 
  */
   delete __pyx_v_refsv;
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":138
- *         evaluator.scorer = new shared_ptr[mteval.SegmentEvaluator](metric.CreateSegmentEvaluator(refsv[0]))
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":146
+ *                 self.metric.CreateSegmentEvaluator(refsv[0]))
  *         del refsv # in theory should not delete but store in SegmentEvaluator
  *         return evaluator             # <<<<<<<<<<<<<<
  * 
@@ -14523,7 +14690,7 @@ static PyObject *__pyx_pw_5_cdec_6Scorer_7__str__(PyObject *__pyx_v_self) {
   return __pyx_r;
 }
 
-/* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":140
+/* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":148
  *         return evaluator
  * 
  *     def __str__(self):             # <<<<<<<<<<<<<<
@@ -14540,15 +14707,15 @@ static PyObject *__pyx_pf_5_cdec_6Scorer_6__str__(struct __pyx_obj_5_cdec_Scorer
   int __pyx_clineno = 0;
   __Pyx_RefNannySetupContext("__str__", 0);
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":141
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":149
  * 
  *     def __str__(self):
  *         return self.name.c_str()             # <<<<<<<<<<<<<<
  * 
- * BLEU = Scorer('IBM_BLEU')
+ * cdef float _compute_score(void* metric_, mteval.SufficientStats* stats):
  */
   __Pyx_XDECREF(__pyx_r);
-  __pyx_t_1 = PyBytes_FromString(__pyx_v_self->name->c_str()); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 141; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_1 = PyBytes_FromString(__pyx_v_self->name->c_str()); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 149; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __Pyx_GOTREF(((PyObject *)__pyx_t_1));
   __pyx_r = ((PyObject *)__pyx_t_1);
   __pyx_t_1 = 0;
@@ -14565,71 +14732,661 @@ static PyObject *__pyx_pf_5_cdec_6Scorer_6__str__(struct __pyx_obj_5_cdec_Scorer
   __Pyx_RefNannyFinishContext();
   return __pyx_r;
 }
-static PyObject *__pyx_gb_5_cdec_4generator16(__pyx_GeneratorObject *__pyx_generator, PyObject *__pyx_sent_value); /* proto */
-
-/* Python wrapper */
-static PyObject *__pyx_pw_5_cdec_3_make_config(PyObject *__pyx_self, PyObject *__pyx_v_config); /*proto*/
-static PyMethodDef __pyx_mdef_5_cdec_3_make_config = {__Pyx_NAMESTR("_make_config"), (PyCFunction)__pyx_pw_5_cdec_3_make_config, METH_O, __Pyx_DOCSTR(0)};
-static PyObject *__pyx_pw_5_cdec_3_make_config(PyObject *__pyx_self, PyObject *__pyx_v_config) {
-  PyObject *__pyx_r = 0;
-  __Pyx_RefNannyDeclarations
-  __Pyx_RefNannySetupContext("_make_config (wrapper)", 0);
-  __pyx_self = __pyx_self;
-  __pyx_r = __pyx_pf_5_cdec_2_make_config(__pyx_self, ((PyObject *)__pyx_v_config));
-  __Pyx_RefNannyFinishContext();
-  return __pyx_r;
-}
 
-/* "_cdec.pyx":28
- * class ParseFailed(Exception): pass
+/* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":151
+ *         return self.name.c_str()
  * 
- * def _make_config(config):             # <<<<<<<<<<<<<<
- *     for key, value in config.items():
- *         if isinstance(value, dict):
+ * cdef float _compute_score(void* metric_, mteval.SufficientStats* stats):             # <<<<<<<<<<<<<<
+ *     cdef Metric metric = <Metric> metric_
+ *     cdef list ss = []
  */
 
-static PyObject *__pyx_pf_5_cdec_2_make_config(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_config) {
-  struct __pyx_obj_5_cdec___pyx_scope_struct_22__make_config *__pyx_cur_scope;
-  PyObject *__pyx_r = NULL;
+static float __pyx_f_5_cdec__compute_score(void *__pyx_v_metric_, SufficientStats *__pyx_v_stats) {
+  struct __pyx_obj_5_cdec_Metric *__pyx_v_metric = 0;
+  PyObject *__pyx_v_ss = 0;
+  unsigned int __pyx_v_i;
+  float __pyx_r;
   __Pyx_RefNannyDeclarations
+  PyObject *__pyx_t_1 = NULL;
+  unsigned int __pyx_t_2;
+  unsigned int __pyx_t_3;
+  int __pyx_t_4;
+  PyObject *__pyx_t_5 = NULL;
+  PyObject *__pyx_t_6 = NULL;
+  float __pyx_t_7;
   int __pyx_lineno = 0;
   const char *__pyx_filename = NULL;
   int __pyx_clineno = 0;
-  __Pyx_RefNannySetupContext("_make_config", 0);
-  __pyx_cur_scope = (struct __pyx_obj_5_cdec___pyx_scope_struct_22__make_config *)__pyx_ptype_5_cdec___pyx_scope_struct_22__make_config->tp_new(__pyx_ptype_5_cdec___pyx_scope_struct_22__make_config, __pyx_empty_tuple, NULL);
-  if (unlikely(!__pyx_cur_scope)) {
-    __Pyx_RefNannyFinishContext();
-    return NULL;
-  }
-  __Pyx_GOTREF(__pyx_cur_scope);
-  __pyx_cur_scope->__pyx_v_config = __pyx_v_config;
-  __Pyx_INCREF(__pyx_cur_scope->__pyx_v_config);
-  __Pyx_GIVEREF(__pyx_cur_scope->__pyx_v_config);
-  {
-    __pyx_GeneratorObject *gen = __Pyx_Generator_New((__pyx_generator_body_t) __pyx_gb_5_cdec_4generator16, (PyObject *) __pyx_cur_scope); if (unlikely(!gen)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 28; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-    __Pyx_DECREF(__pyx_cur_scope);
-    __Pyx_RefNannyFinishContext();
-    return (PyObject *) gen;
-  }
+  __Pyx_RefNannySetupContext("_compute_score", 0);
 
-  __pyx_r = Py_None; __Pyx_INCREF(Py_None);
-  goto __pyx_L0;
-  __pyx_L1_error:;
-  __Pyx_AddTraceback("_cdec._make_config", __pyx_clineno, __pyx_lineno, __pyx_filename);
-  __pyx_r = NULL;
-  __pyx_L0:;
-  __Pyx_DECREF(((PyObject *)__pyx_cur_scope));
-  __Pyx_XGIVEREF(__pyx_r);
-  __Pyx_RefNannyFinishContext();
-  return __pyx_r;
-}
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":152
+ * 
+ * cdef float _compute_score(void* metric_, mteval.SufficientStats* stats):
+ *     cdef Metric metric = <Metric> metric_             # <<<<<<<<<<<<<<
+ *     cdef list ss = []
+ *     cdef unsigned i
+ */
+  __Pyx_INCREF(((PyObject *)((struct __pyx_obj_5_cdec_Metric *)__pyx_v_metric_)));
+  __pyx_v_metric = ((struct __pyx_obj_5_cdec_Metric *)__pyx_v_metric_);
 
-static PyObject *__pyx_gb_5_cdec_4generator16(__pyx_GeneratorObject *__pyx_generator, PyObject *__pyx_sent_value) /* generator body */
-{
-  struct __pyx_obj_5_cdec___pyx_scope_struct_22__make_config *__pyx_cur_scope = ((struct __pyx_obj_5_cdec___pyx_scope_struct_22__make_config *)__pyx_generator->closure);
-  PyObject *__pyx_r = NULL;
-  PyObject *__pyx_t_1 = NULL;
-  PyObject *__pyx_t_2 = NULL;
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":153
+ * cdef float _compute_score(void* metric_, mteval.SufficientStats* stats):
+ *     cdef Metric metric = <Metric> metric_
+ *     cdef list ss = []             # <<<<<<<<<<<<<<
+ *     cdef unsigned i
+ *     for i in range(stats.size()):
+ */
+  __pyx_t_1 = PyList_New(0); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 153; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_1);
+  __pyx_v_ss = __pyx_t_1;
+  __pyx_t_1 = 0;
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":155
+ *     cdef list ss = []
+ *     cdef unsigned i
+ *     for i in range(stats.size()):             # <<<<<<<<<<<<<<
+ *         ss.append(stats[0][i])
+ *     return metric.score(ss)
+ */
+  __pyx_t_2 = __pyx_v_stats->size();
+  for (__pyx_t_3 = 0; __pyx_t_3 < __pyx_t_2; __pyx_t_3+=1) {
+    __pyx_v_i = __pyx_t_3;
+
+    /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":156
+ *     cdef unsigned i
+ *     for i in range(stats.size()):
+ *         ss.append(stats[0][i])             # <<<<<<<<<<<<<<
+ *     return metric.score(ss)
+ * 
+ */
+    __pyx_t_1 = PyFloat_FromDouble(((__pyx_v_stats[0])[__pyx_v_i])); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 156; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_1);
+    __pyx_t_4 = PyList_Append(__pyx_v_ss, __pyx_t_1); if (unlikely(__pyx_t_4 == -1)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 156; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+  }
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":157
+ *     for i in range(stats.size()):
+ *         ss.append(stats[0][i])
+ *     return metric.score(ss)             # <<<<<<<<<<<<<<
+ * 
+ * cdef void _compute_sufficient_stats(void* metric_,
+ */
+  __pyx_t_1 = PyObject_GetAttr(((PyObject *)__pyx_v_metric), __pyx_n_s__score); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 157; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_1);
+  __pyx_t_5 = PyTuple_New(1); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 157; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_5);
+  __Pyx_INCREF(((PyObject *)__pyx_v_ss));
+  PyTuple_SET_ITEM(__pyx_t_5, 0, ((PyObject *)__pyx_v_ss));
+  __Pyx_GIVEREF(((PyObject *)__pyx_v_ss));
+  __pyx_t_6 = PyObject_Call(__pyx_t_1, ((PyObject *)__pyx_t_5), NULL); if (unlikely(!__pyx_t_6)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 157; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_6);
+  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+  __Pyx_DECREF(((PyObject *)__pyx_t_5)); __pyx_t_5 = 0;
+  __pyx_t_7 = __pyx_PyFloat_AsFloat(__pyx_t_6); if (unlikely((__pyx_t_7 == (float)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 157; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0;
+  __pyx_r = __pyx_t_7;
+  goto __pyx_L0;
+
+  __pyx_r = 0;
+  goto __pyx_L0;
+  __pyx_L1_error:;
+  __Pyx_XDECREF(__pyx_t_1);
+  __Pyx_XDECREF(__pyx_t_5);
+  __Pyx_XDECREF(__pyx_t_6);
+  __Pyx_WriteUnraisable("_cdec._compute_score", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __pyx_r = 0;
+  __pyx_L0:;
+  __Pyx_XDECREF((PyObject *)__pyx_v_metric);
+  __Pyx_XDECREF(__pyx_v_ss);
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+/* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":159
+ *     return metric.score(ss)
+ * 
+ * cdef void _compute_sufficient_stats(void* metric_,             # <<<<<<<<<<<<<<
+ *         string* hyp,
+ *         vector[string]* refs,
+ */
+
+static void __pyx_f_5_cdec__compute_sufficient_stats(void *__pyx_v_metric_, std::string *__pyx_v_hyp, std::vector<std::string> *__pyx_v_refs, SufficientStats *__pyx_v_out) {
+  struct __pyx_obj_5_cdec_Metric *__pyx_v_metric = 0;
+  PyObject *__pyx_v_refs_ = 0;
+  unsigned int __pyx_v_i;
+  PyObject *__pyx_v_ss = 0;
+  __Pyx_RefNannyDeclarations
+  PyObject *__pyx_t_1 = NULL;
+  size_t __pyx_t_2;
+  unsigned int __pyx_t_3;
+  int __pyx_t_4;
+  PyObject *__pyx_t_5 = NULL;
+  PyObject *__pyx_t_6 = NULL;
+  Py_ssize_t __pyx_t_7;
+  float __pyx_t_8;
+  int __pyx_lineno = 0;
+  const char *__pyx_filename = NULL;
+  int __pyx_clineno = 0;
+  __Pyx_RefNannySetupContext("_compute_sufficient_stats", 0);
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":163
+ *         vector[string]* refs,
+ *         mteval.SufficientStats* out):
+ *     cdef Metric metric = <Metric> metric_             # <<<<<<<<<<<<<<
+ *     cdef list refs_ = []
+ *     cdef unsigned i
+ */
+  __Pyx_INCREF(((PyObject *)((struct __pyx_obj_5_cdec_Metric *)__pyx_v_metric_)));
+  __pyx_v_metric = ((struct __pyx_obj_5_cdec_Metric *)__pyx_v_metric_);
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":164
+ *         mteval.SufficientStats* out):
+ *     cdef Metric metric = <Metric> metric_
+ *     cdef list refs_ = []             # <<<<<<<<<<<<<<
+ *     cdef unsigned i
+ *     for i in range(refs.size()):
+ */
+  __pyx_t_1 = PyList_New(0); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 164; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_1);
+  __pyx_v_refs_ = __pyx_t_1;
+  __pyx_t_1 = 0;
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":166
+ *     cdef list refs_ = []
+ *     cdef unsigned i
+ *     for i in range(refs.size()):             # <<<<<<<<<<<<<<
+ *         refs_.append(refs[0][i].c_str())
+ *     cdef list ss = metric.evaluate(hyp.c_str(), refs_)
+ */
+  __pyx_t_2 = __pyx_v_refs->size();
+  for (__pyx_t_3 = 0; __pyx_t_3 < __pyx_t_2; __pyx_t_3+=1) {
+    __pyx_v_i = __pyx_t_3;
+
+    /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":167
+ *     cdef unsigned i
+ *     for i in range(refs.size()):
+ *         refs_.append(refs[0][i].c_str())             # <<<<<<<<<<<<<<
+ *     cdef list ss = metric.evaluate(hyp.c_str(), refs_)
+ *     out.fields.resize(len(ss))
+ */
+    __pyx_t_1 = PyBytes_FromString(((__pyx_v_refs[0])[__pyx_v_i]).c_str()); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 167; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(((PyObject *)__pyx_t_1));
+    __pyx_t_4 = PyList_Append(__pyx_v_refs_, ((PyObject *)__pyx_t_1)); if (unlikely(__pyx_t_4 == -1)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 167; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_DECREF(((PyObject *)__pyx_t_1)); __pyx_t_1 = 0;
+  }
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":168
+ *     for i in range(refs.size()):
+ *         refs_.append(refs[0][i].c_str())
+ *     cdef list ss = metric.evaluate(hyp.c_str(), refs_)             # <<<<<<<<<<<<<<
+ *     out.fields.resize(len(ss))
+ *     for i in range(len(ss)):
+ */
+  __pyx_t_1 = PyObject_GetAttr(((PyObject *)__pyx_v_metric), __pyx_n_s__evaluate); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 168; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_1);
+  __pyx_t_5 = PyBytes_FromString(__pyx_v_hyp->c_str()); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 168; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(((PyObject *)__pyx_t_5));
+  __pyx_t_6 = PyTuple_New(2); if (unlikely(!__pyx_t_6)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 168; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_6);
+  PyTuple_SET_ITEM(__pyx_t_6, 0, ((PyObject *)__pyx_t_5));
+  __Pyx_GIVEREF(((PyObject *)__pyx_t_5));
+  __Pyx_INCREF(((PyObject *)__pyx_v_refs_));
+  PyTuple_SET_ITEM(__pyx_t_6, 1, ((PyObject *)__pyx_v_refs_));
+  __Pyx_GIVEREF(((PyObject *)__pyx_v_refs_));
+  __pyx_t_5 = 0;
+  __pyx_t_5 = PyObject_Call(__pyx_t_1, ((PyObject *)__pyx_t_6), NULL); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 168; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_5);
+  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+  __Pyx_DECREF(((PyObject *)__pyx_t_6)); __pyx_t_6 = 0;
+  if (!(likely(PyList_CheckExact(__pyx_t_5))||((__pyx_t_5) == Py_None)||(PyErr_Format(PyExc_TypeError, "Expected list, got %.200s", Py_TYPE(__pyx_t_5)->tp_name), 0))) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 168; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_v_ss = ((PyObject*)__pyx_t_5);
+  __pyx_t_5 = 0;
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":169
+ *         refs_.append(refs[0][i].c_str())
+ *     cdef list ss = metric.evaluate(hyp.c_str(), refs_)
+ *     out.fields.resize(len(ss))             # <<<<<<<<<<<<<<
+ *     for i in range(len(ss)):
+ *         out.fields[i] = ss[i]
+ */
+  if (unlikely(((PyObject *)__pyx_v_ss) == Py_None)) {
+    PyErr_SetString(PyExc_TypeError, "object of type 'NoneType' has no len()"); {__pyx_filename = __pyx_f[5]; __pyx_lineno = 169; __pyx_clineno = __LINE__; goto __pyx_L1_error;} 
+  }
+  __pyx_t_7 = PyList_GET_SIZE(((PyObject *)__pyx_v_ss)); 
+  __pyx_v_out->fields.resize(__pyx_t_7);
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":170
+ *     cdef list ss = metric.evaluate(hyp.c_str(), refs_)
+ *     out.fields.resize(len(ss))
+ *     for i in range(len(ss)):             # <<<<<<<<<<<<<<
+ *         out.fields[i] = ss[i]
+ * 
+ */
+  if (unlikely(((PyObject *)__pyx_v_ss) == Py_None)) {
+    PyErr_SetString(PyExc_TypeError, "object of type 'NoneType' has no len()"); {__pyx_filename = __pyx_f[5]; __pyx_lineno = 170; __pyx_clineno = __LINE__; goto __pyx_L1_error;} 
+  }
+  __pyx_t_7 = PyList_GET_SIZE(((PyObject *)__pyx_v_ss)); 
+  for (__pyx_t_3 = 0; __pyx_t_3 < __pyx_t_7; __pyx_t_3+=1) {
+    __pyx_v_i = __pyx_t_3;
+
+    /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":171
+ *     out.fields.resize(len(ss))
+ *     for i in range(len(ss)):
+ *         out.fields[i] = ss[i]             # <<<<<<<<<<<<<<
+ * 
+ * cdef class Metric:
+ */
+    __pyx_t_5 = __Pyx_GetItemInt_List(((PyObject *)__pyx_v_ss), __pyx_v_i, sizeof(unsigned int)+1, PyLong_FromUnsignedLong); if (!__pyx_t_5) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 171; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_GOTREF(__pyx_t_5);
+    __pyx_t_8 = __pyx_PyFloat_AsFloat(__pyx_t_5); if (unlikely((__pyx_t_8 == (float)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 171; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
+    (__pyx_v_out->fields[__pyx_v_i]) = __pyx_t_8;
+  }
+
+  goto __pyx_L0;
+  __pyx_L1_error:;
+  __Pyx_XDECREF(__pyx_t_1);
+  __Pyx_XDECREF(__pyx_t_5);
+  __Pyx_XDECREF(__pyx_t_6);
+  __Pyx_WriteUnraisable("_cdec._compute_sufficient_stats", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __pyx_L0:;
+  __Pyx_XDECREF((PyObject *)__pyx_v_metric);
+  __Pyx_XDECREF(__pyx_v_refs_);
+  __Pyx_XDECREF(__pyx_v_ss);
+  __Pyx_RefNannyFinishContext();
+}
+
+/* Python wrapper */
+static int __pyx_pw_5_cdec_6Metric_1__cinit__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/
+static int __pyx_pw_5_cdec_6Metric_1__cinit__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) {
+  int __pyx_r;
+  __Pyx_RefNannyDeclarations
+  __Pyx_RefNannySetupContext("__cinit__ (wrapper)", 0);
+  if (unlikely(PyTuple_GET_SIZE(__pyx_args) > 0)) {
+    __Pyx_RaiseArgtupleInvalid("__cinit__", 1, 0, 0, PyTuple_GET_SIZE(__pyx_args)); return -1;}
+  if (unlikely(__pyx_kwds) && unlikely(PyDict_Size(__pyx_kwds) > 0) && unlikely(!__Pyx_CheckKeywordStrings(__pyx_kwds, "__cinit__", 0))) return -1;
+  __pyx_r = __pyx_pf_5_cdec_6Metric___cinit__(((struct __pyx_obj_5_cdec_Metric *)__pyx_v_self));
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+/* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":175
+ * cdef class Metric:
+ *     cdef Scorer scorer
+ *     def __cinit__(self):             # <<<<<<<<<<<<<<
+ *         self.scorer = Scorer()
+ *         self.scorer.name = new string(as_str(self.__class__.__name__))
+ */
+
+static int __pyx_pf_5_cdec_6Metric___cinit__(struct __pyx_obj_5_cdec_Metric *__pyx_v_self) {
+  int __pyx_r;
+  __Pyx_RefNannyDeclarations
+  PyObject *__pyx_t_1 = NULL;
+  PyObject *__pyx_t_2 = NULL;
+  int __pyx_lineno = 0;
+  const char *__pyx_filename = NULL;
+  int __pyx_clineno = 0;
+  __Pyx_RefNannySetupContext("__cinit__", 0);
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":176
+ *     cdef Scorer scorer
+ *     def __cinit__(self):
+ *         self.scorer = Scorer()             # <<<<<<<<<<<<<<
+ *         self.scorer.name = new string(as_str(self.__class__.__name__))
+ *         self.scorer.metric = mteval.PyMetricInstance(self.scorer.name[0],
+ */
+  __pyx_t_1 = PyObject_Call(((PyObject *)((PyObject*)__pyx_ptype_5_cdec_Scorer)), ((PyObject *)__pyx_empty_tuple), NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 176; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_1);
+  __Pyx_GIVEREF(__pyx_t_1);
+  __Pyx_GOTREF(__pyx_v_self->scorer);
+  __Pyx_DECREF(((PyObject *)__pyx_v_self->scorer));
+  __pyx_v_self->scorer = ((struct __pyx_obj_5_cdec_Scorer *)__pyx_t_1);
+  __pyx_t_1 = 0;
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":177
+ *     def __cinit__(self):
+ *         self.scorer = Scorer()
+ *         self.scorer.name = new string(as_str(self.__class__.__name__))             # <<<<<<<<<<<<<<
+ *         self.scorer.metric = mteval.PyMetricInstance(self.scorer.name[0],
+ *                 <void*> self, _compute_sufficient_stats, _compute_score)
+ */
+  __pyx_t_1 = PyObject_GetAttr(((PyObject *)__pyx_v_self), __pyx_n_s____class__); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 177; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_1);
+  __pyx_t_2 = PyObject_GetAttr(__pyx_t_1, __pyx_n_s____name__); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 177; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_2);
+  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+  __pyx_v_self->scorer->name = new std::string(__pyx_f_5_cdec_as_str(__pyx_t_2, NULL));
+  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":178
+ *         self.scorer = Scorer()
+ *         self.scorer.name = new string(as_str(self.__class__.__name__))
+ *         self.scorer.metric = mteval.PyMetricInstance(self.scorer.name[0],             # <<<<<<<<<<<<<<
+ *                 <void*> self, _compute_sufficient_stats, _compute_score)
+ * 
+ */
+  __pyx_v_self->scorer->metric = PythonEvaluationMetric::Instance((__pyx_v_self->scorer->name[0]), ((void *)__pyx_v_self), __pyx_f_5_cdec__compute_sufficient_stats, __pyx_f_5_cdec__compute_score);
+
+  __pyx_r = 0;
+  goto __pyx_L0;
+  __pyx_L1_error:;
+  __Pyx_XDECREF(__pyx_t_1);
+  __Pyx_XDECREF(__pyx_t_2);
+  __Pyx_AddTraceback("_cdec.Metric.__cinit__", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __pyx_r = -1;
+  __pyx_L0:;
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+/* Python wrapper */
+static PyObject *__pyx_pw_5_cdec_6Metric_3__call__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/
+static PyObject *__pyx_pw_5_cdec_6Metric_3__call__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) {
+  PyObject *__pyx_v_refs = 0;
+  static PyObject **__pyx_pyargnames[] = {&__pyx_n_s__refs,0};
+  PyObject *__pyx_r = 0;
+  __Pyx_RefNannyDeclarations
+  __Pyx_RefNannySetupContext("__call__ (wrapper)", 0);
+  {
+    PyObject* values[1] = {0};
+    if (unlikely(__pyx_kwds)) {
+      Py_ssize_t kw_args;
+      const Py_ssize_t pos_args = PyTuple_GET_SIZE(__pyx_args);
+      switch (pos_args) {
+        case  1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0);
+        case  0: break;
+        default: goto __pyx_L5_argtuple_error;
+      }
+      kw_args = PyDict_Size(__pyx_kwds);
+      switch (pos_args) {
+        case  0:
+        values[0] = PyDict_GetItem(__pyx_kwds, __pyx_n_s__refs);
+        if (likely(values[0])) kw_args--;
+        else goto __pyx_L5_argtuple_error;
+      }
+      if (unlikely(kw_args > 0)) {
+        if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "__call__") < 0)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 181; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+      }
+    } else if (PyTuple_GET_SIZE(__pyx_args) != 1) {
+      goto __pyx_L5_argtuple_error;
+    } else {
+      values[0] = PyTuple_GET_ITEM(__pyx_args, 0);
+    }
+    __pyx_v_refs = values[0];
+  }
+  goto __pyx_L4_argument_unpacking_done;
+  __pyx_L5_argtuple_error:;
+  __Pyx_RaiseArgtupleInvalid("__call__", 1, 1, 1, PyTuple_GET_SIZE(__pyx_args)); {__pyx_filename = __pyx_f[5]; __pyx_lineno = 181; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+  __pyx_L3_error:;
+  __Pyx_AddTraceback("_cdec.Metric.__call__", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __Pyx_RefNannyFinishContext();
+  return NULL;
+  __pyx_L4_argument_unpacking_done:;
+  __pyx_r = __pyx_pf_5_cdec_6Metric_2__call__(((struct __pyx_obj_5_cdec_Metric *)__pyx_v_self), __pyx_v_refs);
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+/* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":181
+ *                 <void*> self, _compute_sufficient_stats, _compute_score)
+ * 
+ *     def __call__(self, refs):             # <<<<<<<<<<<<<<
+ *         return self.scorer(refs)
+ * 
+ */
+
+static PyObject *__pyx_pf_5_cdec_6Metric_2__call__(struct __pyx_obj_5_cdec_Metric *__pyx_v_self, PyObject *__pyx_v_refs) {
+  PyObject *__pyx_r = NULL;
+  __Pyx_RefNannyDeclarations
+  PyObject *__pyx_t_1 = NULL;
+  PyObject *__pyx_t_2 = NULL;
+  int __pyx_lineno = 0;
+  const char *__pyx_filename = NULL;
+  int __pyx_clineno = 0;
+  __Pyx_RefNannySetupContext("__call__", 0);
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":182
+ * 
+ *     def __call__(self, refs):
+ *         return self.scorer(refs)             # <<<<<<<<<<<<<<
+ * 
+ *     def score(SufficientStats stats):
+ */
+  __Pyx_XDECREF(__pyx_r);
+  __pyx_t_1 = PyTuple_New(1); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 182; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_1);
+  __Pyx_INCREF(__pyx_v_refs);
+  PyTuple_SET_ITEM(__pyx_t_1, 0, __pyx_v_refs);
+  __Pyx_GIVEREF(__pyx_v_refs);
+  __pyx_t_2 = PyObject_Call(((PyObject *)__pyx_v_self->scorer), ((PyObject *)__pyx_t_1), NULL); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 182; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_2);
+  __Pyx_DECREF(((PyObject *)__pyx_t_1)); __pyx_t_1 = 0;
+  __pyx_r = __pyx_t_2;
+  __pyx_t_2 = 0;
+  goto __pyx_L0;
+
+  __pyx_r = Py_None; __Pyx_INCREF(Py_None);
+  goto __pyx_L0;
+  __pyx_L1_error:;
+  __Pyx_XDECREF(__pyx_t_1);
+  __Pyx_XDECREF(__pyx_t_2);
+  __Pyx_AddTraceback("_cdec.Metric.__call__", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __pyx_r = NULL;
+  __pyx_L0:;
+  __Pyx_XGIVEREF(__pyx_r);
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+/* Python wrapper */
+static PyObject *__pyx_pw_5_cdec_6Metric_5score(PyObject *__pyx_v_stats, CYTHON_UNUSED PyObject *unused); /*proto*/
+static PyObject *__pyx_pw_5_cdec_6Metric_5score(PyObject *__pyx_v_stats, CYTHON_UNUSED PyObject *unused) {
+  PyObject *__pyx_r = 0;
+  __Pyx_RefNannyDeclarations
+  __Pyx_RefNannySetupContext("score (wrapper)", 0);
+  __pyx_r = __pyx_pf_5_cdec_6Metric_4score(((struct __pyx_obj_5_cdec_Metric *)__pyx_v_stats));
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+/* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":184
+ *         return self.scorer(refs)
+ * 
+ *     def score(SufficientStats stats):             # <<<<<<<<<<<<<<
+ *         return 0
+ * 
+ */
+
+static PyObject *__pyx_pf_5_cdec_6Metric_4score(CYTHON_UNUSED struct __pyx_obj_5_cdec_Metric *__pyx_v_stats) {
+  PyObject *__pyx_r = NULL;
+  __Pyx_RefNannyDeclarations
+  __Pyx_RefNannySetupContext("score", 0);
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":185
+ * 
+ *     def score(SufficientStats stats):
+ *         return 0             # <<<<<<<<<<<<<<
+ * 
+ *     def evaluate(self, hyp, refs):
+ */
+  __Pyx_XDECREF(__pyx_r);
+  __Pyx_INCREF(__pyx_int_0);
+  __pyx_r = __pyx_int_0;
+  goto __pyx_L0;
+
+  __pyx_r = Py_None; __Pyx_INCREF(Py_None);
+  __pyx_L0:;
+  __Pyx_XGIVEREF(__pyx_r);
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+/* Python wrapper */
+static PyObject *__pyx_pw_5_cdec_6Metric_7evaluate(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/
+static PyObject *__pyx_pw_5_cdec_6Metric_7evaluate(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) {
+  CYTHON_UNUSED PyObject *__pyx_v_hyp = 0;
+  CYTHON_UNUSED PyObject *__pyx_v_refs = 0;
+  static PyObject **__pyx_pyargnames[] = {&__pyx_n_s__hyp,&__pyx_n_s__refs,0};
+  PyObject *__pyx_r = 0;
+  __Pyx_RefNannyDeclarations
+  __Pyx_RefNannySetupContext("evaluate (wrapper)", 0);
+  {
+    PyObject* values[2] = {0,0};
+    if (unlikely(__pyx_kwds)) {
+      Py_ssize_t kw_args;
+      const Py_ssize_t pos_args = PyTuple_GET_SIZE(__pyx_args);
+      switch (pos_args) {
+        case  2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1);
+        case  1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0);
+        case  0: break;
+        default: goto __pyx_L5_argtuple_error;
+      }
+      kw_args = PyDict_Size(__pyx_kwds);
+      switch (pos_args) {
+        case  0:
+        values[0] = PyDict_GetItem(__pyx_kwds, __pyx_n_s__hyp);
+        if (likely(values[0])) kw_args--;
+        else goto __pyx_L5_argtuple_error;
+        case  1:
+        values[1] = PyDict_GetItem(__pyx_kwds, __pyx_n_s__refs);
+        if (likely(values[1])) kw_args--;
+        else {
+          __Pyx_RaiseArgtupleInvalid("evaluate", 1, 2, 2, 1); {__pyx_filename = __pyx_f[5]; __pyx_lineno = 187; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+        }
+      }
+      if (unlikely(kw_args > 0)) {
+        if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "evaluate") < 0)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 187; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+      }
+    } else if (PyTuple_GET_SIZE(__pyx_args) != 2) {
+      goto __pyx_L5_argtuple_error;
+    } else {
+      values[0] = PyTuple_GET_ITEM(__pyx_args, 0);
+      values[1] = PyTuple_GET_ITEM(__pyx_args, 1);
+    }
+    __pyx_v_hyp = values[0];
+    __pyx_v_refs = values[1];
+  }
+  goto __pyx_L4_argument_unpacking_done;
+  __pyx_L5_argtuple_error:;
+  __Pyx_RaiseArgtupleInvalid("evaluate", 1, 2, 2, PyTuple_GET_SIZE(__pyx_args)); {__pyx_filename = __pyx_f[5]; __pyx_lineno = 187; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
+  __pyx_L3_error:;
+  __Pyx_AddTraceback("_cdec.Metric.evaluate", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __Pyx_RefNannyFinishContext();
+  return NULL;
+  __pyx_L4_argument_unpacking_done:;
+  __pyx_r = __pyx_pf_5_cdec_6Metric_6evaluate(((struct __pyx_obj_5_cdec_Metric *)__pyx_v_self), __pyx_v_hyp, __pyx_v_refs);
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+/* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":187
+ *         return 0
+ * 
+ *     def evaluate(self, hyp, refs):             # <<<<<<<<<<<<<<
+ *         return []
+ * 
+ */
+
+static PyObject *__pyx_pf_5_cdec_6Metric_6evaluate(CYTHON_UNUSED struct __pyx_obj_5_cdec_Metric *__pyx_v_self, CYTHON_UNUSED PyObject *__pyx_v_hyp, CYTHON_UNUSED PyObject *__pyx_v_refs) {
+  PyObject *__pyx_r = NULL;
+  __Pyx_RefNannyDeclarations
+  PyObject *__pyx_t_1 = NULL;
+  int __pyx_lineno = 0;
+  const char *__pyx_filename = NULL;
+  int __pyx_clineno = 0;
+  __Pyx_RefNannySetupContext("evaluate", 0);
+
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":188
+ * 
+ *     def evaluate(self, hyp, refs):
+ *         return []             # <<<<<<<<<<<<<<
+ * 
+ * BLEU = Scorer('IBM_BLEU')
+ */
+  __Pyx_XDECREF(__pyx_r);
+  __pyx_t_1 = PyList_New(0); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 188; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_1);
+  __pyx_r = ((PyObject *)__pyx_t_1);
+  __pyx_t_1 = 0;
+  goto __pyx_L0;
+
+  __pyx_r = Py_None; __Pyx_INCREF(Py_None);
+  goto __pyx_L0;
+  __pyx_L1_error:;
+  __Pyx_XDECREF(__pyx_t_1);
+  __Pyx_AddTraceback("_cdec.Metric.evaluate", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __pyx_r = NULL;
+  __pyx_L0:;
+  __Pyx_XGIVEREF(__pyx_r);
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+static PyObject *__pyx_gb_5_cdec_4generator16(__pyx_GeneratorObject *__pyx_generator, PyObject *__pyx_sent_value); /* proto */
+
+/* Python wrapper */
+static PyObject *__pyx_pw_5_cdec_3_make_config(PyObject *__pyx_self, PyObject *__pyx_v_config); /*proto*/
+static PyMethodDef __pyx_mdef_5_cdec_3_make_config = {__Pyx_NAMESTR("_make_config"), (PyCFunction)__pyx_pw_5_cdec_3_make_config, METH_O, __Pyx_DOCSTR(0)};
+static PyObject *__pyx_pw_5_cdec_3_make_config(PyObject *__pyx_self, PyObject *__pyx_v_config) {
+  PyObject *__pyx_r = 0;
+  __Pyx_RefNannyDeclarations
+  __Pyx_RefNannySetupContext("_make_config (wrapper)", 0);
+  __pyx_self = __pyx_self;
+  __pyx_r = __pyx_pf_5_cdec_2_make_config(__pyx_self, ((PyObject *)__pyx_v_config));
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+/* "_cdec.pyx":28
+ * class ParseFailed(Exception): pass
+ * 
+ * def _make_config(config):             # <<<<<<<<<<<<<<
+ *     for key, value in config.items():
+ *         if isinstance(value, dict):
+ */
+
+static PyObject *__pyx_pf_5_cdec_2_make_config(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_config) {
+  struct __pyx_obj_5_cdec___pyx_scope_struct_22__make_config *__pyx_cur_scope;
+  PyObject *__pyx_r = NULL;
+  __Pyx_RefNannyDeclarations
+  int __pyx_lineno = 0;
+  const char *__pyx_filename = NULL;
+  int __pyx_clineno = 0;
+  __Pyx_RefNannySetupContext("_make_config", 0);
+  __pyx_cur_scope = (struct __pyx_obj_5_cdec___pyx_scope_struct_22__make_config *)__pyx_ptype_5_cdec___pyx_scope_struct_22__make_config->tp_new(__pyx_ptype_5_cdec___pyx_scope_struct_22__make_config, __pyx_empty_tuple, NULL);
+  if (unlikely(!__pyx_cur_scope)) {
+    __Pyx_RefNannyFinishContext();
+    return NULL;
+  }
+  __Pyx_GOTREF(__pyx_cur_scope);
+  __pyx_cur_scope->__pyx_v_config = __pyx_v_config;
+  __Pyx_INCREF(__pyx_cur_scope->__pyx_v_config);
+  __Pyx_GIVEREF(__pyx_cur_scope->__pyx_v_config);
+  {
+    __pyx_GeneratorObject *gen = __Pyx_Generator_New((__pyx_generator_body_t) __pyx_gb_5_cdec_4generator16, (PyObject *) __pyx_cur_scope); if (unlikely(!gen)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 28; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __Pyx_DECREF(__pyx_cur_scope);
+    __Pyx_RefNannyFinishContext();
+    return (PyObject *) gen;
+  }
+
+  __pyx_r = Py_None; __Pyx_INCREF(Py_None);
+  goto __pyx_L0;
+  __pyx_L1_error:;
+  __Pyx_AddTraceback("_cdec._make_config", __pyx_clineno, __pyx_lineno, __pyx_filename);
+  __pyx_r = NULL;
+  __pyx_L0:;
+  __Pyx_DECREF(((PyObject *)__pyx_cur_scope));
+  __Pyx_XGIVEREF(__pyx_r);
+  __Pyx_RefNannyFinishContext();
+  return __pyx_r;
+}
+
+static PyObject *__pyx_gb_5_cdec_4generator16(__pyx_GeneratorObject *__pyx_generator, PyObject *__pyx_sent_value) /* generator body */
+{
+  struct __pyx_obj_5_cdec___pyx_scope_struct_22__make_config *__pyx_cur_scope = ((struct __pyx_obj_5_cdec___pyx_scope_struct_22__make_config *)__pyx_generator->closure);
+  PyObject *__pyx_r = NULL;
+  PyObject *__pyx_t_1 = NULL;
+  PyObject *__pyx_t_2 = NULL;
   Py_ssize_t __pyx_t_3;
   PyObject *(*__pyx_t_4)(PyObject *);
   PyObject *__pyx_t_5 = NULL;
@@ -14866,7 +15623,7 @@ static PyObject *__pyx_gb_5_cdec_4generator16(__pyx_GeneratorObject *__pyx_gener
         __Pyx_INCREF(__pyx_cur_scope->__pyx_v_info);
         PyTuple_SET_ITEM(__pyx_t_6, 1, __pyx_cur_scope->__pyx_v_info);
         __Pyx_GIVEREF(__pyx_cur_scope->__pyx_v_info);
-        __pyx_t_7 = PyNumber_Remainder(((PyObject *)__pyx_kp_s_43), ((PyObject *)__pyx_t_6)); if (unlikely(!__pyx_t_7)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 32; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+        __pyx_t_7 = PyNumber_Remainder(((PyObject *)__pyx_kp_s_45), ((PyObject *)__pyx_t_6)); if (unlikely(!__pyx_t_7)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 32; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
         __Pyx_GOTREF(((PyObject *)__pyx_t_7));
         __Pyx_DECREF(((PyObject *)__pyx_t_6)); __pyx_t_6 = 0;
         __pyx_t_6 = PyTuple_New(2); if (unlikely(!__pyx_t_6)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 32; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
@@ -15245,7 +16002,7 @@ static PyObject *__pyx_gb_5_cdec_7Decoder_9__cinit___2generator20(__pyx_Generato
     __Pyx_GIVEREF(__pyx_t_3);
     __pyx_cur_scope->__pyx_v_kv = __pyx_t_3;
     __pyx_t_3 = 0;
-    __pyx_t_3 = PyNumber_Remainder(((PyObject *)__pyx_kp_s_44), __pyx_cur_scope->__pyx_v_kv); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 54; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_t_3 = PyNumber_Remainder(((PyObject *)__pyx_kp_s_46), __pyx_cur_scope->__pyx_v_kv); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 54; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
     __Pyx_GOTREF(((PyObject *)__pyx_t_3));
     __pyx_r = ((PyObject *)__pyx_t_3);
     __pyx_t_3 = 0;
@@ -15336,7 +16093,7 @@ static int __pyx_pf_5_cdec_7Decoder___cinit__(struct __pyx_obj_5_cdec_Decoder *_
  */
     __pyx_t_2 = PyObject_GetAttr(__pyx_cur_scope->__pyx_v_config, __pyx_n_s__get); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 50; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
     __Pyx_GOTREF(__pyx_t_2);
-    __pyx_t_3 = PyObject_Call(__pyx_t_2, ((PyObject *)__pyx_k_tuple_45), NULL); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 50; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_t_3 = PyObject_Call(__pyx_t_2, ((PyObject *)__pyx_k_tuple_47), NULL); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 50; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
     __Pyx_GOTREF(__pyx_t_3);
     __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
     __pyx_v_formalism = __pyx_t_3;
@@ -15401,7 +16158,7 @@ static int __pyx_pf_5_cdec_7Decoder___cinit__(struct __pyx_obj_5_cdec_Decoder *_
  */
       __pyx_t_3 = __Pyx_GetName(__pyx_m, __pyx_n_s__InvalidConfig); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 53; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
       __Pyx_GOTREF(__pyx_t_3);
-      __pyx_t_2 = PyNumber_Remainder(((PyObject *)__pyx_kp_s_46), __pyx_v_formalism); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 53; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+      __pyx_t_2 = PyNumber_Remainder(((PyObject *)__pyx_kp_s_48), __pyx_v_formalism); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 53; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
       __Pyx_GOTREF(((PyObject *)__pyx_t_2));
       __pyx_t_6 = PyTuple_New(1); if (unlikely(!__pyx_t_6)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 53; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
       __Pyx_GOTREF(__pyx_t_6);
@@ -15807,7 +16564,7 @@ static int __pyx_pf_5_cdec_7Decoder_7weights_2__set__(struct __pyx_obj_5_cdec_De
  * 
  *     property formalism:
  */
-    __pyx_t_1 = PyNumber_Remainder(((PyObject *)__pyx_kp_s_47), ((PyObject *)Py_TYPE(__pyx_v_weights))); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 78; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_t_1 = PyNumber_Remainder(((PyObject *)__pyx_kp_s_49), ((PyObject *)Py_TYPE(__pyx_v_weights))); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 78; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
     __Pyx_GOTREF(((PyObject *)__pyx_t_1));
     __pyx_t_3 = PyTuple_New(1); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 78; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
     __Pyx_GOTREF(__pyx_t_3);
@@ -16038,7 +16795,7 @@ static PyObject *__pyx_pf_5_cdec_7Decoder_4read_weights(struct __pyx_obj_5_cdec_
             __pyx_t_2 = PyObject_GetAttr(__pyx_t_1, __pyx_n_s__startswith); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 88; __pyx_clineno = __LINE__; goto __pyx_L7_error;}
             __Pyx_GOTREF(__pyx_t_2);
             __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
-            __pyx_t_1 = PyObject_Call(__pyx_t_2, ((PyObject *)__pyx_k_tuple_49), NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 88; __pyx_clineno = __LINE__; goto __pyx_L7_error;}
+            __pyx_t_1 = PyObject_Call(__pyx_t_2, ((PyObject *)__pyx_k_tuple_51), NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 88; __pyx_clineno = __LINE__; goto __pyx_L7_error;}
             __Pyx_GOTREF(__pyx_t_1);
             __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
             __pyx_t_10 = __Pyx_PyObject_IsTrue(__pyx_t_1); if (unlikely(__pyx_t_10 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 88; __pyx_clineno = __LINE__; goto __pyx_L7_error;}
@@ -16207,7 +16964,7 @@ static PyObject *__pyx_pf_5_cdec_7Decoder_4read_weights(struct __pyx_obj_5_cdec_
     }
     /*finally:*/ {
       if (__pyx_t_3) {
-        __pyx_t_7 = PyObject_Call(__pyx_t_3, __pyx_k_tuple_50, NULL);
+        __pyx_t_7 = PyObject_Call(__pyx_t_3, __pyx_k_tuple_52, NULL);
         __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
         if (unlikely(!__pyx_t_7)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 86; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
         __Pyx_GOTREF(__pyx_t_7);
@@ -16412,7 +17169,7 @@ static PyObject *__pyx_pf_5_cdec_7Decoder_6translate(struct __pyx_obj_5_cdec_Dec
  *         if grammar:
  *             if isinstance(grammar, str) or isinstance(grammar, unicode):
  */
-    __pyx_t_5 = PyNumber_Remainder(((PyObject *)__pyx_kp_s_51), ((PyObject *)Py_TYPE(__pyx_v_sentence))); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 99; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+    __pyx_t_5 = PyNumber_Remainder(((PyObject *)__pyx_kp_s_53), ((PyObject *)Py_TYPE(__pyx_v_sentence))); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 99; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
     __Pyx_GOTREF(((PyObject *)__pyx_t_5));
     __pyx_t_1 = PyTuple_New(1); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 99; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
     __Pyx_GOTREF(__pyx_t_1);
@@ -19213,6 +19970,13 @@ static void __pyx_tp_dealloc_5_cdec_SufficientStats(PyObject *o) {
   }
   (*Py_TYPE(o)->tp_free)(o);
 }
+static PyObject *__pyx_sq_item_5_cdec_SufficientStats(PyObject *o, Py_ssize_t i) {
+  PyObject *r;
+  PyObject *x = PyInt_FromSsize_t(i); if(!x) return 0;
+  r = Py_TYPE(o)->tp_as_mapping->mp_subscript(o, x);
+  Py_DECREF(x);
+  return r;
+}
 
 static PyObject *__pyx_getprop_5_cdec_15SufficientStats_score(PyObject *o, void *x) {
   return __pyx_pw_5_cdec_15SufficientStats_5score_1__get__(o);
@@ -19233,7 +19997,7 @@ static struct PyGetSetDef __pyx_getsets_5_cdec_SufficientStats[] = {
 };
 
 static PyNumberMethods __pyx_tp_as_number_SufficientStats = {
-  __pyx_pw_5_cdec_15SufficientStats_10__add__, /*nb_add*/
+  __pyx_pw_5_cdec_15SufficientStats_12__add__, /*nb_add*/
   0, /*nb_subtract*/
   0, /*nb_multiply*/
   #if PY_MAJOR_VERSION < 3
@@ -19268,7 +20032,7 @@ static PyNumberMethods __pyx_tp_as_number_SufficientStats = {
   #if PY_MAJOR_VERSION < 3
   0, /*nb_hex*/
   #endif
-  __pyx_pw_5_cdec_15SufficientStats_8__iadd__, /*nb_inplace_add*/
+  __pyx_pw_5_cdec_15SufficientStats_10__iadd__, /*nb_inplace_add*/
   0, /*nb_inplace_subtract*/
   0, /*nb_inplace_multiply*/
   #if PY_MAJOR_VERSION < 3
@@ -19294,7 +20058,7 @@ static PySequenceMethods __pyx_tp_as_sequence_SufficientStats = {
   __pyx_pw_5_cdec_15SufficientStats_3__len__, /*sq_length*/
   0, /*sq_concat*/
   0, /*sq_repeat*/
-  0, /*sq_item*/
+  __pyx_sq_item_5_cdec_SufficientStats, /*sq_item*/
   0, /*sq_slice*/
   0, /*sq_ass_item*/
   0, /*sq_ass_slice*/
@@ -19305,7 +20069,7 @@ static PySequenceMethods __pyx_tp_as_sequence_SufficientStats = {
 
 static PyMappingMethods __pyx_tp_as_mapping_SufficientStats = {
   __pyx_pw_5_cdec_15SufficientStats_3__len__, /*mp_length*/
-  0, /*mp_subscript*/
+  __pyx_pw_5_cdec_15SufficientStats_8__getitem__, /*mp_subscript*/
   0, /*mp_ass_subscript*/
 };
 
@@ -19933,6 +20697,202 @@ static PyTypeObject __pyx_type_5_cdec_Scorer = {
   #endif
 };
 
+static PyObject *__pyx_tp_new_5_cdec_Metric(PyTypeObject *t, PyObject *a, PyObject *k) {
+  struct __pyx_obj_5_cdec_Metric *p;
+  PyObject *o = (*t->tp_alloc)(t, 0);
+  if (!o) return 0;
+  p = ((struct __pyx_obj_5_cdec_Metric *)o);
+  p->scorer = ((struct __pyx_obj_5_cdec_Scorer *)Py_None); Py_INCREF(Py_None);
+  if (__pyx_pw_5_cdec_6Metric_1__cinit__(o, __pyx_empty_tuple, NULL) < 0) {
+    Py_DECREF(o); o = 0;
+  }
+  return o;
+}
+
+static void __pyx_tp_dealloc_5_cdec_Metric(PyObject *o) {
+  struct __pyx_obj_5_cdec_Metric *p = (struct __pyx_obj_5_cdec_Metric *)o;
+  Py_XDECREF(((PyObject *)p->scorer));
+  (*Py_TYPE(o)->tp_free)(o);
+}
+
+static int __pyx_tp_traverse_5_cdec_Metric(PyObject *o, visitproc v, void *a) {
+  int e;
+  struct __pyx_obj_5_cdec_Metric *p = (struct __pyx_obj_5_cdec_Metric *)o;
+  if (p->scorer) {
+    e = (*v)(((PyObject*)p->scorer), a); if (e) return e;
+  }
+  return 0;
+}
+
+static int __pyx_tp_clear_5_cdec_Metric(PyObject *o) {
+  struct __pyx_obj_5_cdec_Metric *p = (struct __pyx_obj_5_cdec_Metric *)o;
+  PyObject* tmp;
+  tmp = ((PyObject*)p->scorer);
+  p->scorer = ((struct __pyx_obj_5_cdec_Scorer *)Py_None); Py_INCREF(Py_None);
+  Py_XDECREF(tmp);
+  return 0;
+}
+
+static PyMethodDef __pyx_methods_5_cdec_Metric[] = {
+  {__Pyx_NAMESTR("score"), (PyCFunction)__pyx_pw_5_cdec_6Metric_5score, METH_NOARGS, __Pyx_DOCSTR(0)},
+  {__Pyx_NAMESTR("evaluate"), (PyCFunction)__pyx_pw_5_cdec_6Metric_7evaluate, METH_VARARGS|METH_KEYWORDS, __Pyx_DOCSTR(0)},
+  {0, 0, 0, 0}
+};
+
+static PyNumberMethods __pyx_tp_as_number_Metric = {
+  0, /*nb_add*/
+  0, /*nb_subtract*/
+  0, /*nb_multiply*/
+  #if PY_MAJOR_VERSION < 3
+  0, /*nb_divide*/
+  #endif
+  0, /*nb_remainder*/
+  0, /*nb_divmod*/
+  0, /*nb_power*/
+  0, /*nb_negative*/
+  0, /*nb_positive*/
+  0, /*nb_absolute*/
+  0, /*nb_nonzero*/
+  0, /*nb_invert*/
+  0, /*nb_lshift*/
+  0, /*nb_rshift*/
+  0, /*nb_and*/
+  0, /*nb_xor*/
+  0, /*nb_or*/
+  #if PY_MAJOR_VERSION < 3
+  0, /*nb_coerce*/
+  #endif
+  0, /*nb_int*/
+  #if PY_MAJOR_VERSION < 3
+  0, /*nb_long*/
+  #else
+  0, /*reserved*/
+  #endif
+  0, /*nb_float*/
+  #if PY_MAJOR_VERSION < 3
+  0, /*nb_oct*/
+  #endif
+  #if PY_MAJOR_VERSION < 3
+  0, /*nb_hex*/
+  #endif
+  0, /*nb_inplace_add*/
+  0, /*nb_inplace_subtract*/
+  0, /*nb_inplace_multiply*/
+  #if PY_MAJOR_VERSION < 3
+  0, /*nb_inplace_divide*/
+  #endif
+  0, /*nb_inplace_remainder*/
+  0, /*nb_inplace_power*/
+  0, /*nb_inplace_lshift*/
+  0, /*nb_inplace_rshift*/
+  0, /*nb_inplace_and*/
+  0, /*nb_inplace_xor*/
+  0, /*nb_inplace_or*/
+  0, /*nb_floor_divide*/
+  0, /*nb_true_divide*/
+  0, /*nb_inplace_floor_divide*/
+  0, /*nb_inplace_true_divide*/
+  #if PY_VERSION_HEX >= 0x02050000
+  0, /*nb_index*/
+  #endif
+};
+
+static PySequenceMethods __pyx_tp_as_sequence_Metric = {
+  0, /*sq_length*/
+  0, /*sq_concat*/
+  0, /*sq_repeat*/
+  0, /*sq_item*/
+  0, /*sq_slice*/
+  0, /*sq_ass_item*/
+  0, /*sq_ass_slice*/
+  0, /*sq_contains*/
+  0, /*sq_inplace_concat*/
+  0, /*sq_inplace_repeat*/
+};
+
+static PyMappingMethods __pyx_tp_as_mapping_Metric = {
+  0, /*mp_length*/
+  0, /*mp_subscript*/
+  0, /*mp_ass_subscript*/
+};
+
+static PyBufferProcs __pyx_tp_as_buffer_Metric = {
+  #if PY_MAJOR_VERSION < 3
+  0, /*bf_getreadbuffer*/
+  #endif
+  #if PY_MAJOR_VERSION < 3
+  0, /*bf_getwritebuffer*/
+  #endif
+  #if PY_MAJOR_VERSION < 3
+  0, /*bf_getsegcount*/
+  #endif
+  #if PY_MAJOR_VERSION < 3
+  0, /*bf_getcharbuffer*/
+  #endif
+  #if PY_VERSION_HEX >= 0x02060000
+  0, /*bf_getbuffer*/
+  #endif
+  #if PY_VERSION_HEX >= 0x02060000
+  0, /*bf_releasebuffer*/
+  #endif
+};
+
+static PyTypeObject __pyx_type_5_cdec_Metric = {
+  PyVarObject_HEAD_INIT(0, 0)
+  __Pyx_NAMESTR("_cdec.Metric"), /*tp_name*/
+  sizeof(struct __pyx_obj_5_cdec_Metric), /*tp_basicsize*/
+  0, /*tp_itemsize*/
+  __pyx_tp_dealloc_5_cdec_Metric, /*tp_dealloc*/
+  0, /*tp_print*/
+  0, /*tp_getattr*/
+  0, /*tp_setattr*/
+  #if PY_MAJOR_VERSION < 3
+  0, /*tp_compare*/
+  #else
+  0, /*reserved*/
+  #endif
+  0, /*tp_repr*/
+  &__pyx_tp_as_number_Metric, /*tp_as_number*/
+  &__pyx_tp_as_sequence_Metric, /*tp_as_sequence*/
+  &__pyx_tp_as_mapping_Metric, /*tp_as_mapping*/
+  0, /*tp_hash*/
+  __pyx_pw_5_cdec_6Metric_3__call__, /*tp_call*/
+  0, /*tp_str*/
+  0, /*tp_getattro*/
+  0, /*tp_setattro*/
+  &__pyx_tp_as_buffer_Metric, /*tp_as_buffer*/
+  Py_TPFLAGS_DEFAULT|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_HAVE_GC, /*tp_flags*/
+  0, /*tp_doc*/
+  __pyx_tp_traverse_5_cdec_Metric, /*tp_traverse*/
+  __pyx_tp_clear_5_cdec_Metric, /*tp_clear*/
+  0, /*tp_richcompare*/
+  0, /*tp_weaklistoffset*/
+  0, /*tp_iter*/
+  0, /*tp_iternext*/
+  __pyx_methods_5_cdec_Metric, /*tp_methods*/
+  0, /*tp_members*/
+  0, /*tp_getset*/
+  0, /*tp_base*/
+  0, /*tp_dict*/
+  0, /*tp_descr_get*/
+  0, /*tp_descr_set*/
+  0, /*tp_dictoffset*/
+  0, /*tp_init*/
+  0, /*tp_alloc*/
+  __pyx_tp_new_5_cdec_Metric, /*tp_new*/
+  0, /*tp_free*/
+  0, /*tp_is_gc*/
+  0, /*tp_bases*/
+  0, /*tp_mro*/
+  0, /*tp_cache*/
+  0, /*tp_subclasses*/
+  0, /*tp_weaklist*/
+  0, /*tp_del*/
+  #if PY_VERSION_HEX >= 0x02060000
+  0, /*tp_version_tag*/
+  #endif
+};
+
 static PyObject *__pyx_tp_new_5_cdec_Decoder(PyTypeObject *t, PyObject *a, PyObject *k) {
   struct __pyx_obj_5_cdec_Decoder *p;
   PyObject *o = (*t->tp_alloc)(t, 0);
@@ -25197,13 +26157,14 @@ static __Pyx_StringTabEntry __pyx_string_tab[] = {
   {&__pyx_kp_s_4, __pyx_k_4, sizeof(__pyx_k_4), 0, 0, 1, 0},
   {&__pyx_kp_s_41, __pyx_k_41, sizeof(__pyx_k_41), 0, 0, 1, 0},
   {&__pyx_kp_s_43, __pyx_k_43, sizeof(__pyx_k_43), 0, 0, 1, 0},
-  {&__pyx_kp_s_44, __pyx_k_44, sizeof(__pyx_k_44), 0, 0, 1, 0},
+  {&__pyx_kp_s_45, __pyx_k_45, sizeof(__pyx_k_45), 0, 0, 1, 0},
   {&__pyx_kp_s_46, __pyx_k_46, sizeof(__pyx_k_46), 0, 0, 1, 0},
-  {&__pyx_kp_s_47, __pyx_k_47, sizeof(__pyx_k_47), 0, 0, 1, 0},
   {&__pyx_kp_s_48, __pyx_k_48, sizeof(__pyx_k_48), 0, 0, 1, 0},
-  {&__pyx_kp_s_51, __pyx_k_51, sizeof(__pyx_k_51), 0, 0, 1, 0},
-  {&__pyx_kp_s_54, __pyx_k_54, sizeof(__pyx_k_54), 0, 0, 1, 0},
-  {&__pyx_kp_s_59, __pyx_k_59, sizeof(__pyx_k_59), 0, 0, 1, 0},
+  {&__pyx_kp_s_49, __pyx_k_49, sizeof(__pyx_k_49), 0, 0, 1, 0},
+  {&__pyx_kp_s_50, __pyx_k_50, sizeof(__pyx_k_50), 0, 0, 1, 0},
+  {&__pyx_kp_s_53, __pyx_k_53, sizeof(__pyx_k_53), 0, 0, 1, 0},
+  {&__pyx_kp_s_56, __pyx_k_56, sizeof(__pyx_k_56), 0, 0, 1, 0},
+  {&__pyx_kp_s_61, __pyx_k_61, sizeof(__pyx_k_61), 0, 0, 1, 0},
   {&__pyx_kp_s_7, __pyx_k_7, sizeof(__pyx_k_7), 0, 0, 1, 0},
   {&__pyx_kp_s_8, __pyx_k_8, sizeof(__pyx_k_8), 0, 0, 1, 0},
   {&__pyx_kp_s_9, __pyx_k_9, sizeof(__pyx_k_9), 0, 0, 1, 0},
@@ -25218,9 +26179,11 @@ static __Pyx_StringTabEntry __pyx_string_tab[] = {
   {&__pyx_n_s__TER, __pyx_k__TER, sizeof(__pyx_k__TER), 0, 0, 1, 1},
   {&__pyx_n_s__TypeError, __pyx_k__TypeError, sizeof(__pyx_k__TypeError), 0, 0, 1, 1},
   {&__pyx_n_s__ValueError, __pyx_k__ValueError, sizeof(__pyx_k__ValueError), 0, 0, 1, 1},
+  {&__pyx_n_s____class__, __pyx_k____class__, sizeof(__pyx_k____class__), 0, 0, 1, 1},
   {&__pyx_n_s____enter__, __pyx_k____enter__, sizeof(__pyx_k____enter__), 0, 0, 1, 1},
   {&__pyx_n_s____exit__, __pyx_k____exit__, sizeof(__pyx_k____exit__), 0, 0, 1, 1},
   {&__pyx_n_s____main__, __pyx_k____main__, sizeof(__pyx_k____main__), 0, 0, 1, 1},
+  {&__pyx_n_s____name__, __pyx_k____name__, sizeof(__pyx_k____name__), 0, 0, 1, 1},
   {&__pyx_n_s____test__, __pyx_k____test__, sizeof(__pyx_k____test__), 0, 0, 1, 1},
   {&__pyx_n_s___cdec, __pyx_k___cdec, sizeof(__pyx_k___cdec), 0, 0, 1, 1},
   {&__pyx_n_s___make_config, __pyx_k___make_config, sizeof(__pyx_k___make_config), 0, 0, 1, 1},
@@ -25239,6 +26202,7 @@ static __Pyx_StringTabEntry __pyx_string_tab[] = {
   {&__pyx_n_s__encoding, __pyx_k__encoding, sizeof(__pyx_k__encoding), 0, 0, 1, 1},
   {&__pyx_n_s__enumerate, __pyx_k__enumerate, sizeof(__pyx_k__enumerate), 0, 0, 1, 1},
   {&__pyx_n_s__eval, __pyx_k__eval, sizeof(__pyx_k__eval), 0, 0, 1, 1},
+  {&__pyx_n_s__evaluate, __pyx_k__evaluate, sizeof(__pyx_k__evaluate), 0, 0, 1, 1},
   {&__pyx_n_s__evaluator, __pyx_k__evaluator, sizeof(__pyx_k__evaluator), 0, 0, 1, 1},
   {&__pyx_n_s__f, __pyx_k__f, sizeof(__pyx_k__f), 0, 0, 1, 1},
   {&__pyx_n_s__formalism, __pyx_k__formalism, sizeof(__pyx_k__formalism), 0, 0, 1, 1},
@@ -25246,6 +26210,7 @@ static __Pyx_StringTabEntry __pyx_string_tab[] = {
   {&__pyx_n_s__genexpr, __pyx_k__genexpr, sizeof(__pyx_k__genexpr), 0, 0, 1, 1},
   {&__pyx_n_s__get, __pyx_k__get, sizeof(__pyx_k__get), 0, 0, 1, 1},
   {&__pyx_n_s__grammar, __pyx_k__grammar, sizeof(__pyx_k__grammar), 0, 0, 1, 1},
+  {&__pyx_n_s__hyp, __pyx_k__hyp, sizeof(__pyx_k__hyp), 0, 0, 1, 1},
   {&__pyx_n_s__hypergraph, __pyx_k__hypergraph, sizeof(__pyx_k__hypergraph), 0, 0, 1, 1},
   {&__pyx_n_s__i, __pyx_k__i, sizeof(__pyx_k__i), 0, 0, 1, 1},
   {&__pyx_n_s__in_edges, __pyx_k__in_edges, sizeof(__pyx_k__in_edges), 0, 0, 1, 1},
@@ -25271,6 +26236,7 @@ static __Pyx_StringTabEntry __pyx_string_tab[] = {
   {&__pyx_n_s__replace, __pyx_k__replace, sizeof(__pyx_k__replace), 0, 0, 1, 1},
   {&__pyx_n_s__rules, __pyx_k__rules, sizeof(__pyx_k__rules), 0, 0, 1, 1},
   {&__pyx_n_s__scfg, __pyx_k__scfg, sizeof(__pyx_k__scfg), 0, 0, 1, 1},
+  {&__pyx_n_s__score, __pyx_k__score, sizeof(__pyx_k__score), 0, 0, 1, 1},
   {&__pyx_n_s__scores, __pyx_k__scores, sizeof(__pyx_k__scores), 0, 0, 1, 1},
   {&__pyx_n_s__self, __pyx_k__self, sizeof(__pyx_k__self), 0, 0, 1, 1},
   {&__pyx_n_s__sentence, __pyx_k__sentence, sizeof(__pyx_k__sentence), 0, 0, 1, 1},
@@ -25350,7 +26316,7 @@ static int __Pyx_InitCachedConstants(void) {
  *         for trule in rules:
  *             if not isinstance(trule, BaseTRule):
  *                 raise ValueError('the grammar should contain TRule objects')             # <<<<<<<<<<<<<<
- *             _g.AddRule((<TRule> trule).rule[0])
+ *             _g.AddRule((<BaseTRule> trule).rule[0])
  */
   __pyx_k_tuple_14 = PyTuple_New(1); if (unlikely(!__pyx_k_tuple_14)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 175; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __Pyx_GOTREF(__pyx_k_tuple_14);
@@ -25494,20 +26460,34 @@ static int __Pyx_InitCachedConstants(void) {
   __Pyx_GIVEREF(((PyObject *)__pyx_n_s__utf8));
   __Pyx_GIVEREF(((PyObject *)__pyx_k_tuple_40));
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":79
- *     def __getitem__(self,int k):
- *         if not 0 <= k < self.cs.size():
- *             raise IndexError('candidate set index out of range')             # <<<<<<<<<<<<<<
- *         cdef Candidate candidate = Candidate()
- *         candidate.candidate = &self.cs[0][k]
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":50
+ *     def __getitem__(self, int index):
+ *         if not 0 <= index < len(self):
+ *             raise IndexError('sufficient stats vector index out of range')             # <<<<<<<<<<<<<<
+ *         return self.stats[0][index]
+ * 
  */
-  __pyx_k_tuple_42 = PyTuple_New(1); if (unlikely(!__pyx_k_tuple_42)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 79; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_k_tuple_42 = PyTuple_New(1); if (unlikely(!__pyx_k_tuple_42)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 50; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __Pyx_GOTREF(__pyx_k_tuple_42);
   __Pyx_INCREF(((PyObject *)__pyx_kp_s_41));
   PyTuple_SET_ITEM(__pyx_k_tuple_42, 0, ((PyObject *)__pyx_kp_s_41));
   __Pyx_GIVEREF(((PyObject *)__pyx_kp_s_41));
   __Pyx_GIVEREF(((PyObject *)__pyx_k_tuple_42));
 
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":84
+ *     def __getitem__(self,int k):
+ *         if not 0 <= k < self.cs.size():
+ *             raise IndexError('candidate set index out of range')             # <<<<<<<<<<<<<<
+ *         cdef Candidate candidate = Candidate()
+ *         candidate.candidate = &self.cs[0][k]
+ */
+  __pyx_k_tuple_44 = PyTuple_New(1); if (unlikely(!__pyx_k_tuple_44)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 84; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_k_tuple_44);
+  __Pyx_INCREF(((PyObject *)__pyx_kp_s_43));
+  PyTuple_SET_ITEM(__pyx_k_tuple_44, 0, ((PyObject *)__pyx_kp_s_43));
+  __Pyx_GIVEREF(((PyObject *)__pyx_kp_s_43));
+  __Pyx_GIVEREF(((PyObject *)__pyx_k_tuple_44));
+
   /* "_cdec.pyx":50
  *         """
  *         if config_str is None:
@@ -25515,15 +26495,15 @@ static int __Pyx_InitCachedConstants(void) {
  *             if formalism not in ('scfg', 'fst', 'lextrans', 'pb',
  *                     'csplit', 'tagger', 'lexalign'):
  */
-  __pyx_k_tuple_45 = PyTuple_New(2); if (unlikely(!__pyx_k_tuple_45)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 50; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __Pyx_GOTREF(__pyx_k_tuple_45);
+  __pyx_k_tuple_47 = PyTuple_New(2); if (unlikely(!__pyx_k_tuple_47)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 50; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_k_tuple_47);
   __Pyx_INCREF(((PyObject *)__pyx_n_s__formalism));
-  PyTuple_SET_ITEM(__pyx_k_tuple_45, 0, ((PyObject *)__pyx_n_s__formalism));
+  PyTuple_SET_ITEM(__pyx_k_tuple_47, 0, ((PyObject *)__pyx_n_s__formalism));
   __Pyx_GIVEREF(((PyObject *)__pyx_n_s__formalism));
   __Pyx_INCREF(Py_None);
-  PyTuple_SET_ITEM(__pyx_k_tuple_45, 1, Py_None);
+  PyTuple_SET_ITEM(__pyx_k_tuple_47, 1, Py_None);
   __Pyx_GIVEREF(Py_None);
-  __Pyx_GIVEREF(((PyObject *)__pyx_k_tuple_45));
+  __Pyx_GIVEREF(((PyObject *)__pyx_k_tuple_47));
 
   /* "_cdec.pyx":88
  *         with open(weights) as fp:
@@ -25532,12 +26512,12 @@ static int __Pyx_InitCachedConstants(void) {
  *                 fname, value = line.split()
  *                 self.weights[fname.strip()] = float(value)
  */
-  __pyx_k_tuple_49 = PyTuple_New(1); if (unlikely(!__pyx_k_tuple_49)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 88; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __Pyx_GOTREF(__pyx_k_tuple_49);
-  __Pyx_INCREF(((PyObject *)__pyx_kp_s_48));
-  PyTuple_SET_ITEM(__pyx_k_tuple_49, 0, ((PyObject *)__pyx_kp_s_48));
-  __Pyx_GIVEREF(((PyObject *)__pyx_kp_s_48));
-  __Pyx_GIVEREF(((PyObject *)__pyx_k_tuple_49));
+  __pyx_k_tuple_51 = PyTuple_New(1); if (unlikely(!__pyx_k_tuple_51)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 88; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_k_tuple_51);
+  __Pyx_INCREF(((PyObject *)__pyx_kp_s_50));
+  PyTuple_SET_ITEM(__pyx_k_tuple_51, 0, ((PyObject *)__pyx_kp_s_50));
+  __Pyx_GIVEREF(((PyObject *)__pyx_kp_s_50));
+  __Pyx_GIVEREF(((PyObject *)__pyx_k_tuple_51));
 
   /* "_cdec.pyx":86
  * 
@@ -25546,18 +26526,18 @@ static int __Pyx_InitCachedConstants(void) {
  *             for line in fp:
  *                 if line.strip().startswith('#'): continue
  */
-  __pyx_k_tuple_50 = PyTuple_New(3); if (unlikely(!__pyx_k_tuple_50)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 86; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __Pyx_GOTREF(__pyx_k_tuple_50);
+  __pyx_k_tuple_52 = PyTuple_New(3); if (unlikely(!__pyx_k_tuple_52)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 86; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_k_tuple_52);
   __Pyx_INCREF(Py_None);
-  PyTuple_SET_ITEM(__pyx_k_tuple_50, 0, Py_None);
+  PyTuple_SET_ITEM(__pyx_k_tuple_52, 0, Py_None);
   __Pyx_GIVEREF(Py_None);
   __Pyx_INCREF(Py_None);
-  PyTuple_SET_ITEM(__pyx_k_tuple_50, 1, Py_None);
+  PyTuple_SET_ITEM(__pyx_k_tuple_52, 1, Py_None);
   __Pyx_GIVEREF(Py_None);
   __Pyx_INCREF(Py_None);
-  PyTuple_SET_ITEM(__pyx_k_tuple_50, 2, Py_None);
+  PyTuple_SET_ITEM(__pyx_k_tuple_52, 2, Py_None);
   __Pyx_GIVEREF(Py_None);
-  __Pyx_GIVEREF(((PyObject *)__pyx_k_tuple_50));
+  __Pyx_GIVEREF(((PyObject *)__pyx_k_tuple_52));
 
   /* "/Users/vchahun/Sandbox/cdec/python/src/grammar.pxi":3
  * cimport grammar
@@ -25566,44 +26546,44 @@ static int __Pyx_InitCachedConstants(void) {
  *     return ' '.join(w.encode('utf8') if isinstance(w, unicode) else str(w) for w in phrase)
  * 
  */
-  __pyx_k_tuple_52 = PyTuple_New(3); if (unlikely(!__pyx_k_tuple_52)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 3; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __Pyx_GOTREF(__pyx_k_tuple_52);
+  __pyx_k_tuple_54 = PyTuple_New(3); if (unlikely(!__pyx_k_tuple_54)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 3; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_k_tuple_54);
   __Pyx_INCREF(((PyObject *)__pyx_n_s__phrase));
-  PyTuple_SET_ITEM(__pyx_k_tuple_52, 0, ((PyObject *)__pyx_n_s__phrase));
+  PyTuple_SET_ITEM(__pyx_k_tuple_54, 0, ((PyObject *)__pyx_n_s__phrase));
   __Pyx_GIVEREF(((PyObject *)__pyx_n_s__phrase));
   __Pyx_INCREF(((PyObject *)__pyx_n_s__genexpr));
-  PyTuple_SET_ITEM(__pyx_k_tuple_52, 1, ((PyObject *)__pyx_n_s__genexpr));
+  PyTuple_SET_ITEM(__pyx_k_tuple_54, 1, ((PyObject *)__pyx_n_s__genexpr));
   __Pyx_GIVEREF(((PyObject *)__pyx_n_s__genexpr));
   __Pyx_INCREF(((PyObject *)__pyx_n_s__genexpr));
-  PyTuple_SET_ITEM(__pyx_k_tuple_52, 2, ((PyObject *)__pyx_n_s__genexpr));
+  PyTuple_SET_ITEM(__pyx_k_tuple_54, 2, ((PyObject *)__pyx_n_s__genexpr));
   __Pyx_GIVEREF(((PyObject *)__pyx_n_s__genexpr));
-  __Pyx_GIVEREF(((PyObject *)__pyx_k_tuple_52));
-  __pyx_k_codeobj_53 = (PyObject*)__Pyx_PyCode_New(1, 0, 3, 0, 0, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_k_tuple_52, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_54, __pyx_n_s___phrase, 3, __pyx_empty_bytes); if (unlikely(!__pyx_k_codeobj_53)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 3; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GIVEREF(((PyObject *)__pyx_k_tuple_54));
+  __pyx_k_codeobj_55 = (PyObject*)__Pyx_PyCode_New(1, 0, 3, 0, 0, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_k_tuple_54, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_56, __pyx_n_s___phrase, 3, __pyx_empty_bytes); if (unlikely(!__pyx_k_codeobj_55)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 3; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":143
- *         return self.name.c_str()
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":190
+ *         return []
  * 
  * BLEU = Scorer('IBM_BLEU')             # <<<<<<<<<<<<<<
  * TER = Scorer('TER')
  */
-  __pyx_k_tuple_55 = PyTuple_New(1); if (unlikely(!__pyx_k_tuple_55)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 143; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __Pyx_GOTREF(__pyx_k_tuple_55);
+  __pyx_k_tuple_57 = PyTuple_New(1); if (unlikely(!__pyx_k_tuple_57)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 190; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_k_tuple_57);
   __Pyx_INCREF(((PyObject *)__pyx_n_s__IBM_BLEU));
-  PyTuple_SET_ITEM(__pyx_k_tuple_55, 0, ((PyObject *)__pyx_n_s__IBM_BLEU));
+  PyTuple_SET_ITEM(__pyx_k_tuple_57, 0, ((PyObject *)__pyx_n_s__IBM_BLEU));
   __Pyx_GIVEREF(((PyObject *)__pyx_n_s__IBM_BLEU));
-  __Pyx_GIVEREF(((PyObject *)__pyx_k_tuple_55));
+  __Pyx_GIVEREF(((PyObject *)__pyx_k_tuple_57));
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":144
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":191
  * 
  * BLEU = Scorer('IBM_BLEU')
  * TER = Scorer('TER')             # <<<<<<<<<<<<<<
  */
-  __pyx_k_tuple_56 = PyTuple_New(1); if (unlikely(!__pyx_k_tuple_56)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 144; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __Pyx_GOTREF(__pyx_k_tuple_56);
+  __pyx_k_tuple_58 = PyTuple_New(1); if (unlikely(!__pyx_k_tuple_58)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 191; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_k_tuple_58);
   __Pyx_INCREF(((PyObject *)__pyx_n_s__TER));
-  PyTuple_SET_ITEM(__pyx_k_tuple_56, 0, ((PyObject *)__pyx_n_s__TER));
+  PyTuple_SET_ITEM(__pyx_k_tuple_58, 0, ((PyObject *)__pyx_n_s__TER));
   __Pyx_GIVEREF(((PyObject *)__pyx_n_s__TER));
-  __Pyx_GIVEREF(((PyObject *)__pyx_k_tuple_56));
+  __Pyx_GIVEREF(((PyObject *)__pyx_k_tuple_58));
 
   /* "_cdec.pyx":28
  * class ParseFailed(Exception): pass
@@ -25612,25 +26592,25 @@ static int __Pyx_InitCachedConstants(void) {
  *     for key, value in config.items():
  *         if isinstance(value, dict):
  */
-  __pyx_k_tuple_57 = PyTuple_New(5); if (unlikely(!__pyx_k_tuple_57)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 28; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __Pyx_GOTREF(__pyx_k_tuple_57);
+  __pyx_k_tuple_59 = PyTuple_New(5); if (unlikely(!__pyx_k_tuple_59)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 28; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_k_tuple_59);
   __Pyx_INCREF(((PyObject *)__pyx_n_s__config));
-  PyTuple_SET_ITEM(__pyx_k_tuple_57, 0, ((PyObject *)__pyx_n_s__config));
+  PyTuple_SET_ITEM(__pyx_k_tuple_59, 0, ((PyObject *)__pyx_n_s__config));
   __Pyx_GIVEREF(((PyObject *)__pyx_n_s__config));
   __Pyx_INCREF(((PyObject *)__pyx_n_s__key));
-  PyTuple_SET_ITEM(__pyx_k_tuple_57, 1, ((PyObject *)__pyx_n_s__key));
+  PyTuple_SET_ITEM(__pyx_k_tuple_59, 1, ((PyObject *)__pyx_n_s__key));
   __Pyx_GIVEREF(((PyObject *)__pyx_n_s__key));
   __Pyx_INCREF(((PyObject *)__pyx_n_s__value));
-  PyTuple_SET_ITEM(__pyx_k_tuple_57, 2, ((PyObject *)__pyx_n_s__value));
+  PyTuple_SET_ITEM(__pyx_k_tuple_59, 2, ((PyObject *)__pyx_n_s__value));
   __Pyx_GIVEREF(((PyObject *)__pyx_n_s__value));
   __Pyx_INCREF(((PyObject *)__pyx_n_s__name));
-  PyTuple_SET_ITEM(__pyx_k_tuple_57, 3, ((PyObject *)__pyx_n_s__name));
+  PyTuple_SET_ITEM(__pyx_k_tuple_59, 3, ((PyObject *)__pyx_n_s__name));
   __Pyx_GIVEREF(((PyObject *)__pyx_n_s__name));
   __Pyx_INCREF(((PyObject *)__pyx_n_s__info));
-  PyTuple_SET_ITEM(__pyx_k_tuple_57, 4, ((PyObject *)__pyx_n_s__info));
+  PyTuple_SET_ITEM(__pyx_k_tuple_59, 4, ((PyObject *)__pyx_n_s__info));
   __Pyx_GIVEREF(((PyObject *)__pyx_n_s__info));
-  __Pyx_GIVEREF(((PyObject *)__pyx_k_tuple_57));
-  __pyx_k_codeobj_58 = (PyObject*)__Pyx_PyCode_New(1, 0, 5, 0, 0, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_k_tuple_57, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_59, __pyx_n_s___make_config, 28, __pyx_empty_bytes); if (unlikely(!__pyx_k_codeobj_58)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 28; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GIVEREF(((PyObject *)__pyx_k_tuple_59));
+  __pyx_k_codeobj_60 = (PyObject*)__Pyx_PyCode_New(1, 0, 5, 0, 0, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_k_tuple_59, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_61, __pyx_n_s___make_config, 28, __pyx_empty_bytes); if (unlikely(!__pyx_k_codeobj_60)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 28; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __Pyx_RefNannyFinishContext();
   return 0;
   __pyx_L1_error:;
@@ -25764,15 +26744,18 @@ PyMODINIT_FUNC PyInit__cdec(void)
   if (PyType_Ready(&__pyx_type_5_cdec_SufficientStats) < 0) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 26; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   if (__Pyx_SetAttrString(__pyx_m, "SufficientStats", (PyObject *)&__pyx_type_5_cdec_SufficientStats) < 0) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 26; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __pyx_ptype_5_cdec_SufficientStats = &__pyx_type_5_cdec_SufficientStats;
-  if (PyType_Ready(&__pyx_type_5_cdec_CandidateSet) < 0) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 60; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  if (__Pyx_SetAttrString(__pyx_m, "CandidateSet", (PyObject *)&__pyx_type_5_cdec_CandidateSet) < 0) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 60; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (PyType_Ready(&__pyx_type_5_cdec_CandidateSet) < 0) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 65; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (__Pyx_SetAttrString(__pyx_m, "CandidateSet", (PyObject *)&__pyx_type_5_cdec_CandidateSet) < 0) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 65; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __pyx_ptype_5_cdec_CandidateSet = &__pyx_type_5_cdec_CandidateSet;
-  if (PyType_Ready(&__pyx_type_5_cdec_SegmentEvaluator) < 0) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 93; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  if (__Pyx_SetAttrString(__pyx_m, "SegmentEvaluator", (PyObject *)&__pyx_type_5_cdec_SegmentEvaluator) < 0) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 93; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (PyType_Ready(&__pyx_type_5_cdec_SegmentEvaluator) < 0) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 98; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (__Pyx_SetAttrString(__pyx_m, "SegmentEvaluator", (PyObject *)&__pyx_type_5_cdec_SegmentEvaluator) < 0) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 98; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __pyx_ptype_5_cdec_SegmentEvaluator = &__pyx_type_5_cdec_SegmentEvaluator;
-  if (PyType_Ready(&__pyx_type_5_cdec_Scorer) < 0) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 112; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  if (__Pyx_SetAttrString(__pyx_m, "Scorer", (PyObject *)&__pyx_type_5_cdec_Scorer) < 0) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 112; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (PyType_Ready(&__pyx_type_5_cdec_Scorer) < 0) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 117; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (__Pyx_SetAttrString(__pyx_m, "Scorer", (PyObject *)&__pyx_type_5_cdec_Scorer) < 0) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 117; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __pyx_ptype_5_cdec_Scorer = &__pyx_type_5_cdec_Scorer;
+  if (PyType_Ready(&__pyx_type_5_cdec_Metric) < 0) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 173; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (__Pyx_SetAttrString(__pyx_m, "Metric", (PyObject *)&__pyx_type_5_cdec_Metric) < 0) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 173; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_ptype_5_cdec_Metric = &__pyx_type_5_cdec_Metric;
   if (PyType_Ready(&__pyx_type_5_cdec_Decoder) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 39; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   if (__Pyx_SetAttrString(__pyx_m, "Decoder", (PyObject *)&__pyx_type_5_cdec_Decoder) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 39; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __pyx_ptype_5_cdec_Decoder = &__pyx_type_5_cdec_Decoder;
@@ -25818,7 +26801,7 @@ PyMODINIT_FUNC PyInit__cdec(void)
   __pyx_ptype_5_cdec___pyx_scope_struct_19_lines = &__pyx_type_5_cdec___pyx_scope_struct_19_lines;
   if (PyType_Ready(&__pyx_type_5_cdec___pyx_scope_struct_20___iter__) < 0) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 44; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __pyx_ptype_5_cdec___pyx_scope_struct_20___iter__ = &__pyx_type_5_cdec___pyx_scope_struct_20___iter__;
-  if (PyType_Ready(&__pyx_type_5_cdec___pyx_scope_struct_21___iter__) < 0) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 85; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (PyType_Ready(&__pyx_type_5_cdec___pyx_scope_struct_21___iter__) < 0) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 90; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __pyx_ptype_5_cdec___pyx_scope_struct_21___iter__ = &__pyx_type_5_cdec___pyx_scope_struct_21___iter__;
   if (PyType_Ready(&__pyx_type_5_cdec___pyx_scope_struct_22__make_config) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 28; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __pyx_ptype_5_cdec___pyx_scope_struct_22__make_config = &__pyx_type_5_cdec___pyx_scope_struct_22__make_config;
@@ -25843,25 +26826,25 @@ PyMODINIT_FUNC PyInit__cdec(void)
   if (PyObject_SetAttr(__pyx_m, __pyx_n_s___phrase, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 3; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":143
- *         return self.name.c_str()
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":190
+ *         return []
  * 
  * BLEU = Scorer('IBM_BLEU')             # <<<<<<<<<<<<<<
  * TER = Scorer('TER')
  */
-  __pyx_t_1 = PyObject_Call(((PyObject *)((PyObject*)__pyx_ptype_5_cdec_Scorer)), ((PyObject *)__pyx_k_tuple_55), NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 143; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_1 = PyObject_Call(((PyObject *)((PyObject*)__pyx_ptype_5_cdec_Scorer)), ((PyObject *)__pyx_k_tuple_57), NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 190; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __Pyx_GOTREF(__pyx_t_1);
-  if (PyObject_SetAttr(__pyx_m, __pyx_n_s__BLEU, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 143; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (PyObject_SetAttr(__pyx_m, __pyx_n_s__BLEU, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 190; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
 
-  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":144
+  /* "/Users/vchahun/Sandbox/cdec/python/src/mteval.pxi":191
  * 
  * BLEU = Scorer('IBM_BLEU')
  * TER = Scorer('TER')             # <<<<<<<<<<<<<<
  */
-  __pyx_t_1 = PyObject_Call(((PyObject *)((PyObject*)__pyx_ptype_5_cdec_Scorer)), ((PyObject *)__pyx_k_tuple_56), NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 144; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __pyx_t_1 = PyObject_Call(((PyObject *)((PyObject*)__pyx_ptype_5_cdec_Scorer)), ((PyObject *)__pyx_k_tuple_58), NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 191; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __Pyx_GOTREF(__pyx_t_1);
-  if (PyObject_SetAttr(__pyx_m, __pyx_n_s__TER, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 144; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  if (PyObject_SetAttr(__pyx_m, __pyx_n_s__TER, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[5]; __pyx_lineno = 191; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
 
   /* "_cdec.pyx":22
@@ -26356,6 +27339,40 @@ static CYTHON_INLINE PyObject *__Pyx_PyIter_Next2(PyObject* iterator, PyObject*
     }
 }
 
+static CYTHON_INLINE int __Pyx_CheckKeywordStrings(
+    PyObject *kwdict,
+    const char* function_name,
+    int kw_allowed)
+{
+    PyObject* key = 0;
+    Py_ssize_t pos = 0;
+    while (PyDict_Next(kwdict, &pos, &key, 0)) {
+        #if PY_MAJOR_VERSION < 3
+        if (unlikely(!PyString_CheckExact(key)) && unlikely(!PyString_Check(key)))
+        #else
+        if (unlikely(!PyUnicode_Check(key)))
+        #endif
+            goto invalid_keyword_type;
+    }
+    if ((!kw_allowed) && unlikely(key))
+        goto invalid_keyword;
+    return 1;
+invalid_keyword_type:
+    PyErr_Format(PyExc_TypeError,
+        "%s() keywords must be strings", function_name);
+    return 0;
+invalid_keyword:
+    PyErr_Format(PyExc_TypeError,
+    #if PY_MAJOR_VERSION < 3
+        "%s() got an unexpected keyword argument '%s'",
+        function_name, PyString_AsString(key));
+    #else
+        "%s() got an unexpected keyword argument '%U'",
+        function_name, key);
+    #endif
+    return 0;
+}
+
 static double __Pyx__PyObject_AsDouble(PyObject* obj) {
     PyObject* float_value;
     if (Py_TYPE(obj)->tp_as_number && Py_TYPE(obj)->tp_as_number->nb_float) {
diff --git a/python/src/decoder.pxd b/python/src/decoder.pxd
index d2065579..a66166a2 100644
--- a/python/src/decoder.pxd
+++ b/python/src/decoder.pxd
@@ -27,8 +27,6 @@ cdef extern from "decoder/decoder.h":
         variables_map& GetConf()
 
         # add grammar rules (currently only supported by SCFG decoders)
-        # that will be used on subsequent calls to Decode. rules should be in standard
-        # text format. This function does NOT read from a file.
         void AddSupplementalGrammarFromString(string& grammar_str)
         void AddSupplementalGrammar(shared_ptr[Grammar] grammar)
 
diff --git a/python/src/grammar.pxd b/python/src/grammar.pxd
index 43806f71..8853a614 100644
--- a/python/src/grammar.pxd
+++ b/python/src/grammar.pxd
@@ -3,7 +3,6 @@ from libcpp.string cimport string
 from utils cimport *
 
 cdef extern from "decoder/trule.h":
-
     cdef cppclass AlignmentPoint:
         AlignmentPoint(int s, int t)
         AlignmentPoint Inverted()
diff --git a/python/src/mteval.pxd b/python/src/mteval.pxd
index 52af6297..27c2808d 100644
--- a/python/src/mteval.pxd
+++ b/python/src/mteval.pxd
@@ -10,6 +10,7 @@ cdef extern from "mteval/ns.h":
         unsigned size()
         float operator[](unsigned i)
         void swap(SufficientStats& other)
+        vector[float] fields
 
     SufficientStats add "operator+" (SufficientStats&, SufficientStats&)
 
@@ -26,9 +27,15 @@ cdef extern from "mteval/ns.h":
                                     vector[WordID]& refs,
                                     SufficientStats* out)
 
-cdef extern from "mteval/ns.h" namespace "EvaluationMetric":
-    EvaluationMetric* Instance(string& metric_id)
-    EvaluationMetric* Instance() # IBM_BLEU
+    cdef EvaluationMetric* MetricInstance "EvaluationMetric::Instance" (string& metric_id)
+
+cdef extern from "py_scorer.h":
+    ctypedef float (*MetricScoreCallback)(void*, SufficientStats* stats)
+    ctypedef void (*MetricStatsCallback)(void*, 
+            string* hyp, vector[string]* refs, SufficientStats* out)
+    
+    cdef EvaluationMetric* PyMetricInstance "PythonEvaluationMetric::Instance"(
+            string& metric_id, void*, MetricStatsCallback, MetricScoreCallback)
 
 cdef extern from "training/candidate_set.h" namespace "training":
     cdef cppclass Candidate "const training::Candidate":
diff --git a/python/src/mteval.pxi b/python/src/mteval.pxi
index 4ba73168..f67f4f04 100644
--- a/python/src/mteval.pxi
+++ b/python/src/mteval.pxi
@@ -43,7 +43,12 @@ cdef class SufficientStats:
 
     def __iter__(self):
         for i in range(len(self)):
-            yield self.stats[0][i]
+            yield self[i]
+
+    def __getitem__(self, int index):
+        if not 0 <= index < len(self):
+            raise IndexError('sufficient stats vector index out of range')
+        return self.stats[0][index]
 
     def __iadd__(SufficientStats self, SufficientStats other):
         self.stats[0] += other.stats[0]
@@ -111,15 +116,17 @@ cdef class SegmentEvaluator:
 
 cdef class Scorer:
     cdef string* name
+    cdef mteval.EvaluationMetric* metric
 
-    def __cinit__(self, char* name):
-        self.name = new string(name)
+    def __cinit__(self, bytes name=None):
+        if name:
+            self.name = new string(name)
+            self.metric = mteval.MetricInstance(self.name[0])
 
     def __dealloc__(self):
         del self.name
     
     def __call__(self, refs):
-        cdef mteval.EvaluationMetric* metric = mteval.Instance(self.name[0])
         if isinstance(refs, unicode) or isinstance(refs, str):
             refs = [refs]
         cdef vector[vector[WordID]]* refsv = new vector[vector[WordID]]()
@@ -132,13 +139,53 @@ cdef class Scorer:
             del refv
         cdef unsigned i
         cdef SegmentEvaluator evaluator = SegmentEvaluator()
-        evaluator.metric = metric
-        evaluator.scorer = new shared_ptr[mteval.SegmentEvaluator](metric.CreateSegmentEvaluator(refsv[0]))
+        evaluator.metric = self.metric
+        evaluator.scorer = new shared_ptr[mteval.SegmentEvaluator](
+                self.metric.CreateSegmentEvaluator(refsv[0]))
         del refsv # in theory should not delete but store in SegmentEvaluator
         return evaluator
 
     def __str__(self):
         return self.name.c_str()
 
+cdef float _compute_score(void* metric_, mteval.SufficientStats* stats):
+    cdef Metric metric = <Metric> metric_
+    cdef list ss = []
+    cdef unsigned i
+    for i in range(stats.size()):
+        ss.append(stats[0][i])
+    return metric.score(ss)
+
+cdef void _compute_sufficient_stats(void* metric_, 
+        string* hyp,
+        vector[string]* refs,
+        mteval.SufficientStats* out):
+    cdef Metric metric = <Metric> metric_
+    cdef list refs_ = []
+    cdef unsigned i
+    for i in range(refs.size()):
+        refs_.append(refs[0][i].c_str())
+    cdef list ss = metric.evaluate(hyp.c_str(), refs_)
+    out.fields.resize(len(ss))
+    for i in range(len(ss)):
+        out.fields[i] = ss[i]
+
+cdef class Metric:
+    cdef Scorer scorer
+    def __cinit__(self):
+        self.scorer = Scorer()
+        self.scorer.name = new string(as_str(self.__class__.__name__))
+        self.scorer.metric = mteval.PyMetricInstance(self.scorer.name[0],
+                <void*> self, _compute_sufficient_stats, _compute_score)
+
+    def __call__(self, refs):
+        return self.scorer(refs)
+
+    def score(SufficientStats stats):
+        return 0
+
+    def evaluate(self, hyp, refs):
+        return []
+
 BLEU = Scorer('IBM_BLEU')
 TER = Scorer('TER')
diff --git a/python/src/observer.h b/python/src/observer.h
index d398f2f7..05f3c9be 100644
--- a/python/src/observer.h
+++ b/python/src/observer.h
@@ -1,6 +1,5 @@
 #include "decoder/hg.h"
 #include "decoder/decoder.h"
-#include <iostream>
 
 struct BasicObserver: public DecoderObserver {
     Hypergraph* hypergraph;
diff --git a/python/src/py_scorer.h b/python/src/py_scorer.h
new file mode 100644
index 00000000..22dc9fee
--- /dev/null
+++ b/python/src/py_scorer.h
@@ -0,0 +1,44 @@
+#include "ns.h"
+#include "tdict.h"
+
+typedef float (*MetricScoreCallback)(void*, SufficientStats* stats);
+typedef void (*MetricStatsCallback)(void*,
+        std::string *hyp,
+        std::vector<std::string> *refs,
+        SufficientStats* out);
+
+struct PythonEvaluationMetric : public EvaluationMetric {
+
+    PythonEvaluationMetric(const std::string& id) : EvaluationMetric(id) {}
+
+    static EvaluationMetric* Instance(const std::string& id, 
+            void* obj,
+            MetricStatsCallback statscb,
+            MetricScoreCallback scorecb) {
+        PythonEvaluationMetric* metric = new PythonEvaluationMetric(id);
+        metric->pymetric = obj;
+        metric->_compute_score =  scorecb;
+        metric->_compute_sufficient_stats = statscb;
+        return metric;
+    }
+
+    float ComputeScore(const SufficientStats& stats) const {
+        SufficientStats stats_(stats);
+        return _compute_score(pymetric, &stats_);
+    }
+
+    void ComputeSufficientStatistics(const std::vector<WordID>& hyp,
+            const std::vector<std::vector<WordID> >& refs,
+            SufficientStats* out) const {
+        std::string hyp_(TD::GetString(hyp));
+        std::vector<std::string> refs_;
+        for(unsigned i = 0; i < refs.size(); ++i) {
+            refs_.push_back(TD::GetString(refs[i]));
+        }
+        _compute_sufficient_stats(pymetric, &hyp_, &refs_, out);
+    }
+
+    void* pymetric;
+    MetricStatsCallback _compute_sufficient_stats;
+    MetricScoreCallback _compute_score;
+};
diff --git a/sa-extract/Makefile b/sa-extract/Makefile
index 7b39ae4d..3145bbfe 100644
--- a/sa-extract/Makefile
+++ b/sa-extract/Makefile
@@ -1,17 +1,11 @@
-PYVER=python2.7
-PYDIR=/usr/local/Cellar/python/2.7.2
-PYINCLUDE=$(PYDIR)/include/$(PYVER)
-CYTHON=/usr/local/share/python/cython
-PYTHON=$(PYDIR)/bin/python
-
 %.c: %.pyx
-	$(CYTHON) $< -o $@
+	cython $< -o $@
 
 %.o: %.cc
 	g++ -O6 -g -fPIC -c $<
 
 all: cstrmap.c strmap.cc rule.c sym.c cdat.c cintlist.c cfloatlist.c calignment.c csuf.c clex.c rulefactory.c cveb.c lcp.c precomputation.c
-	$(PYTHON) setup.py build
+	python setup.py build
 
 clean:
 	rm -f cdat.c cstrmap.c sym.c rule.c cintlist.c cfloatlist.c calignment.c csuf.c clex.c rulefactory.c cveb.c lcp.c precomputation.c *.so *.o *.cxx *~ *.pyc
-- 
cgit v1.2.3


From ee5e376e263d9aeabdeee6968b4457f53d3fc772 Mon Sep 17 00:00:00 2001
From: Victor Chahuneau <vchahune@cs.cmu.edu>
Date: Fri, 27 Jul 2012 23:33:45 -0400
Subject: [python] Move python files to avoid pythonpath conflicts

---
 python/cdec/__init__.py         |    1 -
 python/cdec/configobj.py        | 2468 ---------------------------------------
 python/cdec/sa/__init__.py      |    4 -
 python/cdec/sa/compile.py       |   94 --
 python/cdec/sa/extract.py       |   31 -
 python/cdec/sa/extractor.py     |   78 --
 python/cdec/sa/features.py      |   57 -
 python/cdec/score.py            |    1 -
 python/pkg/cdec/__init__.py     |    1 +
 python/pkg/cdec/configobj.py    | 2468 +++++++++++++++++++++++++++++++++++++++
 python/pkg/cdec/sa/__init__.py  |    4 +
 python/pkg/cdec/sa/compile.py   |   94 ++
 python/pkg/cdec/sa/extract.py   |   31 +
 python/pkg/cdec/sa/extractor.py |   78 ++
 python/pkg/cdec/sa/features.py  |   57 +
 python/pkg/cdec/score.py        |    1 +
 python/setup.py                 |    3 +-
 python/src/sa/_sa.c             |   39 +-
 python/src/sa/sym.pxi           |    2 +-
 19 files changed, 2753 insertions(+), 2759 deletions(-)
 delete mode 100644 python/cdec/__init__.py
 delete mode 100644 python/cdec/configobj.py
 delete mode 100644 python/cdec/sa/__init__.py
 delete mode 100644 python/cdec/sa/compile.py
 delete mode 100644 python/cdec/sa/extract.py
 delete mode 100644 python/cdec/sa/extractor.py
 delete mode 100644 python/cdec/sa/features.py
 delete mode 100644 python/cdec/score.py
 create mode 100644 python/pkg/cdec/__init__.py
 create mode 100644 python/pkg/cdec/configobj.py
 create mode 100644 python/pkg/cdec/sa/__init__.py
 create mode 100644 python/pkg/cdec/sa/compile.py
 create mode 100644 python/pkg/cdec/sa/extract.py
 create mode 100644 python/pkg/cdec/sa/extractor.py
 create mode 100644 python/pkg/cdec/sa/features.py
 create mode 100644 python/pkg/cdec/score.py

(limited to 'python/cdec/__init__.py')

diff --git a/python/cdec/__init__.py b/python/cdec/__init__.py
deleted file mode 100644
index 19058493..00000000
--- a/python/cdec/__init__.py
+++ /dev/null
@@ -1 +0,0 @@
-from _cdec import Decoder, Lattice, TRule, NT, NTRef, ParseFailed, InvalidConfig
diff --git a/python/cdec/configobj.py b/python/cdec/configobj.py
deleted file mode 100644
index c1f6e6df..00000000
--- a/python/cdec/configobj.py
+++ /dev/null
@@ -1,2468 +0,0 @@
-# configobj.py
-# A config file reader/writer that supports nested sections in config files.
-# Copyright (C) 2005-2010 Michael Foord, Nicola Larosa
-# E-mail: fuzzyman AT voidspace DOT org DOT uk
-#         nico AT tekNico DOT net
-
-# ConfigObj 4
-# http://www.voidspace.org.uk/python/configobj.html
-
-# Released subject to the BSD License
-# Please see http://www.voidspace.org.uk/python/license.shtml
-
-# Scripts maintained at http://www.voidspace.org.uk/python/index.shtml
-# For information about bugfixes, updates and support, please join the
-# ConfigObj mailing list:
-# http://lists.sourceforge.net/lists/listinfo/configobj-develop
-# Comments, suggestions and bug reports welcome.
-
-from __future__ import generators
-
-import os
-import re
-import sys
-
-from codecs import BOM_UTF8, BOM_UTF16, BOM_UTF16_BE, BOM_UTF16_LE
-
-
-# imported lazily to avoid startup performance hit if it isn't used
-compiler = None
-
-# A dictionary mapping BOM to
-# the encoding to decode with, and what to set the
-# encoding attribute to.
-BOMS = {
-    BOM_UTF8: ('utf_8', None),
-    BOM_UTF16_BE: ('utf16_be', 'utf_16'),
-    BOM_UTF16_LE: ('utf16_le', 'utf_16'),
-    BOM_UTF16: ('utf_16', 'utf_16'),
-    }
-# All legal variants of the BOM codecs.
-# TODO: the list of aliases is not meant to be exhaustive, is there a
-#   better way ?
-BOM_LIST = {
-    'utf_16': 'utf_16',
-    'u16': 'utf_16',
-    'utf16': 'utf_16',
-    'utf-16': 'utf_16',
-    'utf16_be': 'utf16_be',
-    'utf_16_be': 'utf16_be',
-    'utf-16be': 'utf16_be',
-    'utf16_le': 'utf16_le',
-    'utf_16_le': 'utf16_le',
-    'utf-16le': 'utf16_le',
-    'utf_8': 'utf_8',
-    'u8': 'utf_8',
-    'utf': 'utf_8',
-    'utf8': 'utf_8',
-    'utf-8': 'utf_8',
-    }
-
-# Map of encodings to the BOM to write.
-BOM_SET = {
-    'utf_8': BOM_UTF8,
-    'utf_16': BOM_UTF16,
-    'utf16_be': BOM_UTF16_BE,
-    'utf16_le': BOM_UTF16_LE,
-    None: BOM_UTF8
-    }
-
-
-def match_utf8(encoding):
-    return BOM_LIST.get(encoding.lower()) == 'utf_8'
-
-
-# Quote strings used for writing values
-squot = "'%s'"
-dquot = '"%s"'
-noquot = "%s"
-wspace_plus = ' \r\n\v\t\'"'
-tsquot = '"""%s"""'
-tdquot = "'''%s'''"
-
-# Sentinel for use in getattr calls to replace hasattr
-MISSING = object()
-
-__version__ = '4.7.2'
-
-try:
-    any
-except NameError:
-    def any(iterable):
-        for entry in iterable:
-            if entry:
-                return True
-        return False
-
-
-__all__ = (
-    '__version__',
-    'DEFAULT_INDENT_TYPE',
-    'DEFAULT_INTERPOLATION',
-    'ConfigObjError',
-    'NestingError',
-    'ParseError',
-    'DuplicateError',
-    'ConfigspecError',
-    'ConfigObj',
-    'SimpleVal',
-    'InterpolationError',
-    'InterpolationLoopError',
-    'MissingInterpolationOption',
-    'RepeatSectionError',
-    'ReloadError',
-    'UnreprError',
-    'UnknownType',
-    'flatten_errors',
-    'get_extra_values'
-)
-
-DEFAULT_INTERPOLATION = 'configparser'
-DEFAULT_INDENT_TYPE = '    '
-MAX_INTERPOL_DEPTH = 10
-
-OPTION_DEFAULTS = {
-    'interpolation': True,
-    'raise_errors': False,
-    'list_values': True,
-    'create_empty': False,
-    'file_error': False,
-    'configspec': None,
-    'stringify': True,
-    # option may be set to one of ('', ' ', '\t')
-    'indent_type': None,
-    'encoding': None,
-    'default_encoding': None,
-    'unrepr': False,
-    'write_empty_values': False,
-}
-
-
-
-def getObj(s):
-    global compiler
-    if compiler is None:
-        import compiler
-    s = "a=" + s
-    p = compiler.parse(s)
-    return p.getChildren()[1].getChildren()[0].getChildren()[1]
-
-
-class UnknownType(Exception):
-    pass
-
-
-class Builder(object):
-    
-    def build(self, o):
-        m = getattr(self, 'build_' + o.__class__.__name__, None)
-        if m is None:
-            raise UnknownType(o.__class__.__name__)
-        return m(o)
-    
-    def build_List(self, o):
-        return map(self.build, o.getChildren())
-    
-    def build_Const(self, o):
-        return o.value
-    
-    def build_Dict(self, o):
-        d = {}
-        i = iter(map(self.build, o.getChildren()))
-        for el in i:
-            d[el] = i.next()
-        return d
-    
-    def build_Tuple(self, o):
-        return tuple(self.build_List(o))
-    
-    def build_Name(self, o):
-        if o.name == 'None':
-            return None
-        if o.name == 'True':
-            return True
-        if o.name == 'False':
-            return False
-        
-        # An undefined Name
-        raise UnknownType('Undefined Name')
-    
-    def build_Add(self, o):
-        real, imag = map(self.build_Const, o.getChildren())
-        try:
-            real = float(real)
-        except TypeError:
-            raise UnknownType('Add')
-        if not isinstance(imag, complex) or imag.real != 0.0:
-            raise UnknownType('Add')
-        return real+imag
-    
-    def build_Getattr(self, o):
-        parent = self.build(o.expr)
-        return getattr(parent, o.attrname)
-    
-    def build_UnarySub(self, o):
-        return -self.build_Const(o.getChildren()[0])
-    
-    def build_UnaryAdd(self, o):
-        return self.build_Const(o.getChildren()[0])
-
-
-_builder = Builder()
-
-
-def unrepr(s):
-    if not s:
-        return s
-    return _builder.build(getObj(s))
-
-
-
-class ConfigObjError(SyntaxError):
-    """
-    This is the base class for all errors that ConfigObj raises.
-    It is a subclass of SyntaxError.
-    """
-    def __init__(self, message='', line_number=None, line=''):
-        self.line = line
-        self.line_number = line_number
-        SyntaxError.__init__(self, message)
-
-
-class NestingError(ConfigObjError):
-    """
-    This error indicates a level of nesting that doesn't match.
-    """
-
-
-class ParseError(ConfigObjError):
-    """
-    This error indicates that a line is badly written.
-    It is neither a valid ``key = value`` line,
-    nor a valid section marker line.
-    """
-
-
-class ReloadError(IOError):
-    """
-    A 'reload' operation failed.
-    This exception is a subclass of ``IOError``.
-    """
-    def __init__(self):
-        IOError.__init__(self, 'reload failed, filename is not set.')
-
-
-class DuplicateError(ConfigObjError):
-    """
-    The keyword or section specified already exists.
-    """
-
-
-class ConfigspecError(ConfigObjError):
-    """
-    An error occured whilst parsing a configspec.
-    """
-
-
-class InterpolationError(ConfigObjError):
-    """Base class for the two interpolation errors."""
-
-
-class InterpolationLoopError(InterpolationError):
-    """Maximum interpolation depth exceeded in string interpolation."""
-
-    def __init__(self, option):
-        InterpolationError.__init__(
-            self,
-            'interpolation loop detected in value "%s".' % option)
-
-
-class RepeatSectionError(ConfigObjError):
-    """
-    This error indicates additional sections in a section with a
-    ``__many__`` (repeated) section.
-    """
-
-
-class MissingInterpolationOption(InterpolationError):
-    """A value specified for interpolation was missing."""
-    def __init__(self, option):
-        msg = 'missing option "%s" in interpolation.' % option
-        InterpolationError.__init__(self, msg)
-
-
-class UnreprError(ConfigObjError):
-    """An error parsing in unrepr mode."""
-
-
-
-class InterpolationEngine(object):
-    """
-    A helper class to help perform string interpolation.
-
-    This class is an abstract base class; its descendants perform
-    the actual work.
-    """
-
-    # compiled regexp to use in self.interpolate()
-    _KEYCRE = re.compile(r"%\(([^)]*)\)s")
-    _cookie = '%'
-
-    def __init__(self, section):
-        # the Section instance that "owns" this engine
-        self.section = section
-
-
-    def interpolate(self, key, value):
-        # short-cut
-        if not self._cookie in value:
-            return value
-        
-        def recursive_interpolate(key, value, section, backtrail):
-            """The function that does the actual work.
-
-            ``value``: the string we're trying to interpolate.
-            ``section``: the section in which that string was found
-            ``backtrail``: a dict to keep track of where we've been,
-            to detect and prevent infinite recursion loops
-
-            This is similar to a depth-first-search algorithm.
-            """
-            # Have we been here already?
-            if (key, section.name) in backtrail:
-                # Yes - infinite loop detected
-                raise InterpolationLoopError(key)
-            # Place a marker on our backtrail so we won't come back here again
-            backtrail[(key, section.name)] = 1
-
-            # Now start the actual work
-            match = self._KEYCRE.search(value)
-            while match:
-                # The actual parsing of the match is implementation-dependent,
-                # so delegate to our helper function
-                k, v, s = self._parse_match(match)
-                if k is None:
-                    # That's the signal that no further interpolation is needed
-                    replacement = v
-                else:
-                    # Further interpolation may be needed to obtain final value
-                    replacement = recursive_interpolate(k, v, s, backtrail)
-                # Replace the matched string with its final value
-                start, end = match.span()
-                value = ''.join((value[:start], replacement, value[end:]))
-                new_search_start = start + len(replacement)
-                # Pick up the next interpolation key, if any, for next time
-                # through the while loop
-                match = self._KEYCRE.search(value, new_search_start)
-
-            # Now safe to come back here again; remove marker from backtrail
-            del backtrail[(key, section.name)]
-
-            return value
-
-        # Back in interpolate(), all we have to do is kick off the recursive
-        # function with appropriate starting values
-        value = recursive_interpolate(key, value, self.section, {})
-        return value
-
-
-    def _fetch(self, key):
-        """Helper function to fetch values from owning section.
-
-        Returns a 2-tuple: the value, and the section where it was found.
-        """
-        # switch off interpolation before we try and fetch anything !
-        save_interp = self.section.main.interpolation
-        self.section.main.interpolation = False
-
-        # Start at section that "owns" this InterpolationEngine
-        current_section = self.section
-        while True:
-            # try the current section first
-            val = current_section.get(key)
-            if val is not None and not isinstance(val, Section):
-                break
-            # try "DEFAULT" next
-            val = current_section.get('DEFAULT', {}).get(key)
-            if val is not None and not isinstance(val, Section):
-                break
-            # move up to parent and try again
-            # top-level's parent is itself
-            if current_section.parent is current_section:
-                # reached top level, time to give up
-                break
-            current_section = current_section.parent
-
-        # restore interpolation to previous value before returning
-        self.section.main.interpolation = save_interp
-        if val is None:
-            raise MissingInterpolationOption(key)
-        return val, current_section
-
-
-    def _parse_match(self, match):
-        """Implementation-dependent helper function.
-
-        Will be passed a match object corresponding to the interpolation
-        key we just found (e.g., "%(foo)s" or "$foo"). Should look up that
-        key in the appropriate config file section (using the ``_fetch()``
-        helper function) and return a 3-tuple: (key, value, section)
-
-        ``key`` is the name of the key we're looking for
-        ``value`` is the value found for that key
-        ``section`` is a reference to the section where it was found
-
-        ``key`` and ``section`` should be None if no further
-        interpolation should be performed on the resulting value
-        (e.g., if we interpolated "$$" and returned "$").
-        """
-        raise NotImplementedError()
-    
-
-
-class ConfigParserInterpolation(InterpolationEngine):
-    """Behaves like ConfigParser."""
-    _cookie = '%'
-    _KEYCRE = re.compile(r"%\(([^)]*)\)s")
-
-    def _parse_match(self, match):
-        key = match.group(1)
-        value, section = self._fetch(key)
-        return key, value, section
-
-
-
-class TemplateInterpolation(InterpolationEngine):
-    """Behaves like string.Template."""
-    _cookie = '$'
-    _delimiter = '$'
-    _KEYCRE = re.compile(r"""
-        \$(?:
-          (?P<escaped>\$)              |   # Two $ signs
-          (?P<named>[_a-z][_a-z0-9]*)  |   # $name format
-          {(?P<braced>[^}]*)}              # ${name} format
-        )
-        """, re.IGNORECASE | re.VERBOSE)
-
-    def _parse_match(self, match):
-        # Valid name (in or out of braces): fetch value from section
-        key = match.group('named') or match.group('braced')
-        if key is not None:
-            value, section = self._fetch(key)
-            return key, value, section
-        # Escaped delimiter (e.g., $$): return single delimiter
-        if match.group('escaped') is not None:
-            # Return None for key and section to indicate it's time to stop
-            return None, self._delimiter, None
-        # Anything else: ignore completely, just return it unchanged
-        return None, match.group(), None
-
-
-interpolation_engines = {
-    'configparser': ConfigParserInterpolation,
-    'template': TemplateInterpolation,
-}
-
-
-def __newobj__(cls, *args):
-    # Hack for pickle
-    return cls.__new__(cls, *args) 
-
-class Section(dict):
-    """
-    A dictionary-like object that represents a section in a config file.
-    
-    It does string interpolation if the 'interpolation' attribute
-    of the 'main' object is set to True.
-    
-    Interpolation is tried first from this object, then from the 'DEFAULT'
-    section of this object, next from the parent and its 'DEFAULT' section,
-    and so on until the main object is reached.
-    
-    A Section will behave like an ordered dictionary - following the
-    order of the ``scalars`` and ``sections`` attributes.
-    You can use this to change the order of members.
-    
-    Iteration follows the order: scalars, then sections.
-    """
-
-    
-    def __setstate__(self, state):
-        dict.update(self, state[0])
-        self.__dict__.update(state[1])
-
-    def __reduce__(self):
-        state = (dict(self), self.__dict__)
-        return (__newobj__, (self.__class__,), state)
-    
-    
-    def __init__(self, parent, depth, main, indict=None, name=None):
-        """
-        * parent is the section above
-        * depth is the depth level of this section
-        * main is the main ConfigObj
-        * indict is a dictionary to initialise the section with
-        """
-        if indict is None:
-            indict = {}
-        dict.__init__(self)
-        # used for nesting level *and* interpolation
-        self.parent = parent
-        # used for the interpolation attribute
-        self.main = main
-        # level of nesting depth of this Section
-        self.depth = depth
-        # purely for information
-        self.name = name
-        #
-        self._initialise()
-        # we do this explicitly so that __setitem__ is used properly
-        # (rather than just passing to ``dict.__init__``)
-        for entry, value in indict.iteritems():
-            self[entry] = value
-            
-            
-    def _initialise(self):
-        # the sequence of scalar values in this Section
-        self.scalars = []
-        # the sequence of sections in this Section
-        self.sections = []
-        # for comments :-)
-        self.comments = {}
-        self.inline_comments = {}
-        # the configspec
-        self.configspec = None
-        # for defaults
-        self.defaults = []
-        self.default_values = {}
-        self.extra_values = []
-        self._created = False
-
-
-    def _interpolate(self, key, value):
-        try:
-            # do we already have an interpolation engine?
-            engine = self._interpolation_engine
-        except AttributeError:
-            # not yet: first time running _interpolate(), so pick the engine
-            name = self.main.interpolation
-            if name == True:  # note that "if name:" would be incorrect here
-                # backwards-compatibility: interpolation=True means use default
-                name = DEFAULT_INTERPOLATION
-            name = name.lower()  # so that "Template", "template", etc. all work
-            class_ = interpolation_engines.get(name, None)
-            if class_ is None:
-                # invalid value for self.main.interpolation
-                self.main.interpolation = False
-                return value
-            else:
-                # save reference to engine so we don't have to do this again
-                engine = self._interpolation_engine = class_(self)
-        # let the engine do the actual work
-        return engine.interpolate(key, value)
-
-
-    def __getitem__(self, key):
-        """Fetch the item and do string interpolation."""
-        val = dict.__getitem__(self, key)
-        if self.main.interpolation: 
-            if isinstance(val, basestring):
-                return self._interpolate(key, val)
-            if isinstance(val, list):
-                def _check(entry):
-                    if isinstance(entry, basestring):
-                        return self._interpolate(key, entry)
-                    return entry
-                new = [_check(entry) for entry in val]
-                if new != val:
-                    return new
-        return val
-
-
-    def __setitem__(self, key, value, unrepr=False):
-        """
-        Correctly set a value.
-        
-        Making dictionary values Section instances.
-        (We have to special case 'Section' instances - which are also dicts)
-        
-        Keys must be strings.
-        Values need only be strings (or lists of strings) if
-        ``main.stringify`` is set.
-        
-        ``unrepr`` must be set when setting a value to a dictionary, without
-        creating a new sub-section.
-        """
-        if not isinstance(key, basestring):
-            raise ValueError('The key "%s" is not a string.' % key)
-        
-        # add the comment
-        if key not in self.comments:
-            self.comments[key] = []
-            self.inline_comments[key] = ''
-        # remove the entry from defaults
-        if key in self.defaults:
-            self.defaults.remove(key)
-        #
-        if isinstance(value, Section):
-            if key not in self:
-                self.sections.append(key)
-            dict.__setitem__(self, key, value)
-        elif isinstance(value, dict) and not unrepr:
-            # First create the new depth level,
-            # then create the section
-            if key not in self:
-                self.sections.append(key)
-            new_depth = self.depth + 1
-            dict.__setitem__(
-                self,
-                key,
-                Section(
-                    self,
-                    new_depth,
-                    self.main,
-                    indict=value,
-                    name=key))
-        else:
-            if key not in self:
-                self.scalars.append(key)
-            if not self.main.stringify:
-                if isinstance(value, basestring):
-                    pass
-                elif isinstance(value, (list, tuple)):
-                    for entry in value:
-                        if not isinstance(entry, basestring):
-                            raise TypeError('Value is not a string "%s".' % entry)
-                else:
-                    raise TypeError('Value is not a string "%s".' % value)
-            dict.__setitem__(self, key, value)
-
-
-    def __delitem__(self, key):
-        """Remove items from the sequence when deleting."""
-        dict. __delitem__(self, key)
-        if key in self.scalars:
-            self.scalars.remove(key)
-        else:
-            self.sections.remove(key)
-        del self.comments[key]
-        del self.inline_comments[key]
-
-
-    def get(self, key, default=None):
-        """A version of ``get`` that doesn't bypass string interpolation."""
-        try:
-            return self[key]
-        except KeyError:
-            return default
-
-
-    def update(self, indict):
-        """
-        A version of update that uses our ``__setitem__``.
-        """
-        for entry in indict:
-            self[entry] = indict[entry]
-
-
-    def pop(self, key, default=MISSING):
-        """
-        'D.pop(k[,d]) -> v, remove specified key and return the corresponding value.
-        If key is not found, d is returned if given, otherwise KeyError is raised'
-        """
-        try:
-            val = self[key]
-        except KeyError:
-            if default is MISSING:
-                raise
-            val = default
-        else:
-            del self[key]
-        return val
-
-
-    def popitem(self):
-        """Pops the first (key,val)"""
-        sequence = (self.scalars + self.sections)
-        if not sequence:
-            raise KeyError(": 'popitem(): dictionary is empty'")
-        key = sequence[0]
-        val =  self[key]
-        del self[key]
-        return key, val
-
-
-    def clear(self):
-        """
-        A version of clear that also affects scalars/sections
-        Also clears comments and configspec.
-        
-        Leaves other attributes alone :
-            depth/main/parent are not affected
-        """
-        dict.clear(self)
-        self.scalars = []
-        self.sections = []
-        self.comments = {}
-        self.inline_comments = {}
-        self.configspec = None
-        self.defaults = []
-        self.extra_values = []
-
-
-    def setdefault(self, key, default=None):
-        """A version of setdefault that sets sequence if appropriate."""
-        try:
-            return self[key]
-        except KeyError:
-            self[key] = default
-            return self[key]
-
-
-    def items(self):
-        """D.items() -> list of D's (key, value) pairs, as 2-tuples"""
-        return zip((self.scalars + self.sections), self.values())
-
-
-    def keys(self):
-        """D.keys() -> list of D's keys"""
-        return (self.scalars + self.sections)
-
-
-    def values(self):
-        """D.values() -> list of D's values"""
-        return [self[key] for key in (self.scalars + self.sections)]
-
-
-    def iteritems(self):
-        """D.iteritems() -> an iterator over the (key, value) items of D"""
-        return iter(self.items())
-
-
-    def iterkeys(self):
-        """D.iterkeys() -> an iterator over the keys of D"""
-        return iter((self.scalars + self.sections))
-
-    __iter__ = iterkeys
-
-
-    def itervalues(self):
-        """D.itervalues() -> an iterator over the values of D"""
-        return iter(self.values())
-
-
-    def __repr__(self):
-        """x.__repr__() <==> repr(x)"""
-        def _getval(key):
-            try:
-                return self[key]
-            except MissingInterpolationOption:
-                return dict.__getitem__(self, key)
-        return '{%s}' % ', '.join([('%s: %s' % (repr(key), repr(_getval(key))))
-            for key in (self.scalars + self.sections)])
-
-    __str__ = __repr__
-    __str__.__doc__ = "x.__str__() <==> str(x)"
-
-
-    # Extra methods - not in a normal dictionary
-
-    def dict(self):
-        """
-        Return a deepcopy of self as a dictionary.
-        
-        All members that are ``Section`` instances are recursively turned to
-        ordinary dictionaries - by calling their ``dict`` method.
-        
-        >>> n = a.dict()
-        >>> n == a
-        1
-        >>> n is a
-        0
-        """
-        newdict = {}
-        for entry in self:
-            this_entry = self[entry]
-            if isinstance(this_entry, Section):
-                this_entry = this_entry.dict()
-            elif isinstance(this_entry, list):
-                # create a copy rather than a reference
-                this_entry = list(this_entry)
-            elif isinstance(this_entry, tuple):
-                # create a copy rather than a reference
-                this_entry = tuple(this_entry)
-            newdict[entry] = this_entry
-        return newdict
-
-
-    def merge(self, indict):
-        """
-        A recursive update - useful for merging config files.
-        
-        >>> a = '''[section1]
-        ...     option1 = True
-        ...     [[subsection]]
-        ...     more_options = False
-        ...     # end of file'''.splitlines()
-        >>> b = '''# File is user.ini
-        ...     [section1]
-        ...     option1 = False
-        ...     # end of file'''.splitlines()
-        >>> c1 = ConfigObj(b)
-        >>> c2 = ConfigObj(a)
-        >>> c2.merge(c1)
-        >>> c2
-        ConfigObj({'section1': {'option1': 'False', 'subsection': {'more_options': 'False'}}})
-        """
-        for key, val in indict.items():
-            if (key in self and isinstance(self[key], dict) and
-                                isinstance(val, dict)):
-                self[key].merge(val)
-            else:   
-                self[key] = val
-
-
-    def rename(self, oldkey, newkey):
-        """
-        Change a keyname to another, without changing position in sequence.
-        
-        Implemented so that transformations can be made on keys,
-        as well as on values. (used by encode and decode)
-        
-        Also renames comments.
-        """
-        if oldkey in self.scalars:
-            the_list = self.scalars
-        elif oldkey in self.sections:
-            the_list = self.sections
-        else:
-            raise KeyError('Key "%s" not found.' % oldkey)
-        pos = the_list.index(oldkey)
-        #
-        val = self[oldkey]
-        dict.__delitem__(self, oldkey)
-        dict.__setitem__(self, newkey, val)
-        the_list.remove(oldkey)
-        the_list.insert(pos, newkey)
-        comm = self.comments[oldkey]
-        inline_comment = self.inline_comments[oldkey]
-        del self.comments[oldkey]
-        del self.inline_comments[oldkey]
-        self.comments[newkey] = comm
-        self.inline_comments[newkey] = inline_comment
-
-
-    def walk(self, function, raise_errors=True,
-            call_on_sections=False, **keywargs):
-        """
-        Walk every member and call a function on the keyword and value.
-        
-        Return a dictionary of the return values
-        
-        If the function raises an exception, raise the errror
-        unless ``raise_errors=False``, in which case set the return value to
-        ``False``.
-        
-        Any unrecognised keyword arguments you pass to walk, will be pased on
-        to the function you pass in.
-        
-        Note: if ``call_on_sections`` is ``True`` then - on encountering a
-        subsection, *first* the function is called for the *whole* subsection,
-        and then recurses into it's members. This means your function must be
-        able to handle strings, dictionaries and lists. This allows you
-        to change the key of subsections as well as for ordinary members. The
-        return value when called on the whole subsection has to be discarded.
-        
-        See  the encode and decode methods for examples, including functions.
-        
-        .. admonition:: caution
-        
-            You can use ``walk`` to transform the names of members of a section
-            but you mustn't add or delete members.
-        
-        >>> config = '''[XXXXsection]
-        ... XXXXkey = XXXXvalue'''.splitlines()
-        >>> cfg = ConfigObj(config)
-        >>> cfg
-        ConfigObj({'XXXXsection': {'XXXXkey': 'XXXXvalue'}})
-        >>> def transform(section, key):
-        ...     val = section[key]
-        ...     newkey = key.replace('XXXX', 'CLIENT1')
-        ...     section.rename(key, newkey)
-        ...     if isinstance(val, (tuple, list, dict)):
-        ...         pass
-        ...     else:
-        ...         val = val.replace('XXXX', 'CLIENT1')
-        ...         section[newkey] = val
-        >>> cfg.walk(transform, call_on_sections=True)
-        {'CLIENT1section': {'CLIENT1key': None}}
-        >>> cfg
-        ConfigObj({'CLIENT1section': {'CLIENT1key': 'CLIENT1value'}})
-        """
-        out = {}
-        # scalars first
-        for i in range(len(self.scalars)):
-            entry = self.scalars[i]
-            try:
-                val = function(self, entry, **keywargs)
-                # bound again in case name has changed
-                entry = self.scalars[i]
-                out[entry] = val
-            except Exception:
-                if raise_errors:
-                    raise
-                else:
-                    entry = self.scalars[i]
-                    out[entry] = False
-        # then sections
-        for i in range(len(self.sections)):
-            entry = self.sections[i]
-            if call_on_sections:
-                try:
-                    function(self, entry, **keywargs)
-                except Exception:
-                    if raise_errors:
-                        raise
-                    else:
-                        entry = self.sections[i]
-                        out[entry] = False
-                # bound again in case name has changed
-                entry = self.sections[i]
-            # previous result is discarded
-            out[entry] = self[entry].walk(
-                function,
-                raise_errors=raise_errors,
-                call_on_sections=call_on_sections,
-                **keywargs)
-        return out
-
-
-    def as_bool(self, key):
-        """
-        Accepts a key as input. The corresponding value must be a string or
-        the objects (``True`` or 1) or (``False`` or 0). We allow 0 and 1 to
-        retain compatibility with Python 2.2.
-        
-        If the string is one of  ``True``, ``On``, ``Yes``, or ``1`` it returns 
-        ``True``.
-        
-        If the string is one of  ``False``, ``Off``, ``No``, or ``0`` it returns 
-        ``False``.
-        
-        ``as_bool`` is not case sensitive.
-        
-        Any other input will raise a ``ValueError``.
-        
-        >>> a = ConfigObj()
-        >>> a['a'] = 'fish'
-        >>> a.as_bool('a')
-        Traceback (most recent call last):
-        ValueError: Value "fish" is neither True nor False
-        >>> a['b'] = 'True'
-        >>> a.as_bool('b')
-        1
-        >>> a['b'] = 'off'
-        >>> a.as_bool('b')
-        0
-        """
-        val = self[key]
-        if val == True:
-            return True
-        elif val == False:
-            return False
-        else:
-            try:
-                if not isinstance(val, basestring):
-                    # TODO: Why do we raise a KeyError here?
-                    raise KeyError()
-                else:
-                    return self.main._bools[val.lower()]
-            except KeyError:
-                raise ValueError('Value "%s" is neither True nor False' % val)
-
-
-    def as_int(self, key):
-        """
-        A convenience method which coerces the specified value to an integer.
-        
-        If the value is an invalid literal for ``int``, a ``ValueError`` will
-        be raised.
-        
-        >>> a = ConfigObj()
-        >>> a['a'] = 'fish'
-        >>> a.as_int('a')
-        Traceback (most recent call last):
-        ValueError: invalid literal for int() with base 10: 'fish'
-        >>> a['b'] = '1'
-        >>> a.as_int('b')
-        1
-        >>> a['b'] = '3.2'
-        >>> a.as_int('b')
-        Traceback (most recent call last):
-        ValueError: invalid literal for int() with base 10: '3.2'
-        """
-        return int(self[key])
-
-
-    def as_float(self, key):
-        """
-        A convenience method which coerces the specified value to a float.
-        
-        If the value is an invalid literal for ``float``, a ``ValueError`` will
-        be raised.
-        
-        >>> a = ConfigObj()
-        >>> a['a'] = 'fish'
-        >>> a.as_float('a')
-        Traceback (most recent call last):
-        ValueError: invalid literal for float(): fish
-        >>> a['b'] = '1'
-        >>> a.as_float('b')
-        1.0
-        >>> a['b'] = '3.2'
-        >>> a.as_float('b')
-        3.2000000000000002
-        """
-        return float(self[key])
-    
-    
-    def as_list(self, key):
-        """
-        A convenience method which fetches the specified value, guaranteeing
-        that it is a list.
-        
-        >>> a = ConfigObj()
-        >>> a['a'] = 1
-        >>> a.as_list('a')
-        [1]
-        >>> a['a'] = (1,)
-        >>> a.as_list('a')
-        [1]
-        >>> a['a'] = [1]
-        >>> a.as_list('a')
-        [1]
-        """
-        result = self[key]
-        if isinstance(result, (tuple, list)):
-            return list(result)
-        return [result]
-        
-
-    def restore_default(self, key):
-        """
-        Restore (and return) default value for the specified key.
-        
-        This method will only work for a ConfigObj that was created
-        with a configspec and has been validated.
-        
-        If there is no default value for this key, ``KeyError`` is raised.
-        """
-        default = self.default_values[key]
-        dict.__setitem__(self, key, default)
-        if key not in self.defaults:
-            self.defaults.append(key)
-        return default
-
-    
-    def restore_defaults(self):
-        """
-        Recursively restore default values to all members
-        that have them.
-        
-        This method will only work for a ConfigObj that was created
-        with a configspec and has been validated.
-        
-        It doesn't delete or modify entries without default values.
-        """
-        for key in self.default_values:
-            self.restore_default(key)
-            
-        for section in self.sections:
-            self[section].restore_defaults()
-
-
-class ConfigObj(Section):
-    """An object to read, create, and write config files."""
-
-    _keyword = re.compile(r'''^ # line start
-        (\s*)                   # indentation
-        (                       # keyword
-            (?:".*?")|          # double quotes
-            (?:'.*?')|          # single quotes
-            (?:[^'"=].*?)       # no quotes
-        )
-        \s*=\s*                 # divider
-        (.*)                    # value (including list values and comments)
-        $   # line end
-        ''',
-        re.VERBOSE)
-
-    _sectionmarker = re.compile(r'''^
-        (\s*)                     # 1: indentation
-        ((?:\[\s*)+)              # 2: section marker open
-        (                         # 3: section name open
-            (?:"\s*\S.*?\s*")|    # at least one non-space with double quotes
-            (?:'\s*\S.*?\s*')|    # at least one non-space with single quotes
-            (?:[^'"\s].*?)        # at least one non-space unquoted
-        )                         # section name close
-        ((?:\s*\])+)              # 4: section marker close
-        \s*(\#.*)?                # 5: optional comment
-        $''',
-        re.VERBOSE)
-
-    # this regexp pulls list values out as a single string
-    # or single values and comments
-    # FIXME: this regex adds a '' to the end of comma terminated lists
-    #   workaround in ``_handle_value``
-    _valueexp = re.compile(r'''^
-        (?:
-            (?:
-                (
-                    (?:
-                        (?:
-                            (?:".*?")|              # double quotes
-                            (?:'.*?')|              # single quotes
-                            (?:[^'",\#][^,\#]*?)    # unquoted
-                        )
-                        \s*,\s*                     # comma
-                    )*      # match all list items ending in a comma (if any)
-                )
-                (
-                    (?:".*?")|                      # double quotes
-                    (?:'.*?')|                      # single quotes
-                    (?:[^'",\#\s][^,]*?)|           # unquoted
-                    (?:(?<!,))                      # Empty value
-                )?          # last item in a list - or string value
-            )|
-            (,)             # alternatively a single comma - empty list
-        )
-        \s*(\#.*)?          # optional comment
-        $''',
-        re.VERBOSE)
-
-    # use findall to get the members of a list value
-    _listvalueexp = re.compile(r'''
-        (
-            (?:".*?")|          # double quotes
-            (?:'.*?')|          # single quotes
-            (?:[^'",\#]?.*?)       # unquoted
-        )
-        \s*,\s*                 # comma
-        ''',
-        re.VERBOSE)
-
-    # this regexp is used for the value
-    # when lists are switched off
-    _nolistvalue = re.compile(r'''^
-        (
-            (?:".*?")|          # double quotes
-            (?:'.*?')|          # single quotes
-            (?:[^'"\#].*?)|     # unquoted
-            (?:)                # Empty value
-        )
-        \s*(\#.*)?              # optional comment
-        $''',
-        re.VERBOSE)
-
-    # regexes for finding triple quoted values on one line
-    _single_line_single = re.compile(r"^'''(.*?)'''\s*(#.*)?$")
-    _single_line_double = re.compile(r'^"""(.*?)"""\s*(#.*)?$')
-    _multi_line_single = re.compile(r"^(.*?)'''\s*(#.*)?$")
-    _multi_line_double = re.compile(r'^(.*?)"""\s*(#.*)?$')
-
-    _triple_quote = {
-        "'''": (_single_line_single, _multi_line_single),
-        '"""': (_single_line_double, _multi_line_double),
-    }
-
-    # Used by the ``istrue`` Section method
-    _bools = {
-        'yes': True, 'no': False,
-        'on': True, 'off': False,
-        '1': True, '0': False,
-        'true': True, 'false': False,
-        }
-
-
-    def __init__(self, infile=None, options=None, configspec=None, encoding=None,
-                 interpolation=True, raise_errors=False, list_values=True,
-                 create_empty=False, file_error=False, stringify=True,
-                 indent_type=None, default_encoding=None, unrepr=False,
-                 write_empty_values=False, _inspec=False):
-        """
-        Parse a config file or create a config file object.
-        
-        ``ConfigObj(infile=None, configspec=None, encoding=None,
-                    interpolation=True, raise_errors=False, list_values=True,
-                    create_empty=False, file_error=False, stringify=True,
-                    indent_type=None, default_encoding=None, unrepr=False,
-                    write_empty_values=False, _inspec=False)``
-        """
-        self._inspec = _inspec
-        # init the superclass
-        Section.__init__(self, self, 0, self)
-        
-        infile = infile or []
-        
-        _options = {'configspec': configspec,
-                    'encoding': encoding, 'interpolation': interpolation,
-                    'raise_errors': raise_errors, 'list_values': list_values,
-                    'create_empty': create_empty, 'file_error': file_error,
-                    'stringify': stringify, 'indent_type': indent_type,
-                    'default_encoding': default_encoding, 'unrepr': unrepr,
-                    'write_empty_values': write_empty_values}
-
-        if options is None:
-            options = _options
-        else:
-            import warnings
-            warnings.warn('Passing in an options dictionary to ConfigObj() is '
-                          'deprecated. Use **options instead.',
-                          DeprecationWarning, stacklevel=2)
-            
-            # TODO: check the values too.
-            for entry in options:
-                if entry not in OPTION_DEFAULTS:
-                    raise TypeError('Unrecognised option "%s".' % entry)
-            for entry, value in OPTION_DEFAULTS.items():
-                if entry not in options:
-                    options[entry] = value
-                keyword_value = _options[entry]
-                if value != keyword_value:
-                    options[entry] = keyword_value
-        
-        # XXXX this ignores an explicit list_values = True in combination
-        # with _inspec. The user should *never* do that anyway, but still...
-        if _inspec:
-            options['list_values'] = False
-        
-        self._initialise(options)
-        configspec = options['configspec']
-        self._original_configspec = configspec
-        self._load(infile, configspec)
-        
-        
-    def _load(self, infile, configspec):
-        if isinstance(infile, basestring):
-            self.filename = infile
-            if os.path.isfile(infile):
-                h = open(infile, 'rb')
-                infile = h.read() or []
-                h.close()
-            elif self.file_error:
-                # raise an error if the file doesn't exist
-                raise IOError('Config file not found: "%s".' % self.filename)
-            else:
-                # file doesn't already exist
-                if self.create_empty:
-                    # this is a good test that the filename specified
-                    # isn't impossible - like on a non-existent device
-                    h = open(infile, 'w')
-                    h.write('')
-                    h.close()
-                infile = []
-                
-        elif isinstance(infile, (list, tuple)):
-            infile = list(infile)
-            
-        elif isinstance(infile, dict):
-            # initialise self
-            # the Section class handles creating subsections
-            if isinstance(infile, ConfigObj):
-                # get a copy of our ConfigObj
-                def set_section(in_section, this_section):
-                    for entry in in_section.scalars:
-                        this_section[entry] = in_section[entry]
-                    for section in in_section.sections:
-                        this_section[section] = {}
-                        set_section(in_section[section], this_section[section])
-                set_section(infile, self)
-                
-            else:
-                for entry in infile:
-                    self[entry] = infile[entry]
-            del self._errors
-            
-            if configspec is not None:
-                self._handle_configspec(configspec)
-            else:
-                self.configspec = None
-            return
-        
-        elif getattr(infile, 'read', MISSING) is not MISSING:
-            # This supports file like objects
-            infile = infile.read() or []
-            # needs splitting into lines - but needs doing *after* decoding
-            # in case it's not an 8 bit encoding
-        else:
-            raise TypeError('infile must be a filename, file like object, or list of lines.')
-        
-        if infile:
-            # don't do it for the empty ConfigObj
-            infile = self._handle_bom(infile)
-            # infile is now *always* a list
-            #
-            # Set the newlines attribute (first line ending it finds)
-            # and strip trailing '\n' or '\r' from lines
-            for line in infile:
-                if (not line) or (line[-1] not in ('\r', '\n', '\r\n')):
-                    continue
-                for end in ('\r\n', '\n', '\r'):
-                    if line.endswith(end):
-                        self.newlines = end
-                        break
-                break
-
-            infile = [line.rstrip('\r\n') for line in infile]
-            
-        self._parse(infile)
-        # if we had any errors, now is the time to raise them
-        if self._errors:
-            info = "at line %s." % self._errors[0].line_number
-            if len(self._errors) > 1:
-                msg = "Parsing failed with several errors.\nFirst error %s" % info
-                error = ConfigObjError(msg)
-            else:
-                error = self._errors[0]
-            # set the errors attribute; it's a list of tuples:
-            # (error_type, message, line_number)
-            error.errors = self._errors
-            # set the config attribute
-            error.config = self
-            raise error
-        # delete private attributes
-        del self._errors
-        
-        if configspec is None:
-            self.configspec = None
-        else:
-            self._handle_configspec(configspec)
-    
-    
-    def _initialise(self, options=None):
-        if options is None:
-            options = OPTION_DEFAULTS
-            
-        # initialise a few variables
-        self.filename = None
-        self._errors = []
-        self.raise_errors = options['raise_errors']
-        self.interpolation = options['interpolation']
-        self.list_values = options['list_values']
-        self.create_empty = options['create_empty']
-        self.file_error = options['file_error']
-        self.stringify = options['stringify']
-        self.indent_type = options['indent_type']
-        self.encoding = options['encoding']
-        self.default_encoding = options['default_encoding']
-        self.BOM = False
-        self.newlines = None
-        self.write_empty_values = options['write_empty_values']
-        self.unrepr = options['unrepr']
-        
-        self.initial_comment = []
-        self.final_comment = []
-        self.configspec = None
-        
-        if self._inspec:
-            self.list_values = False
-        
-        # Clear section attributes as well
-        Section._initialise(self)
-        
-        
-    def __repr__(self):
-        def _getval(key):
-            try:
-                return self[key]
-            except MissingInterpolationOption:
-                return dict.__getitem__(self, key)
-        return ('ConfigObj({%s})' % 
-                ', '.join([('%s: %s' % (repr(key), repr(_getval(key)))) 
-                for key in (self.scalars + self.sections)]))
-    
-    
-    def _handle_bom(self, infile):
-        """
-        Handle any BOM, and decode if necessary.
-        
-        If an encoding is specified, that *must* be used - but the BOM should
-        still be removed (and the BOM attribute set).
-        
-        (If the encoding is wrongly specified, then a BOM for an alternative
-        encoding won't be discovered or removed.)
-        
-        If an encoding is not specified, UTF8 or UTF16 BOM will be detected and
-        removed. The BOM attribute will be set. UTF16 will be decoded to
-        unicode.
-        
-        NOTE: This method must not be called with an empty ``infile``.
-        
-        Specifying the *wrong* encoding is likely to cause a
-        ``UnicodeDecodeError``.
-        
-        ``infile`` must always be returned as a list of lines, but may be
-        passed in as a single string.
-        """
-        if ((self.encoding is not None) and
-            (self.encoding.lower() not in BOM_LIST)):
-            # No need to check for a BOM
-            # the encoding specified doesn't have one
-            # just decode
-            return self._decode(infile, self.encoding)
-        
-        if isinstance(infile, (list, tuple)):
-            line = infile[0]
-        else:
-            line = infile
-        if self.encoding is not None:
-            # encoding explicitly supplied
-            # And it could have an associated BOM
-            # TODO: if encoding is just UTF16 - we ought to check for both
-            # TODO: big endian and little endian versions.
-            enc = BOM_LIST[self.encoding.lower()]
-            if enc == 'utf_16':
-                # For UTF16 we try big endian and little endian
-                for BOM, (encoding, final_encoding) in BOMS.items():
-                    if not final_encoding:
-                        # skip UTF8
-                        continue
-                    if infile.startswith(BOM):
-                        ### BOM discovered
-                        ##self.BOM = True
-                        # Don't need to remove BOM
-                        return self._decode(infile, encoding)
-                    
-                # If we get this far, will *probably* raise a DecodeError
-                # As it doesn't appear to start with a BOM
-                return self._decode(infile, self.encoding)
-            
-            # Must be UTF8
-            BOM = BOM_SET[enc]
-            if not line.startswith(BOM):
-                return self._decode(infile, self.encoding)
-            
-            newline = line[len(BOM):]
-            
-            # BOM removed
-            if isinstance(infile, (list, tuple)):
-                infile[0] = newline
-            else:
-                infile = newline
-            self.BOM = True
-            return self._decode(infile, self.encoding)
-        
-        # No encoding specified - so we need to check for UTF8/UTF16
-        for BOM, (encoding, final_encoding) in BOMS.items():
-            if not line.startswith(BOM):
-                continue
-            else:
-                # BOM discovered
-                self.encoding = final_encoding
-                if not final_encoding:
-                    self.BOM = True
-                    # UTF8
-                    # remove BOM
-                    newline = line[len(BOM):]
-                    if isinstance(infile, (list, tuple)):
-                        infile[0] = newline
-                    else:
-                        infile = newline
-                    # UTF8 - don't decode
-                    if isinstance(infile, basestring):
-                        return infile.splitlines(True)
-                    else:
-                        return infile
-                # UTF16 - have to decode
-                return self._decode(infile, encoding)
-            
-        # No BOM discovered and no encoding specified, just return
-        if isinstance(infile, basestring):
-            # infile read from a file will be a single string
-            return infile.splitlines(True)
-        return infile
-
-
-    def _a_to_u(self, aString):
-        """Decode ASCII strings to unicode if a self.encoding is specified."""
-        if self.encoding:
-            return aString.decode('ascii')
-        else:
-            return aString
-
-
-    def _decode(self, infile, encoding):
-        """
-        Decode infile to unicode. Using the specified encoding.
-        
-        if is a string, it also needs converting to a list.
-        """
-        if isinstance(infile, basestring):
-            # can't be unicode
-            # NOTE: Could raise a ``UnicodeDecodeError``
-            return infile.decode(encoding).splitlines(True)
-        for i, line in enumerate(infile):
-            if not isinstance(line, unicode):
-                # NOTE: The isinstance test here handles mixed lists of unicode/string
-                # NOTE: But the decode will break on any non-string values
-                # NOTE: Or could raise a ``UnicodeDecodeError``
-                infile[i] = line.decode(encoding)
-        return infile
-
-
-    def _decode_element(self, line):
-        """Decode element to unicode if necessary."""
-        if not self.encoding:
-            return line
-        if isinstance(line, str) and self.default_encoding:
-            return line.decode(self.default_encoding)
-        return line
-
-
-    def _str(self, value):
-        """
-        Used by ``stringify`` within validate, to turn non-string values
-        into strings.
-        """
-        if not isinstance(value, basestring):
-            return str(value)
-        else:
-            return value
-
-
-    def _parse(self, infile):
-        """Actually parse the config file."""
-        temp_list_values = self.list_values
-        if self.unrepr:
-            self.list_values = False
-            
-        comment_list = []
-        done_start = False
-        this_section = self
-        maxline = len(infile) - 1
-        cur_index = -1
-        reset_comment = False
-        
-        while cur_index < maxline:
-            if reset_comment:
-                comment_list = []
-            cur_index += 1
-            line = infile[cur_index]
-            sline = line.strip()
-            # do we have anything on the line ?
-            if not sline or sline.startswith('#'):
-                reset_comment = False
-                comment_list.append(line)
-                continue
-            
-            if not done_start:
-                # preserve initial comment
-                self.initial_comment = comment_list
-                comment_list = []
-                done_start = True
-                
-            reset_comment = True
-            # first we check if it's a section marker
-            mat = self._sectionmarker.match(line)
-            if mat is not None:
-                # is a section line
-                (indent, sect_open, sect_name, sect_close, comment) = mat.groups()
-                if indent and (self.indent_type is None):
-                    self.indent_type = indent
-                cur_depth = sect_open.count('[')
-                if cur_depth != sect_close.count(']'):
-                    self._handle_error("Cannot compute the section depth at line %s.",
-                                       NestingError, infile, cur_index)
-                    continue
-                
-                if cur_depth < this_section.depth:
-                    # the new section is dropping back to a previous level
-                    try:
-                        parent = self._match_depth(this_section,
-                                                   cur_depth).parent
-                    except SyntaxError:
-                        self._handle_error("Cannot compute nesting level at line %s.",
-                                           NestingError, infile, cur_index)
-                        continue
-                elif cur_depth == this_section.depth:
-                    # the new section is a sibling of the current section
-                    parent = this_section.parent
-                elif cur_depth == this_section.depth + 1:
-                    # the new section is a child the current section
-                    parent = this_section
-                else:
-                    self._handle_error("Section too nested at line %s.",
-                                       NestingError, infile, cur_index)
-                    
-                sect_name = self._unquote(sect_name)
-                if sect_name in parent:
-                    self._handle_error('Duplicate section name at line %s.',
-                                       DuplicateError, infile, cur_index)
-                    continue
-                
-                # create the new section
-                this_section = Section(
-                    parent,
-                    cur_depth,
-                    self,
-                    name=sect_name)
-                parent[sect_name] = this_section
-                parent.inline_comments[sect_name] = comment
-                parent.comments[sect_name] = comment_list
-                continue
-            #
-            # it's not a section marker,
-            # so it should be a valid ``key = value`` line
-            mat = self._keyword.match(line)
-            if mat is None:
-                # it neither matched as a keyword
-                # or a section marker
-                self._handle_error(
-                    'Invalid line at line "%s".',
-                    ParseError, infile, cur_index)
-            else:
-                # is a keyword value
-                # value will include any inline comment
-                (indent, key, value) = mat.groups()
-                if indent and (self.indent_type is None):
-                    self.indent_type = indent
-                # check for a multiline value
-                if value[:3] in ['"""', "'''"]:
-                    try:
-                        value, comment, cur_index = self._multiline(
-                            value, infile, cur_index, maxline)
-                    except SyntaxError:
-                        self._handle_error(
-                            'Parse error in value at line %s.',
-                            ParseError, infile, cur_index)
-                        continue
-                    else:
-                        if self.unrepr:
-                            comment = ''
-                            try:
-                                value = unrepr(value)
-                            except Exception, e:
-                                if type(e) == UnknownType:
-                                    msg = 'Unknown name or type in value at line %s.'
-                                else:
-                                    msg = 'Parse error in value at line %s.'
-                                self._handle_error(msg, UnreprError, infile,
-                                    cur_index)
-                                continue
-                else:
-                    if self.unrepr:
-                        comment = ''
-                        try:
-                            value = unrepr(value)
-                        except Exception, e:
-                            if isinstance(e, UnknownType):
-                                msg = 'Unknown name or type in value at line %s.'
-                            else:
-                                msg = 'Parse error in value at line %s.'
-                            self._handle_error(msg, UnreprError, infile,
-                                cur_index)
-                            continue
-                    else:
-                        # extract comment and lists
-                        try:
-                            (value, comment) = self._handle_value(value)
-                        except SyntaxError:
-                            self._handle_error(
-                                'Parse error in value at line %s.',
-                                ParseError, infile, cur_index)
-                            continue
-                #
-                key = self._unquote(key)
-                if key in this_section:
-                    self._handle_error(
-                        'Duplicate keyword name at line %s.',
-                        DuplicateError, infile, cur_index)
-                    continue
-                # add the key.
-                # we set unrepr because if we have got this far we will never
-                # be creating a new section
-                this_section.__setitem__(key, value, unrepr=True)
-                this_section.inline_comments[key] = comment
-                this_section.comments[key] = comment_list
-                continue
-        #
-        if self.indent_type is None:
-            # no indentation used, set the type accordingly
-            self.indent_type = ''
-
-        # preserve the final comment
-        if not self and not self.initial_comment:
-            self.initial_comment = comment_list
-        elif not reset_comment:
-            self.final_comment = comment_list
-        self.list_values = temp_list_values
-
-
-    def _match_depth(self, sect, depth):
-        """
-        Given a section and a depth level, walk back through the sections
-        parents to see if the depth level matches a previous section.
-        
-        Return a reference to the right section,
-        or raise a SyntaxError.
-        """
-        while depth < sect.depth:
-            if sect is sect.parent:
-                # we've reached the top level already
-                raise SyntaxError()
-            sect = sect.parent
-        if sect.depth == depth:
-            return sect
-        # shouldn't get here
-        raise SyntaxError()
-
-
-    def _handle_error(self, text, ErrorClass, infile, cur_index):
-        """
-        Handle an error according to the error settings.
-        
-        Either raise the error or store it.
-        The error will have occured at ``cur_index``
-        """
-        line = infile[cur_index]
-        cur_index += 1
-        message = text % cur_index
-        error = ErrorClass(message, cur_index, line)
-        if self.raise_errors:
-            # raise the error - parsing stops here
-            raise error
-        # store the error
-        # reraise when parsing has finished
-        self._errors.append(error)
-
-
-    def _unquote(self, value):
-        """Return an unquoted version of a value"""
-        if not value:
-            # should only happen during parsing of lists
-            raise SyntaxError
-        if (value[0] == value[-1]) and (value[0] in ('"', "'")):
-            value = value[1:-1]
-        return value
-
-
-    def _quote(self, value, multiline=True):
-        """
-        Return a safely quoted version of a value.
-        
-        Raise a ConfigObjError if the value cannot be safely quoted.
-        If multiline is ``True`` (default) then use triple quotes
-        if necessary.
-        
-        * Don't quote values that don't need it.
-        * Recursively quote members of a list and return a comma joined list.
-        * Multiline is ``False`` for lists.
-        * Obey list syntax for empty and single member lists.
-        
-        If ``list_values=False`` then the value is only quoted if it contains
-        a ``\\n`` (is multiline) or '#'.
-        
-        If ``write_empty_values`` is set, and the value is an empty string, it
-        won't be quoted.
-        """
-        if multiline and self.write_empty_values and value == '':
-            # Only if multiline is set, so that it is used for values not
-            # keys, and not values that are part of a list
-            return ''
-        
-        if multiline and isinstance(value, (list, tuple)):
-            if not value:
-                return ','
-            elif len(value) == 1:
-                return self._quote(value[0], multiline=False) + ','
-            return ', '.join([self._quote(val, multiline=False)
-                for val in value])
-        if not isinstance(value, basestring):
-            if self.stringify:
-                value = str(value)
-            else:
-                raise TypeError('Value "%s" is not a string.' % value)
-
-        if not value:
-            return '""'
-        
-        no_lists_no_quotes = not self.list_values and '\n' not in value and '#' not in value
-        need_triple = multiline and ((("'" in value) and ('"' in value)) or ('\n' in value ))
-        hash_triple_quote = multiline and not need_triple and ("'" in value) and ('"' in value) and ('#' in value)
-        check_for_single = (no_lists_no_quotes or not need_triple) and not hash_triple_quote
-        
-        if check_for_single:
-            if not self.list_values:
-                # we don't quote if ``list_values=False``
-                quot = noquot
-            # for normal values either single or double quotes will do
-            elif '\n' in value:
-                # will only happen if multiline is off - e.g. '\n' in key
-                raise ConfigObjError('Value "%s" cannot be safely quoted.' % value)
-            elif ((value[0] not in wspace_plus) and
-                    (value[-1] not in wspace_plus) and
-                    (',' not in value)):
-                quot = noquot
-            else:
-                quot = self._get_single_quote(value)
-        else:
-            # if value has '\n' or "'" *and* '"', it will need triple quotes
-            quot = self._get_triple_quote(value)
-        
-        if quot == noquot and '#' in value and self.list_values:
-            quot = self._get_single_quote(value)
-                
-        return quot % value
-    
-    
-    def _get_single_quote(self, value):
-        if ("'" in value) and ('"' in value):
-            raise ConfigObjError('Value "%s" cannot be safely quoted.' % value)
-        elif '"' in value:
-            quot = squot
-        else:
-            quot = dquot
-        return quot
-    
-    
-    def _get_triple_quote(self, value):
-        if (value.find('"""') != -1) and (value.find("'''") != -1):
-            raise ConfigObjError('Value "%s" cannot be safely quoted.' % value)
-        if value.find('"""') == -1:
-            quot = tdquot
-        else:
-            quot = tsquot 
-        return quot
-
-
-    def _handle_value(self, value):
-        """
-        Given a value string, unquote, remove comment,
-        handle lists. (including empty and single member lists)
-        """
-        if self._inspec:
-            # Parsing a configspec so don't handle comments
-            return (value, '')
-        # do we look for lists in values ?
-        if not self.list_values:
-            mat = self._nolistvalue.match(value)
-            if mat is None:
-                raise SyntaxError()
-            # NOTE: we don't unquote here
-            return mat.groups()
-        #
-        mat = self._valueexp.match(value)
-        if mat is None:
-            # the value is badly constructed, probably badly quoted,
-            # or an invalid list
-            raise SyntaxError()
-        (list_values, single, empty_list, comment) = mat.groups()
-        if (list_values == '') and (single is None):
-            # change this if you want to accept empty values
-            raise SyntaxError()
-        # NOTE: note there is no error handling from here if the regex
-        # is wrong: then incorrect values will slip through
-        if empty_list is not None:
-            # the single comma - meaning an empty list
-            return ([], comment)
-        if single is not None:
-            # handle empty values
-            if list_values and not single:
-                # FIXME: the '' is a workaround because our regex now matches
-                #   '' at the end of a list if it has a trailing comma
-                single = None
-            else:
-                single = single or '""'
-                single = self._unquote(single)
-        if list_values == '':
-            # not a list value
-            return (single, comment)
-        the_list = self._listvalueexp.findall(list_values)
-        the_list = [self._unquote(val) for val in the_list]
-        if single is not None:
-            the_list += [single]
-        return (the_list, comment)
-
-
-    def _multiline(self, value, infile, cur_index, maxline):
-        """Extract the value, where we are in a multiline situation."""
-        quot = value[:3]
-        newvalue = value[3:]
-        single_line = self._triple_quote[quot][0]
-        multi_line = self._triple_quote[quot][1]
-        mat = single_line.match(value)
-        if mat is not None:
-            retval = list(mat.groups())
-            retval.append(cur_index)
-            return retval
-        elif newvalue.find(quot) != -1:
-            # somehow the triple quote is missing
-            raise SyntaxError()
-        #
-        while cur_index < maxline:
-            cur_index += 1
-            newvalue += '\n'
-            line = infile[cur_index]
-            if line.find(quot) == -1:
-                newvalue += line
-            else:
-                # end of multiline, process it
-                break
-        else:
-            # we've got to the end of the config, oops...
-            raise SyntaxError()
-        mat = multi_line.match(line)
-        if mat is None:
-            # a badly formed line
-            raise SyntaxError()
-        (value, comment) = mat.groups()
-        return (newvalue + value, comment, cur_index)
-
-
-    def _handle_configspec(self, configspec):
-        """Parse the configspec."""
-        # FIXME: Should we check that the configspec was created with the 
-        #        correct settings ? (i.e. ``list_values=False``)
-        if not isinstance(configspec, ConfigObj):
-            try:
-                configspec = ConfigObj(configspec,
-                                       raise_errors=True,
-                                       file_error=True,
-                                       _inspec=True)
-            except ConfigObjError, e:
-                # FIXME: Should these errors have a reference
-                #        to the already parsed ConfigObj ?
-                raise ConfigspecError('Parsing configspec failed: %s' % e)
-            except IOError, e:
-                raise IOError('Reading configspec failed: %s' % e)
-        
-        self.configspec = configspec
-            
-
-        
-    def _set_configspec(self, section, copy):
-        """
-        Called by validate. Handles setting the configspec on subsections
-        including sections to be validated by __many__
-        """
-        configspec = section.configspec
-        many = configspec.get('__many__')
-        if isinstance(many, dict):
-            for entry in section.sections:
-                if entry not in configspec:
-                    section[entry].configspec = many
-                    
-        for entry in configspec.sections:
-            if entry == '__many__':
-                continue
-            if entry not in section:
-                section[entry] = {}
-                section[entry]._created = True
-                if copy:
-                    # copy comments
-                    section.comments[entry] = configspec.comments.get(entry, [])
-                    section.inline_comments[entry] = configspec.inline_comments.get(entry, '')
-                
-            # Could be a scalar when we expect a section
-            if isinstance(section[entry], Section):
-                section[entry].configspec = configspec[entry]
-                        
-
-    def _write_line(self, indent_string, entry, this_entry, comment):
-        """Write an individual line, for the write method"""
-        # NOTE: the calls to self._quote here handles non-StringType values.
-        if not self.unrepr:
-            val = self._decode_element(self._quote(this_entry))
-        else:
-            val = repr(this_entry)
-        return '%s%s%s%s%s' % (indent_string,
-                               self._decode_element(self._quote(entry, multiline=False)),
-                               self._a_to_u(' = '),
-                               val,
-                               self._decode_element(comment))
-
-
-    def _write_marker(self, indent_string, depth, entry, comment):
-        """Write a section marker line"""
-        return '%s%s%s%s%s' % (indent_string,
-                               self._a_to_u('[' * depth),
-                               self._quote(self._decode_element(entry), multiline=False),
-                               self._a_to_u(']' * depth),
-                               self._decode_element(comment))
-
-
-    def _handle_comment(self, comment):
-        """Deal with a comment."""
-        if not comment:
-            return ''
-        start = self.indent_type
-        if not comment.startswith('#'):
-            start += self._a_to_u(' # ')
-        return (start + comment)
-
-
-    # Public methods
-
-    def write(self, outfile=None, section=None):
-        """
-        Write the current ConfigObj as a file
-        
-        tekNico: FIXME: use StringIO instead of real files
-        
-        >>> filename = a.filename
-        >>> a.filename = 'test.ini'
-        >>> a.write()
-        >>> a.filename = filename
-        >>> a == ConfigObj('test.ini', raise_errors=True)
-        1
-        >>> import os
-        >>> os.remove('test.ini')
-        """
-        if self.indent_type is None:
-            # this can be true if initialised from a dictionary
-            self.indent_type = DEFAULT_INDENT_TYPE
-            
-        out = []
-        cs = self._a_to_u('#')
-        csp = self._a_to_u('# ')
-        if section is None:
-            int_val = self.interpolation
-            self.interpolation = False
-            section = self
-            for line in self.initial_comment:
-                line = self._decode_element(line)
-                stripped_line = line.strip()
-                if stripped_line and not stripped_line.startswith(cs):
-                    line = csp + line
-                out.append(line)
-                
-        indent_string = self.indent_type * section.depth
-        for entry in (section.scalars + section.sections):
-            if entry in section.defaults:
-                # don't write out default values
-                continue
-            for comment_line in section.comments[entry]:
-                comment_line = self._decode_element(comment_line.lstrip())
-                if comment_line and not comment_line.startswith(cs):
-                    comment_line = csp + comment_line
-                out.append(indent_string + comment_line)
-            this_entry = section[entry]
-            comment = self._handle_comment(section.inline_comments[entry])
-            
-            if isinstance(this_entry, dict):
-                # a section
-                out.append(self._write_marker(
-                    indent_string,
-                    this_entry.depth,
-                    entry,
-                    comment))
-                out.extend(self.write(section=this_entry))
-            else:
-                out.append(self._write_line(
-                    indent_string,
-                    entry,
-                    this_entry,
-                    comment))
-                
-        if section is self:
-            for line in self.final_comment:
-                line = self._decode_element(line)
-                stripped_line = line.strip()
-                if stripped_line and not stripped_line.startswith(cs):
-                    line = csp + line
-                out.append(line)
-            self.interpolation = int_val
-            
-        if section is not self:
-            return out
-        
-        if (self.filename is None) and (outfile is None):
-            # output a list of lines
-            # might need to encode
-            # NOTE: This will *screw* UTF16, each line will start with the BOM
-            if self.encoding:
-                out = [l.encode(self.encoding) for l in out]
-            if (self.BOM and ((self.encoding is None) or
-                (BOM_LIST.get(self.encoding.lower()) == 'utf_8'))):
-                # Add the UTF8 BOM
-                if not out:
-                    out.append('')
-                out[0] = BOM_UTF8 + out[0]
-            return out
-        
-        # Turn the list to a string, joined with correct newlines
-        newline = self.newlines or os.linesep
-        if (getattr(outfile, 'mode', None) is not None and outfile.mode == 'w'
-            and sys.platform == 'win32' and newline == '\r\n'):
-            # Windows specific hack to avoid writing '\r\r\n'
-            newline = '\n'
-        output = self._a_to_u(newline).join(out)
-        if self.encoding:
-            output = output.encode(self.encoding)
-        if self.BOM and ((self.encoding is None) or match_utf8(self.encoding)):
-            # Add the UTF8 BOM
-            output = BOM_UTF8 + output
-            
-        if not output.endswith(newline):
-            output += newline
-        if outfile is not None:
-            outfile.write(output)
-        else:
-            h = open(self.filename, 'wb')
-            h.write(output)
-            h.close()
-
-
-    def validate(self, validator, preserve_errors=False, copy=False,
-                 section=None):
-        """
-        Test the ConfigObj against a configspec.
-        
-        It uses the ``validator`` object from *validate.py*.
-        
-        To run ``validate`` on the current ConfigObj, call: ::
-        
-            test = config.validate(validator)
-        
-        (Normally having previously passed in the configspec when the ConfigObj
-        was created - you can dynamically assign a dictionary of checks to the
-        ``configspec`` attribute of a section though).
-        
-        It returns ``True`` if everything passes, or a dictionary of
-        pass/fails (True/False). If every member of a subsection passes, it
-        will just have the value ``True``. (It also returns ``False`` if all
-        members fail).
-        
-        In addition, it converts the values from strings to their native
-        types if their checks pass (and ``stringify`` is set).
-        
-        If ``preserve_errors`` is ``True`` (``False`` is default) then instead
-        of a marking a fail with a ``False``, it will preserve the actual
-        exception object. This can contain info about the reason for failure.
-        For example the ``VdtValueTooSmallError`` indicates that the value
-        supplied was too small. If a value (or section) is missing it will
-        still be marked as ``False``.
-        
-        You must have the validate module to use ``preserve_errors=True``.
-        
-        You can then use the ``flatten_errors`` function to turn your nested
-        results dictionary into a flattened list of failures - useful for
-        displaying meaningful error messages.
-        """
-        if section is None:
-            if self.configspec is None:
-                raise ValueError('No configspec supplied.')
-            if preserve_errors:
-                # We do this once to remove a top level dependency on the validate module
-                # Which makes importing configobj faster
-                from validate import VdtMissingValue
-                self._vdtMissingValue = VdtMissingValue
-                
-            section = self
-
-            if copy:
-                section.initial_comment = section.configspec.initial_comment
-                section.final_comment = section.configspec.final_comment
-                section.encoding = section.configspec.encoding
-                section.BOM = section.configspec.BOM
-                section.newlines = section.configspec.newlines
-                section.indent_type = section.configspec.indent_type
-            
-        #
-        # section.default_values.clear() #??
-        configspec = section.configspec
-        self._set_configspec(section, copy)
-
-        
-        def validate_entry(entry, spec, val, missing, ret_true, ret_false):
-            section.default_values.pop(entry, None)
-                
-            try:
-                section.default_values[entry] = validator.get_default_value(configspec[entry])
-            except (KeyError, AttributeError, validator.baseErrorClass):
-                # No default, bad default or validator has no 'get_default_value'
-                # (e.g. SimpleVal)
-                pass
-            
-            try:
-                check = validator.check(spec,
-                                        val,
-                                        missing=missing
-                                        )
-            except validator.baseErrorClass, e:
-                if not preserve_errors or isinstance(e, self._vdtMissingValue):
-                    out[entry] = False
-                else:
-                    # preserve the error
-                    out[entry] = e
-                    ret_false = False
-                ret_true = False
-            else:
-                ret_false = False
-                out[entry] = True
-                if self.stringify or missing:
-                    # if we are doing type conversion
-                    # or the value is a supplied default
-                    if not self.stringify:
-                        if isinstance(check, (list, tuple)):
-                            # preserve lists
-                            check = [self._str(item) for item in check]
-                        elif missing and check is None:
-                            # convert the None from a default to a ''
-                            check = ''
-                        else:
-                            check = self._str(check)
-                    if (check != val) or missing:
-                        section[entry] = check
-                if not copy and missing and entry not in section.defaults:
-                    section.defaults.append(entry)
-            return ret_true, ret_false
-        
-        #
-        out = {}
-        ret_true = True
-        ret_false = True
-        
-        unvalidated = [k for k in section.scalars if k not in configspec]
-        incorrect_sections = [k for k in configspec.sections if k in section.scalars]        
-        incorrect_scalars = [k for k in configspec.scalars if k in section.sections]
-        
-        for entry in configspec.scalars:
-            if entry in ('__many__', '___many___'):
-                # reserved names
-                continue
-            if (not entry in section.scalars) or (entry in section.defaults):
-                # missing entries
-                # or entries from defaults
-                missing = True
-                val = None
-                if copy and entry not in section.scalars:
-                    # copy comments
-                    section.comments[entry] = (
-                        configspec.comments.get(entry, []))
-                    section.inline_comments[entry] = (
-                        configspec.inline_comments.get(entry, ''))
-                #
-            else:
-                missing = False
-                val = section[entry]
-            
-            ret_true, ret_false = validate_entry(entry, configspec[entry], val, 
-                                                 missing, ret_true, ret_false)
-        
-        many = None
-        if '__many__' in configspec.scalars:
-            many = configspec['__many__']
-        elif '___many___' in configspec.scalars:
-            many = configspec['___many___']
-        
-        if many is not None:
-            for entry in unvalidated:
-                val = section[entry]
-                ret_true, ret_false = validate_entry(entry, many, val, False,
-                                                     ret_true, ret_false)
-            unvalidated = []
-
-        for entry in incorrect_scalars:
-            ret_true = False
-            if not preserve_errors:
-                out[entry] = False
-            else:
-                ret_false = False
-                msg = 'Value %r was provided as a section' % entry
-                out[entry] = validator.baseErrorClass(msg)
-        for entry in incorrect_sections:
-            ret_true = False
-            if not preserve_errors:
-                out[entry] = False
-            else:
-                ret_false = False
-                msg = 'Section %r was provided as a single value' % entry
-                out[entry] = validator.baseErrorClass(msg)
-                
-        # Missing sections will have been created as empty ones when the
-        # configspec was read.
-        for entry in section.sections:
-            # FIXME: this means DEFAULT is not copied in copy mode
-            if section is self and entry == 'DEFAULT':
-                continue
-            if section[entry].configspec is None:
-                unvalidated.append(entry)
-                continue
-            if copy:
-                section.comments[entry] = configspec.comments.get(entry, [])
-                section.inline_comments[entry] = configspec.inline_comments.get(entry, '')
-            check = self.validate(validator, preserve_errors=preserve_errors, copy=copy, section=section[entry])
-            out[entry] = check
-            if check == False:
-                ret_true = False
-            elif check == True:
-                ret_false = False
-            else:
-                ret_true = False
-        
-        section.extra_values = unvalidated
-        if preserve_errors and not section._created:
-            # If the section wasn't created (i.e. it wasn't missing)
-            # then we can't return False, we need to preserve errors
-            ret_false = False
-        #
-        if ret_false and preserve_errors and out:
-            # If we are preserving errors, but all
-            # the failures are from missing sections / values
-            # then we can return False. Otherwise there is a
-            # real failure that we need to preserve.
-            ret_false = not any(out.values())
-        if ret_true:
-            return True
-        elif ret_false:
-            return False
-        return out
-
-
-    def reset(self):
-        """Clear ConfigObj instance and restore to 'freshly created' state."""
-        self.clear()
-        self._initialise()
-        # FIXME: Should be done by '_initialise', but ConfigObj constructor (and reload)
-        #        requires an empty dictionary
-        self.configspec = None
-        # Just to be sure ;-)
-        self._original_configspec = None
-        
-        
-    def reload(self):
-        """
-        Reload a ConfigObj from file.
-        
-        This method raises a ``ReloadError`` if the ConfigObj doesn't have
-        a filename attribute pointing to a file.
-        """
-        if not isinstance(self.filename, basestring):
-            raise ReloadError()
-
-        filename = self.filename
-        current_options = {}
-        for entry in OPTION_DEFAULTS:
-            if entry == 'configspec':
-                continue
-            current_options[entry] = getattr(self, entry)
-            
-        configspec = self._original_configspec
-        current_options['configspec'] = configspec
-            
-        self.clear()
-        self._initialise(current_options)
-        self._load(filename, configspec)
-        
-
-
-class SimpleVal(object):
-    """
-    A simple validator.
-    Can be used to check that all members expected are present.
-    
-    To use it, provide a configspec with all your members in (the value given
-    will be ignored). Pass an instance of ``SimpleVal`` to the ``validate``
-    method of your ``ConfigObj``. ``validate`` will return ``True`` if all
-    members are present, or a dictionary with True/False meaning
-    present/missing. (Whole missing sections will be replaced with ``False``)
-    """
-    
-    def __init__(self):
-        self.baseErrorClass = ConfigObjError
-    
-    def check(self, check, member, missing=False):
-        """A dummy check method, always returns the value unchanged."""
-        if missing:
-            raise self.baseErrorClass()
-        return member
-
-
-def flatten_errors(cfg, res, levels=None, results=None):
-    """
-    An example function that will turn a nested dictionary of results
-    (as returned by ``ConfigObj.validate``) into a flat list.
-    
-    ``cfg`` is the ConfigObj instance being checked, ``res`` is the results
-    dictionary returned by ``validate``.
-    
-    (This is a recursive function, so you shouldn't use the ``levels`` or
-    ``results`` arguments - they are used by the function.)
-    
-    Returns a list of keys that failed. Each member of the list is a tuple::
-    
-        ([list of sections...], key, result)
-    
-    If ``validate`` was called with ``preserve_errors=False`` (the default)
-    then ``result`` will always be ``False``.
-
-    *list of sections* is a flattened list of sections that the key was found
-    in.
-    
-    If the section was missing (or a section was expected and a scalar provided
-    - or vice-versa) then key will be ``None``.
-    
-    If the value (or section) was missing then ``result`` will be ``False``.
-    
-    If ``validate`` was called with ``preserve_errors=True`` and a value
-    was present, but failed the check, then ``result`` will be the exception
-    object returned. You can use this as a string that describes the failure.
-    
-    For example *The value "3" is of the wrong type*.
-    """
-    if levels is None:
-        # first time called
-        levels = []
-        results = []
-    if res == True:
-        return results
-    if res == False or isinstance(res, Exception):
-        results.append((levels[:], None, res))
-        if levels:
-            levels.pop()
-        return results
-    for (key, val) in res.items():
-        if val == True:
-            continue
-        if isinstance(cfg.get(key), dict):
-            # Go down one level
-            levels.append(key)
-            flatten_errors(cfg[key], val, levels, results)
-            continue
-        results.append((levels[:], key, val))
-    #
-    # Go up one level
-    if levels:
-        levels.pop()
-    #
-    return results
-
-
-def get_extra_values(conf, _prepend=()):
-    """
-    Find all the values and sections not in the configspec from a validated
-    ConfigObj.
-    
-    ``get_extra_values`` returns a list of tuples where each tuple represents
-    either an extra section, or an extra value.
-    
-    The tuples contain two values, a tuple representing the section the value 
-    is in and the name of the extra values. For extra values in the top level
-    section the first member will be an empty tuple. For values in the 'foo'
-    section the first member will be ``('foo',)``. For members in the 'bar'
-    subsection of the 'foo' section the first member will be ``('foo', 'bar')``.
-    
-    NOTE: If you call ``get_extra_values`` on a ConfigObj instance that hasn't
-    been validated it will return an empty list.
-    """
-    out = []
-    
-    out.extend([(_prepend, name) for name in conf.extra_values])
-    for name in conf.sections:
-        if name not in conf.extra_values:
-            out.extend(get_extra_values(conf[name], _prepend + (name,)))
-    return out
-
-
-"""*A programming language is a medium of expression.* - Paul Graham"""
diff --git a/python/cdec/sa/__init__.py b/python/cdec/sa/__init__.py
deleted file mode 100644
index 8645e837..00000000
--- a/python/cdec/sa/__init__.py
+++ /dev/null
@@ -1,4 +0,0 @@
-from _sa import sym_fromstring,\
-        SuffixArray, DataArray, LCP, Precomputation, Alignment, BiLex,\
-        HieroCachingRuleFactory, Sampler
-from extractor import GrammarExtractor
diff --git a/python/cdec/sa/compile.py b/python/cdec/sa/compile.py
deleted file mode 100644
index 30e605a6..00000000
--- a/python/cdec/sa/compile.py
+++ /dev/null
@@ -1,94 +0,0 @@
-#!/usr/bin/env python
-import argparse
-import os
-import logging
-import cdec.configobj
-import cdec.sa
-
-MAX_PHRASE_LENGTH = 4
-def precompute(f_sa, max_len, max_nt, max_size, min_gap, rank1, rank2):
-    lcp = cdec.sa.LCP(f_sa)
-    stats = sorted(lcp.compute_stats(MAX_PHRASE_LENGTH), reverse=True)
-    precomp = cdec.sa.Precomputation(from_stats=stats,
-            fsarray=f_sa,
-            precompute_rank=rank1,
-            precompute_secondary_rank=rank2,
-            max_length=max_len,
-            max_nonterminals=max_nt,
-            train_max_initial_size=max_size,
-            train_min_gap_size=min_gap)
-    return precomp
-
-def main():
-    logging.basicConfig(level=logging.INFO)
-    logger = logging.getLogger('cdec.sa.compile')
-    parser = argparse.ArgumentParser(description='Compile a corpus into a suffix array.')
-    parser.add_argument('--maxnt', '-n', type=int, default=2,
-                        help='Maximum number of non-terminal symbols')
-    parser.add_argument('--maxlen', '-l', type=int, default=5,
-                        help='Maximum number of terminals')
-    parser.add_argument('--maxsize', '-s', type=int, default=15,
-                        help='Maximum rule span')
-    parser.add_argument('--mingap', '-g', type=int, default=1,
-                        help='Minimum gap size')
-    parser.add_argument('--rank1', '-r1', type=int, default=100,
-                        help='Number of pre-computed frequent patterns')
-    parser.add_argument('--rank2', '-r2', type=int, default=10,
-                        help='Number of pre-computed super-frequent patterns)')
-    parser.add_argument('-c', '--config', default='/dev/stdout',
-                        help='Output configuration')
-    parser.add_argument('-o', '--output', required=True,
-                        help='Output path')
-    parser.add_argument('-f', '--source', required=True,
-                        help='Source language corpus')
-    parser.add_argument('-e', '--target', required=True,
-                        help='Target language corpus')
-    parser.add_argument('-a', '--alignment', required=True,
-                        help='Bitext word alignment')
-    args = parser.parse_args()
-
-    param_names = ("max_len", "max_nt", "max_size", "min_gap", "rank1", "rank2")
-    params = (args.maxlen, args.maxnt, args.maxsize, args.mingap, args.rank1, args.rank2)
-
-    if not os.path.exists(args.output):
-        os.mkdir(args.output)
-
-    f_sa_bin = os.path.join(args.output, 'f.sa.bin')
-    e_bin = os.path.join(args.output, 'e.bin')
-    precomp_file = 'precomp.{0}.{1}.{2}.{3}.{4}.{5}.bin'.format(*params)
-    precomp_bin = os.path.join(args.output, precomp_file)
-    a_bin = os.path.join(args.output, 'a.bin')
-    lex_bin = os.path.join(args.output, 'lex.bin')
-
-    logger.info('Compiling source suffix array')
-    f_sa = cdec.sa.SuffixArray(from_text=args.source)
-    f_sa.write_binary(f_sa_bin)
-
-    logger.info('Compiling target data array')
-    e = cdec.sa.DataArray(from_text=args.target)
-    e.write_binary(e_bin)
-
-    logger.info('Precomputing frequent phrases')
-    precompute(f_sa, *params).write_binary(precomp_bin)
-
-    logger.info('Compiling alignment')
-    a = cdec.sa.Alignment(from_text=args.alignment)
-    a.write_binary(a_bin)
-
-    logger.info('Compiling bilexical dictionary')
-    lex = cdec.sa.BiLex(from_data=True, alignment=a, earray=e, fsarray=f_sa)
-    lex.write_binary(lex_bin)
-    
-    # Write configuration
-    config = cdec.configobj.ConfigObj(args.config, unrepr=True)
-    config['f_sa_file'] = f_sa_bin
-    config['e_file'] = e_bin
-    config['a_file'] = a_bin
-    config['lex_file'] = lex_bin
-    config['precompute_file'] = precomp_bin
-    for name, value in zip(param_names, params):
-        config[name] = value
-    config.write()
-
-if __name__ == '__main__':
-    main()
diff --git a/python/cdec/sa/extract.py b/python/cdec/sa/extract.py
deleted file mode 100644
index 918aa3bb..00000000
--- a/python/cdec/sa/extract.py
+++ /dev/null
@@ -1,31 +0,0 @@
-#!/usr/bin/env python
-import sys
-import os
-import argparse
-import logging
-import cdec.sa
-
-def main():
-    logging.basicConfig(level=logging.INFO)
-    parser = argparse.ArgumentParser(description='Extract grammars from a compiled corpus.')
-    parser.add_argument('-c', '--config', required=True,
-                        help='Extractor configuration')
-    parser.add_argument('-g', '--grammars', required=True,
-                        help='Grammar output path')
-    args = parser.parse_args()
-
-    if not os.path.exists(args.grammars):
-        os.mkdir(args.grammars)
-
-    extractor = cdec.sa.GrammarExtractor(args.config)
-    for i, sentence in enumerate(sys.stdin):
-        sentence = sentence[:-1]
-        grammar_file = os.path.join(args.grammars, 'grammar.{0}'.format(i))
-        with open(grammar_file, 'w') as output:
-            for rule in extractor.grammar(sentence):
-                output.write(str(rule)+'\n')
-        grammar_file = os.path.abspath(grammar_file)
-        print('<seg grammar="{0}">{1}</seg>'.format(grammar_file, sentence))
-
-if __name__ == '__main__':
-    main()
diff --git a/python/cdec/sa/extractor.py b/python/cdec/sa/extractor.py
deleted file mode 100644
index bb912e16..00000000
--- a/python/cdec/sa/extractor.py
+++ /dev/null
@@ -1,78 +0,0 @@
-from itertools import chain
-import os
-import cdec.configobj
-from cdec.sa.features import EgivenFCoherent, SampleCountF, CountEF,\
-        MaxLexEgivenF, MaxLexFgivenE, IsSingletonF, IsSingletonFE
-import cdec.sa
-
-# maximum span of a grammar rule in TEST DATA
-MAX_INITIAL_SIZE = 15
-
-class GrammarExtractor:
-    def __init__(self, config):
-        if isinstance(config, str) or isinstance(config, unicode):
-            if not os.path.exists(config):
-                raise IOError('cannot read configuration from {0}'.format(config))
-            config = cdec.configobj.ConfigObj(config, unrepr=True)
-        alignment = cdec.sa.Alignment(from_binary=config['a_file'])
-        self.factory = cdec.sa.HieroCachingRuleFactory(
-                # compiled alignment object (REQUIRED)
-                alignment,
-                # name of generic nonterminal used by Hiero
-                category="[X]",
-                # maximum number of contiguous chunks of terminal symbols in RHS of a rule
-                max_chunks=config['max_nt']+1,
-                # maximum span of a grammar rule in TEST DATA
-                max_initial_size=MAX_INITIAL_SIZE,
-                # maximum number of symbols (both T and NT) allowed in a rule
-                max_length=config['max_len'],
-                # maximum number of nonterminals allowed in a rule (set >2 at your own risk)
-                max_nonterminals=config['max_nt'],
-                # maximum number of contiguous chunks of terminal symbols
-                # in target-side RHS of a rule.
-                max_target_chunks=config['max_nt']+1,
-                # maximum number of target side symbols (both T and NT) allowed in a rule.
-                max_target_length=MAX_INITIAL_SIZE,
-                # minimum span of a nonterminal in the RHS of a rule in TEST DATA
-                min_gap_size=1,
-                # filename of file containing precomputed collocations
-                precompute_file=config['precompute_file'],
-                # maximum frequency rank of patterns used to compute triples (< 20)
-                precompute_secondary_rank=config['rank2'],
-                # maximum frequency rank of patterns used to compute collocations (< 300)
-                precompute_rank=config['rank1'],
-                # require extracted rules to have at least one aligned word
-                require_aligned_terminal=True,
-                # require each contiguous chunk of extracted rules
-                # to have at least one aligned word
-                require_aligned_chunks=False,
-                # maximum span of a grammar rule extracted from TRAINING DATA
-                train_max_initial_size=config['max_size'],
-                # minimum span of an RHS nonterminal in a rule extracted from TRAINING DATA
-                train_min_gap_size=config['min_gap'],
-                # True if phrases should be tight, False otherwise (better but slower)
-                tight_phrases=True,
-                )
-
-        # lexical weighting tables
-        tt = cdec.sa.BiLex(from_binary=config['lex_file'])
-
-        self.models = (EgivenFCoherent, SampleCountF, CountEF, 
-                MaxLexFgivenE(tt), MaxLexEgivenF(tt), IsSingletonF, IsSingletonFE)
-
-        fsarray = cdec.sa.SuffixArray(from_binary=config['f_sa_file'])
-        edarray = cdec.sa.DataArray(from_binary=config['e_file'])
-
-        # lower=faster, higher=better; improvements level off above 200-300 range,
-        # -1 = don't sample, use all data (VERY SLOW!)
-        sampler = cdec.sa.Sampler(300, fsarray)
-
-        self.factory.configure(fsarray, edarray, sampler)
-
-    def grammar(self, sentence):
-        if isinstance(sentence, unicode):
-            sentence = sentence.encode('utf8')
-        cnet = chain(('<s>',), sentence.split(), ('</s>',))
-        cnet = (cdec.sa.sym_fromstring(word, terminal=True) for word in cnet)
-        cnet = tuple(((word, None, 1), ) for word in cnet)
-        return self.factory.input(cnet, self.models)
diff --git a/python/cdec/sa/features.py b/python/cdec/sa/features.py
deleted file mode 100644
index 325b9e13..00000000
--- a/python/cdec/sa/features.py
+++ /dev/null
@@ -1,57 +0,0 @@
-from __future__ import division
-import math
-
-MAXSCORE = 99
-
-def EgivenF(fphrase, ephrase, paircount, fcount, fsample_count): # p(e|f)
-    return -math.log10(paircount/fcount)
-
-def CountEF(fphrase, ephrase, paircount, fcount, fsample_count):
-    return math.log10(1 + paircount)
-
-def SampleCountF(fphrase, ephrase, paircount, fcount, fsample_count):
-    return math.log10(1 + fsample_count)
-
-def EgivenFCoherent(fphrase, ephrase, paircount, fcount, fsample_count):
-    prob = paircount/fsample_count
-    return -math.log10(prob) if prob > 0 else MAXSCORE
-
-def CoherenceProb(fphrase, ephrase, paircount, fcount, fsample_count):
-    return -math.log10(fcount/fsample_count)
-
-def MaxLexEgivenF(ttable):
-    def feature(fphrase, ephrase, paircount, fcount, fsample_count):
-        fwords = fphrase.words
-        fwords.append('NULL')
-        def score():
-            for e in ephrase.words:
-              maxScore = max(ttable.get_score(f, e, 0) for f in fwords)
-              yield -math.log10(maxScore) if maxScore > 0 else MAXSCORE
-        return sum(score())
-    return feature
-
-def MaxLexFgivenE(ttable):
-    def feature(fphrase, ephrase, paircount, fcount, fsample_count):
-        ewords = ephrase.words
-        ewords.append('NULL')
-        def score():
-            for f in fphrase.words:
-              maxScore = max(ttable.get_score(f, e, 1) for e in ewords)
-              yield -math.log10(maxScore) if maxScore > 0 else MAXSCORE
-        return sum(score())
-    return feature
-
-def IsSingletonF(fphrase, ephrase, paircount, fcount, fsample_count):
-    return (fcount == 1)
-
-def IsSingletonFE(fphrase, ephrase, paircount, fcount, fsample_count):
-    return (paircount == 1)
-
-def IsNotSingletonF(fphrase, ephrase, paircount, fcount, fsample_count):
-    return (fcount > 1)
-
-def IsNotSingletonFE(fphrase, ephrase, paircount, fcount, fsample_count):
-    return (paircount > 1)
-
-def IsFEGreaterThanZero(fphrase, ephrase, paircount, fcount, fsample_count):
-    return (paircount > 0.01)
diff --git a/python/cdec/score.py b/python/cdec/score.py
deleted file mode 100644
index 22257774..00000000
--- a/python/cdec/score.py
+++ /dev/null
@@ -1 +0,0 @@
-from _cdec import BLEU, TER, CER, Metric
diff --git a/python/pkg/cdec/__init__.py b/python/pkg/cdec/__init__.py
new file mode 100644
index 00000000..503ac787
--- /dev/null
+++ b/python/pkg/cdec/__init__.py
@@ -0,0 +1 @@
+from cdec._cdec import Decoder, Lattice, TRule, NT, NTRef, ParseFailed, InvalidConfig
diff --git a/python/pkg/cdec/configobj.py b/python/pkg/cdec/configobj.py
new file mode 100644
index 00000000..c1f6e6df
--- /dev/null
+++ b/python/pkg/cdec/configobj.py
@@ -0,0 +1,2468 @@
+# configobj.py
+# A config file reader/writer that supports nested sections in config files.
+# Copyright (C) 2005-2010 Michael Foord, Nicola Larosa
+# E-mail: fuzzyman AT voidspace DOT org DOT uk
+#         nico AT tekNico DOT net
+
+# ConfigObj 4
+# http://www.voidspace.org.uk/python/configobj.html
+
+# Released subject to the BSD License
+# Please see http://www.voidspace.org.uk/python/license.shtml
+
+# Scripts maintained at http://www.voidspace.org.uk/python/index.shtml
+# For information about bugfixes, updates and support, please join the
+# ConfigObj mailing list:
+# http://lists.sourceforge.net/lists/listinfo/configobj-develop
+# Comments, suggestions and bug reports welcome.
+
+from __future__ import generators
+
+import os
+import re
+import sys
+
+from codecs import BOM_UTF8, BOM_UTF16, BOM_UTF16_BE, BOM_UTF16_LE
+
+
+# imported lazily to avoid startup performance hit if it isn't used
+compiler = None
+
+# A dictionary mapping BOM to
+# the encoding to decode with, and what to set the
+# encoding attribute to.
+BOMS = {
+    BOM_UTF8: ('utf_8', None),
+    BOM_UTF16_BE: ('utf16_be', 'utf_16'),
+    BOM_UTF16_LE: ('utf16_le', 'utf_16'),
+    BOM_UTF16: ('utf_16', 'utf_16'),
+    }
+# All legal variants of the BOM codecs.
+# TODO: the list of aliases is not meant to be exhaustive, is there a
+#   better way ?
+BOM_LIST = {
+    'utf_16': 'utf_16',
+    'u16': 'utf_16',
+    'utf16': 'utf_16',
+    'utf-16': 'utf_16',
+    'utf16_be': 'utf16_be',
+    'utf_16_be': 'utf16_be',
+    'utf-16be': 'utf16_be',
+    'utf16_le': 'utf16_le',
+    'utf_16_le': 'utf16_le',
+    'utf-16le': 'utf16_le',
+    'utf_8': 'utf_8',
+    'u8': 'utf_8',
+    'utf': 'utf_8',
+    'utf8': 'utf_8',
+    'utf-8': 'utf_8',
+    }
+
+# Map of encodings to the BOM to write.
+BOM_SET = {
+    'utf_8': BOM_UTF8,
+    'utf_16': BOM_UTF16,
+    'utf16_be': BOM_UTF16_BE,
+    'utf16_le': BOM_UTF16_LE,
+    None: BOM_UTF8
+    }
+
+
+def match_utf8(encoding):
+    return BOM_LIST.get(encoding.lower()) == 'utf_8'
+
+
+# Quote strings used for writing values
+squot = "'%s'"
+dquot = '"%s"'
+noquot = "%s"
+wspace_plus = ' \r\n\v\t\'"'
+tsquot = '"""%s"""'
+tdquot = "'''%s'''"
+
+# Sentinel for use in getattr calls to replace hasattr
+MISSING = object()
+
+__version__ = '4.7.2'
+
+try:
+    any
+except NameError:
+    def any(iterable):
+        for entry in iterable:
+            if entry:
+                return True
+        return False
+
+
+__all__ = (
+    '__version__',
+    'DEFAULT_INDENT_TYPE',
+    'DEFAULT_INTERPOLATION',
+    'ConfigObjError',
+    'NestingError',
+    'ParseError',
+    'DuplicateError',
+    'ConfigspecError',
+    'ConfigObj',
+    'SimpleVal',
+    'InterpolationError',
+    'InterpolationLoopError',
+    'MissingInterpolationOption',
+    'RepeatSectionError',
+    'ReloadError',
+    'UnreprError',
+    'UnknownType',
+    'flatten_errors',
+    'get_extra_values'
+)
+
+DEFAULT_INTERPOLATION = 'configparser'
+DEFAULT_INDENT_TYPE = '    '
+MAX_INTERPOL_DEPTH = 10
+
+OPTION_DEFAULTS = {
+    'interpolation': True,
+    'raise_errors': False,
+    'list_values': True,
+    'create_empty': False,
+    'file_error': False,
+    'configspec': None,
+    'stringify': True,
+    # option may be set to one of ('', ' ', '\t')
+    'indent_type': None,
+    'encoding': None,
+    'default_encoding': None,
+    'unrepr': False,
+    'write_empty_values': False,
+}
+
+
+
+def getObj(s):
+    global compiler
+    if compiler is None:
+        import compiler
+    s = "a=" + s
+    p = compiler.parse(s)
+    return p.getChildren()[1].getChildren()[0].getChildren()[1]
+
+
+class UnknownType(Exception):
+    pass
+
+
+class Builder(object):
+    
+    def build(self, o):
+        m = getattr(self, 'build_' + o.__class__.__name__, None)
+        if m is None:
+            raise UnknownType(o.__class__.__name__)
+        return m(o)
+    
+    def build_List(self, o):
+        return map(self.build, o.getChildren())
+    
+    def build_Const(self, o):
+        return o.value
+    
+    def build_Dict(self, o):
+        d = {}
+        i = iter(map(self.build, o.getChildren()))
+        for el in i:
+            d[el] = i.next()
+        return d
+    
+    def build_Tuple(self, o):
+        return tuple(self.build_List(o))
+    
+    def build_Name(self, o):
+        if o.name == 'None':
+            return None
+        if o.name == 'True':
+            return True
+        if o.name == 'False':
+            return False
+        
+        # An undefined Name
+        raise UnknownType('Undefined Name')
+    
+    def build_Add(self, o):
+        real, imag = map(self.build_Const, o.getChildren())
+        try:
+            real = float(real)
+        except TypeError:
+            raise UnknownType('Add')
+        if not isinstance(imag, complex) or imag.real != 0.0:
+            raise UnknownType('Add')
+        return real+imag
+    
+    def build_Getattr(self, o):
+        parent = self.build(o.expr)
+        return getattr(parent, o.attrname)
+    
+    def build_UnarySub(self, o):
+        return -self.build_Const(o.getChildren()[0])
+    
+    def build_UnaryAdd(self, o):
+        return self.build_Const(o.getChildren()[0])
+
+
+_builder = Builder()
+
+
+def unrepr(s):
+    if not s:
+        return s
+    return _builder.build(getObj(s))
+
+
+
+class ConfigObjError(SyntaxError):
+    """
+    This is the base class for all errors that ConfigObj raises.
+    It is a subclass of SyntaxError.
+    """
+    def __init__(self, message='', line_number=None, line=''):
+        self.line = line
+        self.line_number = line_number
+        SyntaxError.__init__(self, message)
+
+
+class NestingError(ConfigObjError):
+    """
+    This error indicates a level of nesting that doesn't match.
+    """
+
+
+class ParseError(ConfigObjError):
+    """
+    This error indicates that a line is badly written.
+    It is neither a valid ``key = value`` line,
+    nor a valid section marker line.
+    """
+
+
+class ReloadError(IOError):
+    """
+    A 'reload' operation failed.
+    This exception is a subclass of ``IOError``.
+    """
+    def __init__(self):
+        IOError.__init__(self, 'reload failed, filename is not set.')
+
+
+class DuplicateError(ConfigObjError):
+    """
+    The keyword or section specified already exists.
+    """
+
+
+class ConfigspecError(ConfigObjError):
+    """
+    An error occured whilst parsing a configspec.
+    """
+
+
+class InterpolationError(ConfigObjError):
+    """Base class for the two interpolation errors."""
+
+
+class InterpolationLoopError(InterpolationError):
+    """Maximum interpolation depth exceeded in string interpolation."""
+
+    def __init__(self, option):
+        InterpolationError.__init__(
+            self,
+            'interpolation loop detected in value "%s".' % option)
+
+
+class RepeatSectionError(ConfigObjError):
+    """
+    This error indicates additional sections in a section with a
+    ``__many__`` (repeated) section.
+    """
+
+
+class MissingInterpolationOption(InterpolationError):
+    """A value specified for interpolation was missing."""
+    def __init__(self, option):
+        msg = 'missing option "%s" in interpolation.' % option
+        InterpolationError.__init__(self, msg)
+
+
+class UnreprError(ConfigObjError):
+    """An error parsing in unrepr mode."""
+
+
+
+class InterpolationEngine(object):
+    """
+    A helper class to help perform string interpolation.
+
+    This class is an abstract base class; its descendants perform
+    the actual work.
+    """
+
+    # compiled regexp to use in self.interpolate()
+    _KEYCRE = re.compile(r"%\(([^)]*)\)s")
+    _cookie = '%'
+
+    def __init__(self, section):
+        # the Section instance that "owns" this engine
+        self.section = section
+
+
+    def interpolate(self, key, value):
+        # short-cut
+        if not self._cookie in value:
+            return value
+        
+        def recursive_interpolate(key, value, section, backtrail):
+            """The function that does the actual work.
+
+            ``value``: the string we're trying to interpolate.
+            ``section``: the section in which that string was found
+            ``backtrail``: a dict to keep track of where we've been,
+            to detect and prevent infinite recursion loops
+
+            This is similar to a depth-first-search algorithm.
+            """
+            # Have we been here already?
+            if (key, section.name) in backtrail:
+                # Yes - infinite loop detected
+                raise InterpolationLoopError(key)
+            # Place a marker on our backtrail so we won't come back here again
+            backtrail[(key, section.name)] = 1
+
+            # Now start the actual work
+            match = self._KEYCRE.search(value)
+            while match:
+                # The actual parsing of the match is implementation-dependent,
+                # so delegate to our helper function
+                k, v, s = self._parse_match(match)
+                if k is None:
+                    # That's the signal that no further interpolation is needed
+                    replacement = v
+                else:
+                    # Further interpolation may be needed to obtain final value
+                    replacement = recursive_interpolate(k, v, s, backtrail)
+                # Replace the matched string with its final value
+                start, end = match.span()
+                value = ''.join((value[:start], replacement, value[end:]))
+                new_search_start = start + len(replacement)
+                # Pick up the next interpolation key, if any, for next time
+                # through the while loop
+                match = self._KEYCRE.search(value, new_search_start)
+
+            # Now safe to come back here again; remove marker from backtrail
+            del backtrail[(key, section.name)]
+
+            return value
+
+        # Back in interpolate(), all we have to do is kick off the recursive
+        # function with appropriate starting values
+        value = recursive_interpolate(key, value, self.section, {})
+        return value
+
+
+    def _fetch(self, key):
+        """Helper function to fetch values from owning section.
+
+        Returns a 2-tuple: the value, and the section where it was found.
+        """
+        # switch off interpolation before we try and fetch anything !
+        save_interp = self.section.main.interpolation
+        self.section.main.interpolation = False
+
+        # Start at section that "owns" this InterpolationEngine
+        current_section = self.section
+        while True:
+            # try the current section first
+            val = current_section.get(key)
+            if val is not None and not isinstance(val, Section):
+                break
+            # try "DEFAULT" next
+            val = current_section.get('DEFAULT', {}).get(key)
+            if val is not None and not isinstance(val, Section):
+                break
+            # move up to parent and try again
+            # top-level's parent is itself
+            if current_section.parent is current_section:
+                # reached top level, time to give up
+                break
+            current_section = current_section.parent
+
+        # restore interpolation to previous value before returning
+        self.section.main.interpolation = save_interp
+        if val is None:
+            raise MissingInterpolationOption(key)
+        return val, current_section
+
+
+    def _parse_match(self, match):
+        """Implementation-dependent helper function.
+
+        Will be passed a match object corresponding to the interpolation
+        key we just found (e.g., "%(foo)s" or "$foo"). Should look up that
+        key in the appropriate config file section (using the ``_fetch()``
+        helper function) and return a 3-tuple: (key, value, section)
+
+        ``key`` is the name of the key we're looking for
+        ``value`` is the value found for that key
+        ``section`` is a reference to the section where it was found
+
+        ``key`` and ``section`` should be None if no further
+        interpolation should be performed on the resulting value
+        (e.g., if we interpolated "$$" and returned "$").
+        """
+        raise NotImplementedError()
+    
+
+
+class ConfigParserInterpolation(InterpolationEngine):
+    """Behaves like ConfigParser."""
+    _cookie = '%'
+    _KEYCRE = re.compile(r"%\(([^)]*)\)s")
+
+    def _parse_match(self, match):
+        key = match.group(1)
+        value, section = self._fetch(key)
+        return key, value, section
+
+
+
+class TemplateInterpolation(InterpolationEngine):
+    """Behaves like string.Template."""
+    _cookie = '$'
+    _delimiter = '$'
+    _KEYCRE = re.compile(r"""
+        \$(?:
+          (?P<escaped>\$)              |   # Two $ signs
+          (?P<named>[_a-z][_a-z0-9]*)  |   # $name format
+          {(?P<braced>[^}]*)}              # ${name} format
+        )
+        """, re.IGNORECASE | re.VERBOSE)
+
+    def _parse_match(self, match):
+        # Valid name (in or out of braces): fetch value from section
+        key = match.group('named') or match.group('braced')
+        if key is not None:
+            value, section = self._fetch(key)
+            return key, value, section
+        # Escaped delimiter (e.g., $$): return single delimiter
+        if match.group('escaped') is not None:
+            # Return None for key and section to indicate it's time to stop
+            return None, self._delimiter, None
+        # Anything else: ignore completely, just return it unchanged
+        return None, match.group(), None
+
+
+interpolation_engines = {
+    'configparser': ConfigParserInterpolation,
+    'template': TemplateInterpolation,
+}
+
+
+def __newobj__(cls, *args):
+    # Hack for pickle
+    return cls.__new__(cls, *args) 
+
+class Section(dict):
+    """
+    A dictionary-like object that represents a section in a config file.
+    
+    It does string interpolation if the 'interpolation' attribute
+    of the 'main' object is set to True.
+    
+    Interpolation is tried first from this object, then from the 'DEFAULT'
+    section of this object, next from the parent and its 'DEFAULT' section,
+    and so on until the main object is reached.
+    
+    A Section will behave like an ordered dictionary - following the
+    order of the ``scalars`` and ``sections`` attributes.
+    You can use this to change the order of members.
+    
+    Iteration follows the order: scalars, then sections.
+    """
+
+    
+    def __setstate__(self, state):
+        dict.update(self, state[0])
+        self.__dict__.update(state[1])
+
+    def __reduce__(self):
+        state = (dict(self), self.__dict__)
+        return (__newobj__, (self.__class__,), state)
+    
+    
+    def __init__(self, parent, depth, main, indict=None, name=None):
+        """
+        * parent is the section above
+        * depth is the depth level of this section
+        * main is the main ConfigObj
+        * indict is a dictionary to initialise the section with
+        """
+        if indict is None:
+            indict = {}
+        dict.__init__(self)
+        # used for nesting level *and* interpolation
+        self.parent = parent
+        # used for the interpolation attribute
+        self.main = main
+        # level of nesting depth of this Section
+        self.depth = depth
+        # purely for information
+        self.name = name
+        #
+        self._initialise()
+        # we do this explicitly so that __setitem__ is used properly
+        # (rather than just passing to ``dict.__init__``)
+        for entry, value in indict.iteritems():
+            self[entry] = value
+            
+            
+    def _initialise(self):
+        # the sequence of scalar values in this Section
+        self.scalars = []
+        # the sequence of sections in this Section
+        self.sections = []
+        # for comments :-)
+        self.comments = {}
+        self.inline_comments = {}
+        # the configspec
+        self.configspec = None
+        # for defaults
+        self.defaults = []
+        self.default_values = {}
+        self.extra_values = []
+        self._created = False
+
+
+    def _interpolate(self, key, value):
+        try:
+            # do we already have an interpolation engine?
+            engine = self._interpolation_engine
+        except AttributeError:
+            # not yet: first time running _interpolate(), so pick the engine
+            name = self.main.interpolation
+            if name == True:  # note that "if name:" would be incorrect here
+                # backwards-compatibility: interpolation=True means use default
+                name = DEFAULT_INTERPOLATION
+            name = name.lower()  # so that "Template", "template", etc. all work
+            class_ = interpolation_engines.get(name, None)
+            if class_ is None:
+                # invalid value for self.main.interpolation
+                self.main.interpolation = False
+                return value
+            else:
+                # save reference to engine so we don't have to do this again
+                engine = self._interpolation_engine = class_(self)
+        # let the engine do the actual work
+        return engine.interpolate(key, value)
+
+
+    def __getitem__(self, key):
+        """Fetch the item and do string interpolation."""
+        val = dict.__getitem__(self, key)
+        if self.main.interpolation: 
+            if isinstance(val, basestring):
+                return self._interpolate(key, val)
+            if isinstance(val, list):
+                def _check(entry):
+                    if isinstance(entry, basestring):
+                        return self._interpolate(key, entry)
+                    return entry
+                new = [_check(entry) for entry in val]
+                if new != val:
+                    return new
+        return val
+
+
+    def __setitem__(self, key, value, unrepr=False):
+        """
+        Correctly set a value.
+        
+        Making dictionary values Section instances.
+        (We have to special case 'Section' instances - which are also dicts)
+        
+        Keys must be strings.
+        Values need only be strings (or lists of strings) if
+        ``main.stringify`` is set.
+        
+        ``unrepr`` must be set when setting a value to a dictionary, without
+        creating a new sub-section.
+        """
+        if not isinstance(key, basestring):
+            raise ValueError('The key "%s" is not a string.' % key)
+        
+        # add the comment
+        if key not in self.comments:
+            self.comments[key] = []
+            self.inline_comments[key] = ''
+        # remove the entry from defaults
+        if key in self.defaults:
+            self.defaults.remove(key)
+        #
+        if isinstance(value, Section):
+            if key not in self:
+                self.sections.append(key)
+            dict.__setitem__(self, key, value)
+        elif isinstance(value, dict) and not unrepr:
+            # First create the new depth level,
+            # then create the section
+            if key not in self:
+                self.sections.append(key)
+            new_depth = self.depth + 1
+            dict.__setitem__(
+                self,
+                key,
+                Section(
+                    self,
+                    new_depth,
+                    self.main,
+                    indict=value,
+                    name=key))
+        else:
+            if key not in self:
+                self.scalars.append(key)
+            if not self.main.stringify:
+                if isinstance(value, basestring):
+                    pass
+                elif isinstance(value, (list, tuple)):
+                    for entry in value:
+                        if not isinstance(entry, basestring):
+                            raise TypeError('Value is not a string "%s".' % entry)
+                else:
+                    raise TypeError('Value is not a string "%s".' % value)
+            dict.__setitem__(self, key, value)
+
+
+    def __delitem__(self, key):
+        """Remove items from the sequence when deleting."""
+        dict. __delitem__(self, key)
+        if key in self.scalars:
+            self.scalars.remove(key)
+        else:
+            self.sections.remove(key)
+        del self.comments[key]
+        del self.inline_comments[key]
+
+
+    def get(self, key, default=None):
+        """A version of ``get`` that doesn't bypass string interpolation."""
+        try:
+            return self[key]
+        except KeyError:
+            return default
+
+
+    def update(self, indict):
+        """
+        A version of update that uses our ``__setitem__``.
+        """
+        for entry in indict:
+            self[entry] = indict[entry]
+
+
+    def pop(self, key, default=MISSING):
+        """
+        'D.pop(k[,d]) -> v, remove specified key and return the corresponding value.
+        If key is not found, d is returned if given, otherwise KeyError is raised'
+        """
+        try:
+            val = self[key]
+        except KeyError:
+            if default is MISSING:
+                raise
+            val = default
+        else:
+            del self[key]
+        return val
+
+
+    def popitem(self):
+        """Pops the first (key,val)"""
+        sequence = (self.scalars + self.sections)
+        if not sequence:
+            raise KeyError(": 'popitem(): dictionary is empty'")
+        key = sequence[0]
+        val =  self[key]
+        del self[key]
+        return key, val
+
+
+    def clear(self):
+        """
+        A version of clear that also affects scalars/sections
+        Also clears comments and configspec.
+        
+        Leaves other attributes alone :
+            depth/main/parent are not affected
+        """
+        dict.clear(self)
+        self.scalars = []
+        self.sections = []
+        self.comments = {}
+        self.inline_comments = {}
+        self.configspec = None
+        self.defaults = []
+        self.extra_values = []
+
+
+    def setdefault(self, key, default=None):
+        """A version of setdefault that sets sequence if appropriate."""
+        try:
+            return self[key]
+        except KeyError:
+            self[key] = default
+            return self[key]
+
+
+    def items(self):
+        """D.items() -> list of D's (key, value) pairs, as 2-tuples"""
+        return zip((self.scalars + self.sections), self.values())
+
+
+    def keys(self):
+        """D.keys() -> list of D's keys"""
+        return (self.scalars + self.sections)
+
+
+    def values(self):
+        """D.values() -> list of D's values"""
+        return [self[key] for key in (self.scalars + self.sections)]
+
+
+    def iteritems(self):
+        """D.iteritems() -> an iterator over the (key, value) items of D"""
+        return iter(self.items())
+
+
+    def iterkeys(self):
+        """D.iterkeys() -> an iterator over the keys of D"""
+        return iter((self.scalars + self.sections))
+
+    __iter__ = iterkeys
+
+
+    def itervalues(self):
+        """D.itervalues() -> an iterator over the values of D"""
+        return iter(self.values())
+
+
+    def __repr__(self):
+        """x.__repr__() <==> repr(x)"""
+        def _getval(key):
+            try:
+                return self[key]
+            except MissingInterpolationOption:
+                return dict.__getitem__(self, key)
+        return '{%s}' % ', '.join([('%s: %s' % (repr(key), repr(_getval(key))))
+            for key in (self.scalars + self.sections)])
+
+    __str__ = __repr__
+    __str__.__doc__ = "x.__str__() <==> str(x)"
+
+
+    # Extra methods - not in a normal dictionary
+
+    def dict(self):
+        """
+        Return a deepcopy of self as a dictionary.
+        
+        All members that are ``Section`` instances are recursively turned to
+        ordinary dictionaries - by calling their ``dict`` method.
+        
+        >>> n = a.dict()
+        >>> n == a
+        1
+        >>> n is a
+        0
+        """
+        newdict = {}
+        for entry in self:
+            this_entry = self[entry]
+            if isinstance(this_entry, Section):
+                this_entry = this_entry.dict()
+            elif isinstance(this_entry, list):
+                # create a copy rather than a reference
+                this_entry = list(this_entry)
+            elif isinstance(this_entry, tuple):
+                # create a copy rather than a reference
+                this_entry = tuple(this_entry)
+            newdict[entry] = this_entry
+        return newdict
+
+
+    def merge(self, indict):
+        """
+        A recursive update - useful for merging config files.
+        
+        >>> a = '''[section1]
+        ...     option1 = True
+        ...     [[subsection]]
+        ...     more_options = False
+        ...     # end of file'''.splitlines()
+        >>> b = '''# File is user.ini
+        ...     [section1]
+        ...     option1 = False
+        ...     # end of file'''.splitlines()
+        >>> c1 = ConfigObj(b)
+        >>> c2 = ConfigObj(a)
+        >>> c2.merge(c1)
+        >>> c2
+        ConfigObj({'section1': {'option1': 'False', 'subsection': {'more_options': 'False'}}})
+        """
+        for key, val in indict.items():
+            if (key in self and isinstance(self[key], dict) and
+                                isinstance(val, dict)):
+                self[key].merge(val)
+            else:   
+                self[key] = val
+
+
+    def rename(self, oldkey, newkey):
+        """
+        Change a keyname to another, without changing position in sequence.
+        
+        Implemented so that transformations can be made on keys,
+        as well as on values. (used by encode and decode)
+        
+        Also renames comments.
+        """
+        if oldkey in self.scalars:
+            the_list = self.scalars
+        elif oldkey in self.sections:
+            the_list = self.sections
+        else:
+            raise KeyError('Key "%s" not found.' % oldkey)
+        pos = the_list.index(oldkey)
+        #
+        val = self[oldkey]
+        dict.__delitem__(self, oldkey)
+        dict.__setitem__(self, newkey, val)
+        the_list.remove(oldkey)
+        the_list.insert(pos, newkey)
+        comm = self.comments[oldkey]
+        inline_comment = self.inline_comments[oldkey]
+        del self.comments[oldkey]
+        del self.inline_comments[oldkey]
+        self.comments[newkey] = comm
+        self.inline_comments[newkey] = inline_comment
+
+
+    def walk(self, function, raise_errors=True,
+            call_on_sections=False, **keywargs):
+        """
+        Walk every member and call a function on the keyword and value.
+        
+        Return a dictionary of the return values
+        
+        If the function raises an exception, raise the errror
+        unless ``raise_errors=False``, in which case set the return value to
+        ``False``.
+        
+        Any unrecognised keyword arguments you pass to walk, will be pased on
+        to the function you pass in.
+        
+        Note: if ``call_on_sections`` is ``True`` then - on encountering a
+        subsection, *first* the function is called for the *whole* subsection,
+        and then recurses into it's members. This means your function must be
+        able to handle strings, dictionaries and lists. This allows you
+        to change the key of subsections as well as for ordinary members. The
+        return value when called on the whole subsection has to be discarded.
+        
+        See  the encode and decode methods for examples, including functions.
+        
+        .. admonition:: caution
+        
+            You can use ``walk`` to transform the names of members of a section
+            but you mustn't add or delete members.
+        
+        >>> config = '''[XXXXsection]
+        ... XXXXkey = XXXXvalue'''.splitlines()
+        >>> cfg = ConfigObj(config)
+        >>> cfg
+        ConfigObj({'XXXXsection': {'XXXXkey': 'XXXXvalue'}})
+        >>> def transform(section, key):
+        ...     val = section[key]
+        ...     newkey = key.replace('XXXX', 'CLIENT1')
+        ...     section.rename(key, newkey)
+        ...     if isinstance(val, (tuple, list, dict)):
+        ...         pass
+        ...     else:
+        ...         val = val.replace('XXXX', 'CLIENT1')
+        ...         section[newkey] = val
+        >>> cfg.walk(transform, call_on_sections=True)
+        {'CLIENT1section': {'CLIENT1key': None}}
+        >>> cfg
+        ConfigObj({'CLIENT1section': {'CLIENT1key': 'CLIENT1value'}})
+        """
+        out = {}
+        # scalars first
+        for i in range(len(self.scalars)):
+            entry = self.scalars[i]
+            try:
+                val = function(self, entry, **keywargs)
+                # bound again in case name has changed
+                entry = self.scalars[i]
+                out[entry] = val
+            except Exception:
+                if raise_errors:
+                    raise
+                else:
+                    entry = self.scalars[i]
+                    out[entry] = False
+        # then sections
+        for i in range(len(self.sections)):
+            entry = self.sections[i]
+            if call_on_sections:
+                try:
+                    function(self, entry, **keywargs)
+                except Exception:
+                    if raise_errors:
+                        raise
+                    else:
+                        entry = self.sections[i]
+                        out[entry] = False
+                # bound again in case name has changed
+                entry = self.sections[i]
+            # previous result is discarded
+            out[entry] = self[entry].walk(
+                function,
+                raise_errors=raise_errors,
+                call_on_sections=call_on_sections,
+                **keywargs)
+        return out
+
+
+    def as_bool(self, key):
+        """
+        Accepts a key as input. The corresponding value must be a string or
+        the objects (``True`` or 1) or (``False`` or 0). We allow 0 and 1 to
+        retain compatibility with Python 2.2.
+        
+        If the string is one of  ``True``, ``On``, ``Yes``, or ``1`` it returns 
+        ``True``.
+        
+        If the string is one of  ``False``, ``Off``, ``No``, or ``0`` it returns 
+        ``False``.
+        
+        ``as_bool`` is not case sensitive.
+        
+        Any other input will raise a ``ValueError``.
+        
+        >>> a = ConfigObj()
+        >>> a['a'] = 'fish'
+        >>> a.as_bool('a')
+        Traceback (most recent call last):
+        ValueError: Value "fish" is neither True nor False
+        >>> a['b'] = 'True'
+        >>> a.as_bool('b')
+        1
+        >>> a['b'] = 'off'
+        >>> a.as_bool('b')
+        0
+        """
+        val = self[key]
+        if val == True:
+            return True
+        elif val == False:
+            return False
+        else:
+            try:
+                if not isinstance(val, basestring):
+                    # TODO: Why do we raise a KeyError here?
+                    raise KeyError()
+                else:
+                    return self.main._bools[val.lower()]
+            except KeyError:
+                raise ValueError('Value "%s" is neither True nor False' % val)
+
+
+    def as_int(self, key):
+        """
+        A convenience method which coerces the specified value to an integer.
+        
+        If the value is an invalid literal for ``int``, a ``ValueError`` will
+        be raised.
+        
+        >>> a = ConfigObj()
+        >>> a['a'] = 'fish'
+        >>> a.as_int('a')
+        Traceback (most recent call last):
+        ValueError: invalid literal for int() with base 10: 'fish'
+        >>> a['b'] = '1'
+        >>> a.as_int('b')
+        1
+        >>> a['b'] = '3.2'
+        >>> a.as_int('b')
+        Traceback (most recent call last):
+        ValueError: invalid literal for int() with base 10: '3.2'
+        """
+        return int(self[key])
+
+
+    def as_float(self, key):
+        """
+        A convenience method which coerces the specified value to a float.
+        
+        If the value is an invalid literal for ``float``, a ``ValueError`` will
+        be raised.
+        
+        >>> a = ConfigObj()
+        >>> a['a'] = 'fish'
+        >>> a.as_float('a')
+        Traceback (most recent call last):
+        ValueError: invalid literal for float(): fish
+        >>> a['b'] = '1'
+        >>> a.as_float('b')
+        1.0
+        >>> a['b'] = '3.2'
+        >>> a.as_float('b')
+        3.2000000000000002
+        """
+        return float(self[key])
+    
+    
+    def as_list(self, key):
+        """
+        A convenience method which fetches the specified value, guaranteeing
+        that it is a list.
+        
+        >>> a = ConfigObj()
+        >>> a['a'] = 1
+        >>> a.as_list('a')
+        [1]
+        >>> a['a'] = (1,)
+        >>> a.as_list('a')
+        [1]
+        >>> a['a'] = [1]
+        >>> a.as_list('a')
+        [1]
+        """
+        result = self[key]
+        if isinstance(result, (tuple, list)):
+            return list(result)
+        return [result]
+        
+
+    def restore_default(self, key):
+        """
+        Restore (and return) default value for the specified key.
+        
+        This method will only work for a ConfigObj that was created
+        with a configspec and has been validated.
+        
+        If there is no default value for this key, ``KeyError`` is raised.
+        """
+        default = self.default_values[key]
+        dict.__setitem__(self, key, default)
+        if key not in self.defaults:
+            self.defaults.append(key)
+        return default
+
+    
+    def restore_defaults(self):
+        """
+        Recursively restore default values to all members
+        that have them.
+        
+        This method will only work for a ConfigObj that was created
+        with a configspec and has been validated.
+        
+        It doesn't delete or modify entries without default values.
+        """
+        for key in self.default_values:
+            self.restore_default(key)
+            
+        for section in self.sections:
+            self[section].restore_defaults()
+
+
+class ConfigObj(Section):
+    """An object to read, create, and write config files."""
+
+    _keyword = re.compile(r'''^ # line start
+        (\s*)                   # indentation
+        (                       # keyword
+            (?:".*?")|          # double quotes
+            (?:'.*?')|          # single quotes
+            (?:[^'"=].*?)       # no quotes
+        )
+        \s*=\s*                 # divider
+        (.*)                    # value (including list values and comments)
+        $   # line end
+        ''',
+        re.VERBOSE)
+
+    _sectionmarker = re.compile(r'''^
+        (\s*)                     # 1: indentation
+        ((?:\[\s*)+)              # 2: section marker open
+        (                         # 3: section name open
+            (?:"\s*\S.*?\s*")|    # at least one non-space with double quotes
+            (?:'\s*\S.*?\s*')|    # at least one non-space with single quotes
+            (?:[^'"\s].*?)        # at least one non-space unquoted
+        )                         # section name close
+        ((?:\s*\])+)              # 4: section marker close
+        \s*(\#.*)?                # 5: optional comment
+        $''',
+        re.VERBOSE)
+
+    # this regexp pulls list values out as a single string
+    # or single values and comments
+    # FIXME: this regex adds a '' to the end of comma terminated lists
+    #   workaround in ``_handle_value``
+    _valueexp = re.compile(r'''^
+        (?:
+            (?:
+                (
+                    (?:
+                        (?:
+                            (?:".*?")|              # double quotes
+                            (?:'.*?')|              # single quotes
+                            (?:[^'",\#][^,\#]*?)    # unquoted
+                        )
+                        \s*,\s*                     # comma
+                    )*      # match all list items ending in a comma (if any)
+                )
+                (
+                    (?:".*?")|                      # double quotes
+                    (?:'.*?')|                      # single quotes
+                    (?:[^'",\#\s][^,]*?)|           # unquoted
+                    (?:(?<!,))                      # Empty value
+                )?          # last item in a list - or string value
+            )|
+            (,)             # alternatively a single comma - empty list
+        )
+        \s*(\#.*)?          # optional comment
+        $''',
+        re.VERBOSE)
+
+    # use findall to get the members of a list value
+    _listvalueexp = re.compile(r'''
+        (
+            (?:".*?")|          # double quotes
+            (?:'.*?')|          # single quotes
+            (?:[^'",\#]?.*?)       # unquoted
+        )
+        \s*,\s*                 # comma
+        ''',
+        re.VERBOSE)
+
+    # this regexp is used for the value
+    # when lists are switched off
+    _nolistvalue = re.compile(r'''^
+        (
+            (?:".*?")|          # double quotes
+            (?:'.*?')|          # single quotes
+            (?:[^'"\#].*?)|     # unquoted
+            (?:)                # Empty value
+        )
+        \s*(\#.*)?              # optional comment
+        $''',
+        re.VERBOSE)
+
+    # regexes for finding triple quoted values on one line
+    _single_line_single = re.compile(r"^'''(.*?)'''\s*(#.*)?$")
+    _single_line_double = re.compile(r'^"""(.*?)"""\s*(#.*)?$')
+    _multi_line_single = re.compile(r"^(.*?)'''\s*(#.*)?$")
+    _multi_line_double = re.compile(r'^(.*?)"""\s*(#.*)?$')
+
+    _triple_quote = {
+        "'''": (_single_line_single, _multi_line_single),
+        '"""': (_single_line_double, _multi_line_double),
+    }
+
+    # Used by the ``istrue`` Section method
+    _bools = {
+        'yes': True, 'no': False,
+        'on': True, 'off': False,
+        '1': True, '0': False,
+        'true': True, 'false': False,
+        }
+
+
+    def __init__(self, infile=None, options=None, configspec=None, encoding=None,
+                 interpolation=True, raise_errors=False, list_values=True,
+                 create_empty=False, file_error=False, stringify=True,
+                 indent_type=None, default_encoding=None, unrepr=False,
+                 write_empty_values=False, _inspec=False):
+        """
+        Parse a config file or create a config file object.
+        
+        ``ConfigObj(infile=None, configspec=None, encoding=None,
+                    interpolation=True, raise_errors=False, list_values=True,
+                    create_empty=False, file_error=False, stringify=True,
+                    indent_type=None, default_encoding=None, unrepr=False,
+                    write_empty_values=False, _inspec=False)``
+        """
+        self._inspec = _inspec
+        # init the superclass
+        Section.__init__(self, self, 0, self)
+        
+        infile = infile or []
+        
+        _options = {'configspec': configspec,
+                    'encoding': encoding, 'interpolation': interpolation,
+                    'raise_errors': raise_errors, 'list_values': list_values,
+                    'create_empty': create_empty, 'file_error': file_error,
+                    'stringify': stringify, 'indent_type': indent_type,
+                    'default_encoding': default_encoding, 'unrepr': unrepr,
+                    'write_empty_values': write_empty_values}
+
+        if options is None:
+            options = _options
+        else:
+            import warnings
+            warnings.warn('Passing in an options dictionary to ConfigObj() is '
+                          'deprecated. Use **options instead.',
+                          DeprecationWarning, stacklevel=2)
+            
+            # TODO: check the values too.
+            for entry in options:
+                if entry not in OPTION_DEFAULTS:
+                    raise TypeError('Unrecognised option "%s".' % entry)
+            for entry, value in OPTION_DEFAULTS.items():
+                if entry not in options:
+                    options[entry] = value
+                keyword_value = _options[entry]
+                if value != keyword_value:
+                    options[entry] = keyword_value
+        
+        # XXXX this ignores an explicit list_values = True in combination
+        # with _inspec. The user should *never* do that anyway, but still...
+        if _inspec:
+            options['list_values'] = False
+        
+        self._initialise(options)
+        configspec = options['configspec']
+        self._original_configspec = configspec
+        self._load(infile, configspec)
+        
+        
+    def _load(self, infile, configspec):
+        if isinstance(infile, basestring):
+            self.filename = infile
+            if os.path.isfile(infile):
+                h = open(infile, 'rb')
+                infile = h.read() or []
+                h.close()
+            elif self.file_error:
+                # raise an error if the file doesn't exist
+                raise IOError('Config file not found: "%s".' % self.filename)
+            else:
+                # file doesn't already exist
+                if self.create_empty:
+                    # this is a good test that the filename specified
+                    # isn't impossible - like on a non-existent device
+                    h = open(infile, 'w')
+                    h.write('')
+                    h.close()
+                infile = []
+                
+        elif isinstance(infile, (list, tuple)):
+            infile = list(infile)
+            
+        elif isinstance(infile, dict):
+            # initialise self
+            # the Section class handles creating subsections
+            if isinstance(infile, ConfigObj):
+                # get a copy of our ConfigObj
+                def set_section(in_section, this_section):
+                    for entry in in_section.scalars:
+                        this_section[entry] = in_section[entry]
+                    for section in in_section.sections:
+                        this_section[section] = {}
+                        set_section(in_section[section], this_section[section])
+                set_section(infile, self)
+                
+            else:
+                for entry in infile:
+                    self[entry] = infile[entry]
+            del self._errors
+            
+            if configspec is not None:
+                self._handle_configspec(configspec)
+            else:
+                self.configspec = None
+            return
+        
+        elif getattr(infile, 'read', MISSING) is not MISSING:
+            # This supports file like objects
+            infile = infile.read() or []
+            # needs splitting into lines - but needs doing *after* decoding
+            # in case it's not an 8 bit encoding
+        else:
+            raise TypeError('infile must be a filename, file like object, or list of lines.')
+        
+        if infile:
+            # don't do it for the empty ConfigObj
+            infile = self._handle_bom(infile)
+            # infile is now *always* a list
+            #
+            # Set the newlines attribute (first line ending it finds)
+            # and strip trailing '\n' or '\r' from lines
+            for line in infile:
+                if (not line) or (line[-1] not in ('\r', '\n', '\r\n')):
+                    continue
+                for end in ('\r\n', '\n', '\r'):
+                    if line.endswith(end):
+                        self.newlines = end
+                        break
+                break
+
+            infile = [line.rstrip('\r\n') for line in infile]
+            
+        self._parse(infile)
+        # if we had any errors, now is the time to raise them
+        if self._errors:
+            info = "at line %s." % self._errors[0].line_number
+            if len(self._errors) > 1:
+                msg = "Parsing failed with several errors.\nFirst error %s" % info
+                error = ConfigObjError(msg)
+            else:
+                error = self._errors[0]
+            # set the errors attribute; it's a list of tuples:
+            # (error_type, message, line_number)
+            error.errors = self._errors
+            # set the config attribute
+            error.config = self
+            raise error
+        # delete private attributes
+        del self._errors
+        
+        if configspec is None:
+            self.configspec = None
+        else:
+            self._handle_configspec(configspec)
+    
+    
+    def _initialise(self, options=None):
+        if options is None:
+            options = OPTION_DEFAULTS
+            
+        # initialise a few variables
+        self.filename = None
+        self._errors = []
+        self.raise_errors = options['raise_errors']
+        self.interpolation = options['interpolation']
+        self.list_values = options['list_values']
+        self.create_empty = options['create_empty']
+        self.file_error = options['file_error']
+        self.stringify = options['stringify']
+        self.indent_type = options['indent_type']
+        self.encoding = options['encoding']
+        self.default_encoding = options['default_encoding']
+        self.BOM = False
+        self.newlines = None
+        self.write_empty_values = options['write_empty_values']
+        self.unrepr = options['unrepr']
+        
+        self.initial_comment = []
+        self.final_comment = []
+        self.configspec = None
+        
+        if self._inspec:
+            self.list_values = False
+        
+        # Clear section attributes as well
+        Section._initialise(self)
+        
+        
+    def __repr__(self):
+        def _getval(key):
+            try:
+                return self[key]
+            except MissingInterpolationOption:
+                return dict.__getitem__(self, key)
+        return ('ConfigObj({%s})' % 
+                ', '.join([('%s: %s' % (repr(key), repr(_getval(key)))) 
+                for key in (self.scalars + self.sections)]))
+    
+    
+    def _handle_bom(self, infile):
+        """
+        Handle any BOM, and decode if necessary.
+        
+        If an encoding is specified, that *must* be used - but the BOM should
+        still be removed (and the BOM attribute set).
+        
+        (If the encoding is wrongly specified, then a BOM for an alternative
+        encoding won't be discovered or removed.)
+        
+        If an encoding is not specified, UTF8 or UTF16 BOM will be detected and
+        removed. The BOM attribute will be set. UTF16 will be decoded to
+        unicode.
+        
+        NOTE: This method must not be called with an empty ``infile``.
+        
+        Specifying the *wrong* encoding is likely to cause a
+        ``UnicodeDecodeError``.
+        
+        ``infile`` must always be returned as a list of lines, but may be
+        passed in as a single string.
+        """
+        if ((self.encoding is not None) and
+            (self.encoding.lower() not in BOM_LIST)):
+            # No need to check for a BOM
+            # the encoding specified doesn't have one
+            # just decode
+            return self._decode(infile, self.encoding)
+        
+        if isinstance(infile, (list, tuple)):
+            line = infile[0]
+        else:
+            line = infile
+        if self.encoding is not None:
+            # encoding explicitly supplied
+            # And it could have an associated BOM
+            # TODO: if encoding is just UTF16 - we ought to check for both
+            # TODO: big endian and little endian versions.
+            enc = BOM_LIST[self.encoding.lower()]
+            if enc == 'utf_16':
+                # For UTF16 we try big endian and little endian
+                for BOM, (encoding, final_encoding) in BOMS.items():
+                    if not final_encoding:
+                        # skip UTF8
+                        continue
+                    if infile.startswith(BOM):
+                        ### BOM discovered
+                        ##self.BOM = True
+                        # Don't need to remove BOM
+                        return self._decode(infile, encoding)
+                    
+                # If we get this far, will *probably* raise a DecodeError
+                # As it doesn't appear to start with a BOM
+                return self._decode(infile, self.encoding)
+            
+            # Must be UTF8
+            BOM = BOM_SET[enc]
+            if not line.startswith(BOM):
+                return self._decode(infile, self.encoding)
+            
+            newline = line[len(BOM):]
+            
+            # BOM removed
+            if isinstance(infile, (list, tuple)):
+                infile[0] = newline
+            else:
+                infile = newline
+            self.BOM = True
+            return self._decode(infile, self.encoding)
+        
+        # No encoding specified - so we need to check for UTF8/UTF16
+        for BOM, (encoding, final_encoding) in BOMS.items():
+            if not line.startswith(BOM):
+                continue
+            else:
+                # BOM discovered
+                self.encoding = final_encoding
+                if not final_encoding:
+                    self.BOM = True
+                    # UTF8
+                    # remove BOM
+                    newline = line[len(BOM):]
+                    if isinstance(infile, (list, tuple)):
+                        infile[0] = newline
+                    else:
+                        infile = newline
+                    # UTF8 - don't decode
+                    if isinstance(infile, basestring):
+                        return infile.splitlines(True)
+                    else:
+                        return infile
+                # UTF16 - have to decode
+                return self._decode(infile, encoding)
+            
+        # No BOM discovered and no encoding specified, just return
+        if isinstance(infile, basestring):
+            # infile read from a file will be a single string
+            return infile.splitlines(True)
+        return infile
+
+
+    def _a_to_u(self, aString):
+        """Decode ASCII strings to unicode if a self.encoding is specified."""
+        if self.encoding:
+            return aString.decode('ascii')
+        else:
+            return aString
+
+
+    def _decode(self, infile, encoding):
+        """
+        Decode infile to unicode. Using the specified encoding.
+        
+        if is a string, it also needs converting to a list.
+        """
+        if isinstance(infile, basestring):
+            # can't be unicode
+            # NOTE: Could raise a ``UnicodeDecodeError``
+            return infile.decode(encoding).splitlines(True)
+        for i, line in enumerate(infile):
+            if not isinstance(line, unicode):
+                # NOTE: The isinstance test here handles mixed lists of unicode/string
+                # NOTE: But the decode will break on any non-string values
+                # NOTE: Or could raise a ``UnicodeDecodeError``
+                infile[i] = line.decode(encoding)
+        return infile
+
+
+    def _decode_element(self, line):
+        """Decode element to unicode if necessary."""
+        if not self.encoding:
+            return line
+        if isinstance(line, str) and self.default_encoding:
+            return line.decode(self.default_encoding)
+        return line
+
+
+    def _str(self, value):
+        """
+        Used by ``stringify`` within validate, to turn non-string values
+        into strings.
+        """
+        if not isinstance(value, basestring):
+            return str(value)
+        else:
+            return value
+
+
+    def _parse(self, infile):
+        """Actually parse the config file."""
+        temp_list_values = self.list_values
+        if self.unrepr:
+            self.list_values = False
+            
+        comment_list = []
+        done_start = False
+        this_section = self
+        maxline = len(infile) - 1
+        cur_index = -1
+        reset_comment = False
+        
+        while cur_index < maxline:
+            if reset_comment:
+                comment_list = []
+            cur_index += 1
+            line = infile[cur_index]
+            sline = line.strip()
+            # do we have anything on the line ?
+            if not sline or sline.startswith('#'):
+                reset_comment = False
+                comment_list.append(line)
+                continue
+            
+            if not done_start:
+                # preserve initial comment
+                self.initial_comment = comment_list
+                comment_list = []
+                done_start = True
+                
+            reset_comment = True
+            # first we check if it's a section marker
+            mat = self._sectionmarker.match(line)
+            if mat is not None:
+                # is a section line
+                (indent, sect_open, sect_name, sect_close, comment) = mat.groups()
+                if indent and (self.indent_type is None):
+                    self.indent_type = indent
+                cur_depth = sect_open.count('[')
+                if cur_depth != sect_close.count(']'):
+                    self._handle_error("Cannot compute the section depth at line %s.",
+                                       NestingError, infile, cur_index)
+                    continue
+                
+                if cur_depth < this_section.depth:
+                    # the new section is dropping back to a previous level
+                    try:
+                        parent = self._match_depth(this_section,
+                                                   cur_depth).parent
+                    except SyntaxError:
+                        self._handle_error("Cannot compute nesting level at line %s.",
+                                           NestingError, infile, cur_index)
+                        continue
+                elif cur_depth == this_section.depth:
+                    # the new section is a sibling of the current section
+                    parent = this_section.parent
+                elif cur_depth == this_section.depth + 1:
+                    # the new section is a child the current section
+                    parent = this_section
+                else:
+                    self._handle_error("Section too nested at line %s.",
+                                       NestingError, infile, cur_index)
+                    
+                sect_name = self._unquote(sect_name)
+                if sect_name in parent:
+                    self._handle_error('Duplicate section name at line %s.',
+                                       DuplicateError, infile, cur_index)
+                    continue
+                
+                # create the new section
+                this_section = Section(
+                    parent,
+                    cur_depth,
+                    self,
+                    name=sect_name)
+                parent[sect_name] = this_section
+                parent.inline_comments[sect_name] = comment
+                parent.comments[sect_name] = comment_list
+                continue
+            #
+            # it's not a section marker,
+            # so it should be a valid ``key = value`` line
+            mat = self._keyword.match(line)
+            if mat is None:
+                # it neither matched as a keyword
+                # or a section marker
+                self._handle_error(
+                    'Invalid line at line "%s".',
+                    ParseError, infile, cur_index)
+            else:
+                # is a keyword value
+                # value will include any inline comment
+                (indent, key, value) = mat.groups()
+                if indent and (self.indent_type is None):
+                    self.indent_type = indent
+                # check for a multiline value
+                if value[:3] in ['"""', "'''"]:
+                    try:
+                        value, comment, cur_index = self._multiline(
+                            value, infile, cur_index, maxline)
+                    except SyntaxError:
+                        self._handle_error(
+                            'Parse error in value at line %s.',
+                            ParseError, infile, cur_index)
+                        continue
+                    else:
+                        if self.unrepr:
+                            comment = ''
+                            try:
+                                value = unrepr(value)
+                            except Exception, e:
+                                if type(e) == UnknownType:
+                                    msg = 'Unknown name or type in value at line %s.'
+                                else:
+                                    msg = 'Parse error in value at line %s.'
+                                self._handle_error(msg, UnreprError, infile,
+                                    cur_index)
+                                continue
+                else:
+                    if self.unrepr:
+                        comment = ''
+                        try:
+                            value = unrepr(value)
+                        except Exception, e:
+                            if isinstance(e, UnknownType):
+                                msg = 'Unknown name or type in value at line %s.'
+                            else:
+                                msg = 'Parse error in value at line %s.'
+                            self._handle_error(msg, UnreprError, infile,
+                                cur_index)
+                            continue
+                    else:
+                        # extract comment and lists
+                        try:
+                            (value, comment) = self._handle_value(value)
+                        except SyntaxError:
+                            self._handle_error(
+                                'Parse error in value at line %s.',
+                                ParseError, infile, cur_index)
+                            continue
+                #
+                key = self._unquote(key)
+                if key in this_section:
+                    self._handle_error(
+                        'Duplicate keyword name at line %s.',
+                        DuplicateError, infile, cur_index)
+                    continue
+                # add the key.
+                # we set unrepr because if we have got this far we will never
+                # be creating a new section
+                this_section.__setitem__(key, value, unrepr=True)
+                this_section.inline_comments[key] = comment
+                this_section.comments[key] = comment_list
+                continue
+        #
+        if self.indent_type is None:
+            # no indentation used, set the type accordingly
+            self.indent_type = ''
+
+        # preserve the final comment
+        if not self and not self.initial_comment:
+            self.initial_comment = comment_list
+        elif not reset_comment:
+            self.final_comment = comment_list
+        self.list_values = temp_list_values
+
+
+    def _match_depth(self, sect, depth):
+        """
+        Given a section and a depth level, walk back through the sections
+        parents to see if the depth level matches a previous section.
+        
+        Return a reference to the right section,
+        or raise a SyntaxError.
+        """
+        while depth < sect.depth:
+            if sect is sect.parent:
+                # we've reached the top level already
+                raise SyntaxError()
+            sect = sect.parent
+        if sect.depth == depth:
+            return sect
+        # shouldn't get here
+        raise SyntaxError()
+
+
+    def _handle_error(self, text, ErrorClass, infile, cur_index):
+        """
+        Handle an error according to the error settings.
+        
+        Either raise the error or store it.
+        The error will have occured at ``cur_index``
+        """
+        line = infile[cur_index]
+        cur_index += 1
+        message = text % cur_index
+        error = ErrorClass(message, cur_index, line)
+        if self.raise_errors:
+            # raise the error - parsing stops here
+            raise error
+        # store the error
+        # reraise when parsing has finished
+        self._errors.append(error)
+
+
+    def _unquote(self, value):
+        """Return an unquoted version of a value"""
+        if not value:
+            # should only happen during parsing of lists
+            raise SyntaxError
+        if (value[0] == value[-1]) and (value[0] in ('"', "'")):
+            value = value[1:-1]
+        return value
+
+
+    def _quote(self, value, multiline=True):
+        """
+        Return a safely quoted version of a value.
+        
+        Raise a ConfigObjError if the value cannot be safely quoted.
+        If multiline is ``True`` (default) then use triple quotes
+        if necessary.
+        
+        * Don't quote values that don't need it.
+        * Recursively quote members of a list and return a comma joined list.
+        * Multiline is ``False`` for lists.
+        * Obey list syntax for empty and single member lists.
+        
+        If ``list_values=False`` then the value is only quoted if it contains
+        a ``\\n`` (is multiline) or '#'.
+        
+        If ``write_empty_values`` is set, and the value is an empty string, it
+        won't be quoted.
+        """
+        if multiline and self.write_empty_values and value == '':
+            # Only if multiline is set, so that it is used for values not
+            # keys, and not values that are part of a list
+            return ''
+        
+        if multiline and isinstance(value, (list, tuple)):
+            if not value:
+                return ','
+            elif len(value) == 1:
+                return self._quote(value[0], multiline=False) + ','
+            return ', '.join([self._quote(val, multiline=False)
+                for val in value])
+        if not isinstance(value, basestring):
+            if self.stringify:
+                value = str(value)
+            else:
+                raise TypeError('Value "%s" is not a string.' % value)
+
+        if not value:
+            return '""'
+        
+        no_lists_no_quotes = not self.list_values and '\n' not in value and '#' not in value
+        need_triple = multiline and ((("'" in value) and ('"' in value)) or ('\n' in value ))
+        hash_triple_quote = multiline and not need_triple and ("'" in value) and ('"' in value) and ('#' in value)
+        check_for_single = (no_lists_no_quotes or not need_triple) and not hash_triple_quote
+        
+        if check_for_single:
+            if not self.list_values:
+                # we don't quote if ``list_values=False``
+                quot = noquot
+            # for normal values either single or double quotes will do
+            elif '\n' in value:
+                # will only happen if multiline is off - e.g. '\n' in key
+                raise ConfigObjError('Value "%s" cannot be safely quoted.' % value)
+            elif ((value[0] not in wspace_plus) and
+                    (value[-1] not in wspace_plus) and
+                    (',' not in value)):
+                quot = noquot
+            else:
+                quot = self._get_single_quote(value)
+        else:
+            # if value has '\n' or "'" *and* '"', it will need triple quotes
+            quot = self._get_triple_quote(value)
+        
+        if quot == noquot and '#' in value and self.list_values:
+            quot = self._get_single_quote(value)
+                
+        return quot % value
+    
+    
+    def _get_single_quote(self, value):
+        if ("'" in value) and ('"' in value):
+            raise ConfigObjError('Value "%s" cannot be safely quoted.' % value)
+        elif '"' in value:
+            quot = squot
+        else:
+            quot = dquot
+        return quot
+    
+    
+    def _get_triple_quote(self, value):
+        if (value.find('"""') != -1) and (value.find("'''") != -1):
+            raise ConfigObjError('Value "%s" cannot be safely quoted.' % value)
+        if value.find('"""') == -1:
+            quot = tdquot
+        else:
+            quot = tsquot 
+        return quot
+
+
+    def _handle_value(self, value):
+        """
+        Given a value string, unquote, remove comment,
+        handle lists. (including empty and single member lists)
+        """
+        if self._inspec:
+            # Parsing a configspec so don't handle comments
+            return (value, '')
+        # do we look for lists in values ?
+        if not self.list_values:
+            mat = self._nolistvalue.match(value)
+            if mat is None:
+                raise SyntaxError()
+            # NOTE: we don't unquote here
+            return mat.groups()
+        #
+        mat = self._valueexp.match(value)
+        if mat is None:
+            # the value is badly constructed, probably badly quoted,
+            # or an invalid list
+            raise SyntaxError()
+        (list_values, single, empty_list, comment) = mat.groups()
+        if (list_values == '') and (single is None):
+            # change this if you want to accept empty values
+            raise SyntaxError()
+        # NOTE: note there is no error handling from here if the regex
+        # is wrong: then incorrect values will slip through
+        if empty_list is not None:
+            # the single comma - meaning an empty list
+            return ([], comment)
+        if single is not None:
+            # handle empty values
+            if list_values and not single:
+                # FIXME: the '' is a workaround because our regex now matches
+                #   '' at the end of a list if it has a trailing comma
+                single = None
+            else:
+                single = single or '""'
+                single = self._unquote(single)
+        if list_values == '':
+            # not a list value
+            return (single, comment)
+        the_list = self._listvalueexp.findall(list_values)
+        the_list = [self._unquote(val) for val in the_list]
+        if single is not None:
+            the_list += [single]
+        return (the_list, comment)
+
+
+    def _multiline(self, value, infile, cur_index, maxline):
+        """Extract the value, where we are in a multiline situation."""
+        quot = value[:3]
+        newvalue = value[3:]
+        single_line = self._triple_quote[quot][0]
+        multi_line = self._triple_quote[quot][1]
+        mat = single_line.match(value)
+        if mat is not None:
+            retval = list(mat.groups())
+            retval.append(cur_index)
+            return retval
+        elif newvalue.find(quot) != -1:
+            # somehow the triple quote is missing
+            raise SyntaxError()
+        #
+        while cur_index < maxline:
+            cur_index += 1
+            newvalue += '\n'
+            line = infile[cur_index]
+            if line.find(quot) == -1:
+                newvalue += line
+            else:
+                # end of multiline, process it
+                break
+        else:
+            # we've got to the end of the config, oops...
+            raise SyntaxError()
+        mat = multi_line.match(line)
+        if mat is None:
+            # a badly formed line
+            raise SyntaxError()
+        (value, comment) = mat.groups()
+        return (newvalue + value, comment, cur_index)
+
+
+    def _handle_configspec(self, configspec):
+        """Parse the configspec."""
+        # FIXME: Should we check that the configspec was created with the 
+        #        correct settings ? (i.e. ``list_values=False``)
+        if not isinstance(configspec, ConfigObj):
+            try:
+                configspec = ConfigObj(configspec,
+                                       raise_errors=True,
+                                       file_error=True,
+                                       _inspec=True)
+            except ConfigObjError, e:
+                # FIXME: Should these errors have a reference
+                #        to the already parsed ConfigObj ?
+                raise ConfigspecError('Parsing configspec failed: %s' % e)
+            except IOError, e:
+                raise IOError('Reading configspec failed: %s' % e)
+        
+        self.configspec = configspec
+            
+
+        
+    def _set_configspec(self, section, copy):
+        """
+        Called by validate. Handles setting the configspec on subsections
+        including sections to be validated by __many__
+        """
+        configspec = section.configspec
+        many = configspec.get('__many__')
+        if isinstance(many, dict):
+            for entry in section.sections:
+                if entry not in configspec:
+                    section[entry].configspec = many
+                    
+        for entry in configspec.sections:
+            if entry == '__many__':
+                continue
+            if entry not in section:
+                section[entry] = {}
+                section[entry]._created = True
+                if copy:
+                    # copy comments
+                    section.comments[entry] = configspec.comments.get(entry, [])
+                    section.inline_comments[entry] = configspec.inline_comments.get(entry, '')
+                
+            # Could be a scalar when we expect a section
+            if isinstance(section[entry], Section):
+                section[entry].configspec = configspec[entry]
+                        
+
+    def _write_line(self, indent_string, entry, this_entry, comment):
+        """Write an individual line, for the write method"""
+        # NOTE: the calls to self._quote here handles non-StringType values.
+        if not self.unrepr:
+            val = self._decode_element(self._quote(this_entry))
+        else:
+            val = repr(this_entry)
+        return '%s%s%s%s%s' % (indent_string,
+                               self._decode_element(self._quote(entry, multiline=False)),
+                               self._a_to_u(' = '),
+                               val,
+                               self._decode_element(comment))
+
+
+    def _write_marker(self, indent_string, depth, entry, comment):
+        """Write a section marker line"""
+        return '%s%s%s%s%s' % (indent_string,
+                               self._a_to_u('[' * depth),
+                               self._quote(self._decode_element(entry), multiline=False),
+                               self._a_to_u(']' * depth),
+                               self._decode_element(comment))
+
+
+    def _handle_comment(self, comment):
+        """Deal with a comment."""
+        if not comment:
+            return ''
+        start = self.indent_type
+        if not comment.startswith('#'):
+            start += self._a_to_u(' # ')
+        return (start + comment)
+
+
+    # Public methods
+
+    def write(self, outfile=None, section=None):
+        """
+        Write the current ConfigObj as a file
+        
+        tekNico: FIXME: use StringIO instead of real files
+        
+        >>> filename = a.filename
+        >>> a.filename = 'test.ini'
+        >>> a.write()
+        >>> a.filename = filename
+        >>> a == ConfigObj('test.ini', raise_errors=True)
+        1
+        >>> import os
+        >>> os.remove('test.ini')
+        """
+        if self.indent_type is None:
+            # this can be true if initialised from a dictionary
+            self.indent_type = DEFAULT_INDENT_TYPE
+            
+        out = []
+        cs = self._a_to_u('#')
+        csp = self._a_to_u('# ')
+        if section is None:
+            int_val = self.interpolation
+            self.interpolation = False
+            section = self
+            for line in self.initial_comment:
+                line = self._decode_element(line)
+                stripped_line = line.strip()
+                if stripped_line and not stripped_line.startswith(cs):
+                    line = csp + line
+                out.append(line)
+                
+        indent_string = self.indent_type * section.depth
+        for entry in (section.scalars + section.sections):
+            if entry in section.defaults:
+                # don't write out default values
+                continue
+            for comment_line in section.comments[entry]:
+                comment_line = self._decode_element(comment_line.lstrip())
+                if comment_line and not comment_line.startswith(cs):
+                    comment_line = csp + comment_line
+                out.append(indent_string + comment_line)
+            this_entry = section[entry]
+            comment = self._handle_comment(section.inline_comments[entry])
+            
+            if isinstance(this_entry, dict):
+                # a section
+                out.append(self._write_marker(
+                    indent_string,
+                    this_entry.depth,
+                    entry,
+                    comment))
+                out.extend(self.write(section=this_entry))
+            else:
+                out.append(self._write_line(
+                    indent_string,
+                    entry,
+                    this_entry,
+                    comment))
+                
+        if section is self:
+            for line in self.final_comment:
+                line = self._decode_element(line)
+                stripped_line = line.strip()
+                if stripped_line and not stripped_line.startswith(cs):
+                    line = csp + line
+                out.append(line)
+            self.interpolation = int_val
+            
+        if section is not self:
+            return out
+        
+        if (self.filename is None) and (outfile is None):
+            # output a list of lines
+            # might need to encode
+            # NOTE: This will *screw* UTF16, each line will start with the BOM
+            if self.encoding:
+                out = [l.encode(self.encoding) for l in out]
+            if (self.BOM and ((self.encoding is None) or
+                (BOM_LIST.get(self.encoding.lower()) == 'utf_8'))):
+                # Add the UTF8 BOM
+                if not out:
+                    out.append('')
+                out[0] = BOM_UTF8 + out[0]
+            return out
+        
+        # Turn the list to a string, joined with correct newlines
+        newline = self.newlines or os.linesep
+        if (getattr(outfile, 'mode', None) is not None and outfile.mode == 'w'
+            and sys.platform == 'win32' and newline == '\r\n'):
+            # Windows specific hack to avoid writing '\r\r\n'
+            newline = '\n'
+        output = self._a_to_u(newline).join(out)
+        if self.encoding:
+            output = output.encode(self.encoding)
+        if self.BOM and ((self.encoding is None) or match_utf8(self.encoding)):
+            # Add the UTF8 BOM
+            output = BOM_UTF8 + output
+            
+        if not output.endswith(newline):
+            output += newline
+        if outfile is not None:
+            outfile.write(output)
+        else:
+            h = open(self.filename, 'wb')
+            h.write(output)
+            h.close()
+
+
+    def validate(self, validator, preserve_errors=False, copy=False,
+                 section=None):
+        """
+        Test the ConfigObj against a configspec.
+        
+        It uses the ``validator`` object from *validate.py*.
+        
+        To run ``validate`` on the current ConfigObj, call: ::
+        
+            test = config.validate(validator)
+        
+        (Normally having previously passed in the configspec when the ConfigObj
+        was created - you can dynamically assign a dictionary of checks to the
+        ``configspec`` attribute of a section though).
+        
+        It returns ``True`` if everything passes, or a dictionary of
+        pass/fails (True/False). If every member of a subsection passes, it
+        will just have the value ``True``. (It also returns ``False`` if all
+        members fail).
+        
+        In addition, it converts the values from strings to their native
+        types if their checks pass (and ``stringify`` is set).
+        
+        If ``preserve_errors`` is ``True`` (``False`` is default) then instead
+        of a marking a fail with a ``False``, it will preserve the actual
+        exception object. This can contain info about the reason for failure.
+        For example the ``VdtValueTooSmallError`` indicates that the value
+        supplied was too small. If a value (or section) is missing it will
+        still be marked as ``False``.
+        
+        You must have the validate module to use ``preserve_errors=True``.
+        
+        You can then use the ``flatten_errors`` function to turn your nested
+        results dictionary into a flattened list of failures - useful for
+        displaying meaningful error messages.
+        """
+        if section is None:
+            if self.configspec is None:
+                raise ValueError('No configspec supplied.')
+            if preserve_errors:
+                # We do this once to remove a top level dependency on the validate module
+                # Which makes importing configobj faster
+                from validate import VdtMissingValue
+                self._vdtMissingValue = VdtMissingValue
+                
+            section = self
+
+            if copy:
+                section.initial_comment = section.configspec.initial_comment
+                section.final_comment = section.configspec.final_comment
+                section.encoding = section.configspec.encoding
+                section.BOM = section.configspec.BOM
+                section.newlines = section.configspec.newlines
+                section.indent_type = section.configspec.indent_type
+            
+        #
+        # section.default_values.clear() #??
+        configspec = section.configspec
+        self._set_configspec(section, copy)
+
+        
+        def validate_entry(entry, spec, val, missing, ret_true, ret_false):
+            section.default_values.pop(entry, None)
+                
+            try:
+                section.default_values[entry] = validator.get_default_value(configspec[entry])
+            except (KeyError, AttributeError, validator.baseErrorClass):
+                # No default, bad default or validator has no 'get_default_value'
+                # (e.g. SimpleVal)
+                pass
+            
+            try:
+                check = validator.check(spec,
+                                        val,
+                                        missing=missing
+                                        )
+            except validator.baseErrorClass, e:
+                if not preserve_errors or isinstance(e, self._vdtMissingValue):
+                    out[entry] = False
+                else:
+                    # preserve the error
+                    out[entry] = e
+                    ret_false = False
+                ret_true = False
+            else:
+                ret_false = False
+                out[entry] = True
+                if self.stringify or missing:
+                    # if we are doing type conversion
+                    # or the value is a supplied default
+                    if not self.stringify:
+                        if isinstance(check, (list, tuple)):
+                            # preserve lists
+                            check = [self._str(item) for item in check]
+                        elif missing and check is None:
+                            # convert the None from a default to a ''
+                            check = ''
+                        else:
+                            check = self._str(check)
+                    if (check != val) or missing:
+                        section[entry] = check
+                if not copy and missing and entry not in section.defaults:
+                    section.defaults.append(entry)
+            return ret_true, ret_false
+        
+        #
+        out = {}
+        ret_true = True
+        ret_false = True
+        
+        unvalidated = [k for k in section.scalars if k not in configspec]
+        incorrect_sections = [k for k in configspec.sections if k in section.scalars]        
+        incorrect_scalars = [k for k in configspec.scalars if k in section.sections]
+        
+        for entry in configspec.scalars:
+            if entry in ('__many__', '___many___'):
+                # reserved names
+                continue
+            if (not entry in section.scalars) or (entry in section.defaults):
+                # missing entries
+                # or entries from defaults
+                missing = True
+                val = None
+                if copy and entry not in section.scalars:
+                    # copy comments
+                    section.comments[entry] = (
+                        configspec.comments.get(entry, []))
+                    section.inline_comments[entry] = (
+                        configspec.inline_comments.get(entry, ''))
+                #
+            else:
+                missing = False
+                val = section[entry]
+            
+            ret_true, ret_false = validate_entry(entry, configspec[entry], val, 
+                                                 missing, ret_true, ret_false)
+        
+        many = None
+        if '__many__' in configspec.scalars:
+            many = configspec['__many__']
+        elif '___many___' in configspec.scalars:
+            many = configspec['___many___']
+        
+        if many is not None:
+            for entry in unvalidated:
+                val = section[entry]
+                ret_true, ret_false = validate_entry(entry, many, val, False,
+                                                     ret_true, ret_false)
+            unvalidated = []
+
+        for entry in incorrect_scalars:
+            ret_true = False
+            if not preserve_errors:
+                out[entry] = False
+            else:
+                ret_false = False
+                msg = 'Value %r was provided as a section' % entry
+                out[entry] = validator.baseErrorClass(msg)
+        for entry in incorrect_sections:
+            ret_true = False
+            if not preserve_errors:
+                out[entry] = False
+            else:
+                ret_false = False
+                msg = 'Section %r was provided as a single value' % entry
+                out[entry] = validator.baseErrorClass(msg)
+                
+        # Missing sections will have been created as empty ones when the
+        # configspec was read.
+        for entry in section.sections:
+            # FIXME: this means DEFAULT is not copied in copy mode
+            if section is self and entry == 'DEFAULT':
+                continue
+            if section[entry].configspec is None:
+                unvalidated.append(entry)
+                continue
+            if copy:
+                section.comments[entry] = configspec.comments.get(entry, [])
+                section.inline_comments[entry] = configspec.inline_comments.get(entry, '')
+            check = self.validate(validator, preserve_errors=preserve_errors, copy=copy, section=section[entry])
+            out[entry] = check
+            if check == False:
+                ret_true = False
+            elif check == True:
+                ret_false = False
+            else:
+                ret_true = False
+        
+        section.extra_values = unvalidated
+        if preserve_errors and not section._created:
+            # If the section wasn't created (i.e. it wasn't missing)
+            # then we can't return False, we need to preserve errors
+            ret_false = False
+        #
+        if ret_false and preserve_errors and out:
+            # If we are preserving errors, but all
+            # the failures are from missing sections / values
+            # then we can return False. Otherwise there is a
+            # real failure that we need to preserve.
+            ret_false = not any(out.values())
+        if ret_true:
+            return True
+        elif ret_false:
+            return False
+        return out
+
+
+    def reset(self):
+        """Clear ConfigObj instance and restore to 'freshly created' state."""
+        self.clear()
+        self._initialise()
+        # FIXME: Should be done by '_initialise', but ConfigObj constructor (and reload)
+        #        requires an empty dictionary
+        self.configspec = None
+        # Just to be sure ;-)
+        self._original_configspec = None
+        
+        
+    def reload(self):
+        """
+        Reload a ConfigObj from file.
+        
+        This method raises a ``ReloadError`` if the ConfigObj doesn't have
+        a filename attribute pointing to a file.
+        """
+        if not isinstance(self.filename, basestring):
+            raise ReloadError()
+
+        filename = self.filename
+        current_options = {}
+        for entry in OPTION_DEFAULTS:
+            if entry == 'configspec':
+                continue
+            current_options[entry] = getattr(self, entry)
+            
+        configspec = self._original_configspec
+        current_options['configspec'] = configspec
+            
+        self.clear()
+        self._initialise(current_options)
+        self._load(filename, configspec)
+        
+
+
+class SimpleVal(object):
+    """
+    A simple validator.
+    Can be used to check that all members expected are present.
+    
+    To use it, provide a configspec with all your members in (the value given
+    will be ignored). Pass an instance of ``SimpleVal`` to the ``validate``
+    method of your ``ConfigObj``. ``validate`` will return ``True`` if all
+    members are present, or a dictionary with True/False meaning
+    present/missing. (Whole missing sections will be replaced with ``False``)
+    """
+    
+    def __init__(self):
+        self.baseErrorClass = ConfigObjError
+    
+    def check(self, check, member, missing=False):
+        """A dummy check method, always returns the value unchanged."""
+        if missing:
+            raise self.baseErrorClass()
+        return member
+
+
+def flatten_errors(cfg, res, levels=None, results=None):
+    """
+    An example function that will turn a nested dictionary of results
+    (as returned by ``ConfigObj.validate``) into a flat list.
+    
+    ``cfg`` is the ConfigObj instance being checked, ``res`` is the results
+    dictionary returned by ``validate``.
+    
+    (This is a recursive function, so you shouldn't use the ``levels`` or
+    ``results`` arguments - they are used by the function.)
+    
+    Returns a list of keys that failed. Each member of the list is a tuple::
+    
+        ([list of sections...], key, result)
+    
+    If ``validate`` was called with ``preserve_errors=False`` (the default)
+    then ``result`` will always be ``False``.
+
+    *list of sections* is a flattened list of sections that the key was found
+    in.
+    
+    If the section was missing (or a section was expected and a scalar provided
+    - or vice-versa) then key will be ``None``.
+    
+    If the value (or section) was missing then ``result`` will be ``False``.
+    
+    If ``validate`` was called with ``preserve_errors=True`` and a value
+    was present, but failed the check, then ``result`` will be the exception
+    object returned. You can use this as a string that describes the failure.
+    
+    For example *The value "3" is of the wrong type*.
+    """
+    if levels is None:
+        # first time called
+        levels = []
+        results = []
+    if res == True:
+        return results
+    if res == False or isinstance(res, Exception):
+        results.append((levels[:], None, res))
+        if levels:
+            levels.pop()
+        return results
+    for (key, val) in res.items():
+        if val == True:
+            continue
+        if isinstance(cfg.get(key), dict):
+            # Go down one level
+            levels.append(key)
+            flatten_errors(cfg[key], val, levels, results)
+            continue
+        results.append((levels[:], key, val))
+    #
+    # Go up one level
+    if levels:
+        levels.pop()
+    #
+    return results
+
+
+def get_extra_values(conf, _prepend=()):
+    """
+    Find all the values and sections not in the configspec from a validated
+    ConfigObj.
+    
+    ``get_extra_values`` returns a list of tuples where each tuple represents
+    either an extra section, or an extra value.
+    
+    The tuples contain two values, a tuple representing the section the value 
+    is in and the name of the extra values. For extra values in the top level
+    section the first member will be an empty tuple. For values in the 'foo'
+    section the first member will be ``('foo',)``. For members in the 'bar'
+    subsection of the 'foo' section the first member will be ``('foo', 'bar')``.
+    
+    NOTE: If you call ``get_extra_values`` on a ConfigObj instance that hasn't
+    been validated it will return an empty list.
+    """
+    out = []
+    
+    out.extend([(_prepend, name) for name in conf.extra_values])
+    for name in conf.sections:
+        if name not in conf.extra_values:
+            out.extend(get_extra_values(conf[name], _prepend + (name,)))
+    return out
+
+
+"""*A programming language is a medium of expression.* - Paul Graham"""
diff --git a/python/pkg/cdec/sa/__init__.py b/python/pkg/cdec/sa/__init__.py
new file mode 100644
index 00000000..fd4a4148
--- /dev/null
+++ b/python/pkg/cdec/sa/__init__.py
@@ -0,0 +1,4 @@
+from cdec.sa._sa import sym_fromstring,\
+        SuffixArray, DataArray, LCP, Precomputation, Alignment, BiLex,\
+        HieroCachingRuleFactory, Sampler
+from cdec.sa.extractor import GrammarExtractor
diff --git a/python/pkg/cdec/sa/compile.py b/python/pkg/cdec/sa/compile.py
new file mode 100644
index 00000000..30e605a6
--- /dev/null
+++ b/python/pkg/cdec/sa/compile.py
@@ -0,0 +1,94 @@
+#!/usr/bin/env python
+import argparse
+import os
+import logging
+import cdec.configobj
+import cdec.sa
+
+MAX_PHRASE_LENGTH = 4
+def precompute(f_sa, max_len, max_nt, max_size, min_gap, rank1, rank2):
+    lcp = cdec.sa.LCP(f_sa)
+    stats = sorted(lcp.compute_stats(MAX_PHRASE_LENGTH), reverse=True)
+    precomp = cdec.sa.Precomputation(from_stats=stats,
+            fsarray=f_sa,
+            precompute_rank=rank1,
+            precompute_secondary_rank=rank2,
+            max_length=max_len,
+            max_nonterminals=max_nt,
+            train_max_initial_size=max_size,
+            train_min_gap_size=min_gap)
+    return precomp
+
+def main():
+    logging.basicConfig(level=logging.INFO)
+    logger = logging.getLogger('cdec.sa.compile')
+    parser = argparse.ArgumentParser(description='Compile a corpus into a suffix array.')
+    parser.add_argument('--maxnt', '-n', type=int, default=2,
+                        help='Maximum number of non-terminal symbols')
+    parser.add_argument('--maxlen', '-l', type=int, default=5,
+                        help='Maximum number of terminals')
+    parser.add_argument('--maxsize', '-s', type=int, default=15,
+                        help='Maximum rule span')
+    parser.add_argument('--mingap', '-g', type=int, default=1,
+                        help='Minimum gap size')
+    parser.add_argument('--rank1', '-r1', type=int, default=100,
+                        help='Number of pre-computed frequent patterns')
+    parser.add_argument('--rank2', '-r2', type=int, default=10,
+                        help='Number of pre-computed super-frequent patterns)')
+    parser.add_argument('-c', '--config', default='/dev/stdout',
+                        help='Output configuration')
+    parser.add_argument('-o', '--output', required=True,
+                        help='Output path')
+    parser.add_argument('-f', '--source', required=True,
+                        help='Source language corpus')
+    parser.add_argument('-e', '--target', required=True,
+                        help='Target language corpus')
+    parser.add_argument('-a', '--alignment', required=True,
+                        help='Bitext word alignment')
+    args = parser.parse_args()
+
+    param_names = ("max_len", "max_nt", "max_size", "min_gap", "rank1", "rank2")
+    params = (args.maxlen, args.maxnt, args.maxsize, args.mingap, args.rank1, args.rank2)
+
+    if not os.path.exists(args.output):
+        os.mkdir(args.output)
+
+    f_sa_bin = os.path.join(args.output, 'f.sa.bin')
+    e_bin = os.path.join(args.output, 'e.bin')
+    precomp_file = 'precomp.{0}.{1}.{2}.{3}.{4}.{5}.bin'.format(*params)
+    precomp_bin = os.path.join(args.output, precomp_file)
+    a_bin = os.path.join(args.output, 'a.bin')
+    lex_bin = os.path.join(args.output, 'lex.bin')
+
+    logger.info('Compiling source suffix array')
+    f_sa = cdec.sa.SuffixArray(from_text=args.source)
+    f_sa.write_binary(f_sa_bin)
+
+    logger.info('Compiling target data array')
+    e = cdec.sa.DataArray(from_text=args.target)
+    e.write_binary(e_bin)
+
+    logger.info('Precomputing frequent phrases')
+    precompute(f_sa, *params).write_binary(precomp_bin)
+
+    logger.info('Compiling alignment')
+    a = cdec.sa.Alignment(from_text=args.alignment)
+    a.write_binary(a_bin)
+
+    logger.info('Compiling bilexical dictionary')
+    lex = cdec.sa.BiLex(from_data=True, alignment=a, earray=e, fsarray=f_sa)
+    lex.write_binary(lex_bin)
+    
+    # Write configuration
+    config = cdec.configobj.ConfigObj(args.config, unrepr=True)
+    config['f_sa_file'] = f_sa_bin
+    config['e_file'] = e_bin
+    config['a_file'] = a_bin
+    config['lex_file'] = lex_bin
+    config['precompute_file'] = precomp_bin
+    for name, value in zip(param_names, params):
+        config[name] = value
+    config.write()
+
+if __name__ == '__main__':
+    main()
diff --git a/python/pkg/cdec/sa/extract.py b/python/pkg/cdec/sa/extract.py
new file mode 100644
index 00000000..918aa3bb
--- /dev/null
+++ b/python/pkg/cdec/sa/extract.py
@@ -0,0 +1,31 @@
+#!/usr/bin/env python
+import sys
+import os
+import argparse
+import logging
+import cdec.sa
+
+def main():
+    logging.basicConfig(level=logging.INFO)
+    parser = argparse.ArgumentParser(description='Extract grammars from a compiled corpus.')
+    parser.add_argument('-c', '--config', required=True,
+                        help='Extractor configuration')
+    parser.add_argument('-g', '--grammars', required=True,
+                        help='Grammar output path')
+    args = parser.parse_args()
+
+    if not os.path.exists(args.grammars):
+        os.mkdir(args.grammars)
+
+    extractor = cdec.sa.GrammarExtractor(args.config)
+    for i, sentence in enumerate(sys.stdin):
+        sentence = sentence[:-1]
+        grammar_file = os.path.join(args.grammars, 'grammar.{0}'.format(i))
+        with open(grammar_file, 'w') as output:
+            for rule in extractor.grammar(sentence):
+                output.write(str(rule)+'\n')
+        grammar_file = os.path.abspath(grammar_file)
+        print('<seg grammar="{0}">{1}</seg>'.format(grammar_file, sentence))
+
+if __name__ == '__main__':
+    main()
diff --git a/python/pkg/cdec/sa/extractor.py b/python/pkg/cdec/sa/extractor.py
new file mode 100644
index 00000000..bb912e16
--- /dev/null
+++ b/python/pkg/cdec/sa/extractor.py
@@ -0,0 +1,78 @@
+from itertools import chain
+import os
+import cdec.configobj
+from cdec.sa.features import EgivenFCoherent, SampleCountF, CountEF,\
+        MaxLexEgivenF, MaxLexFgivenE, IsSingletonF, IsSingletonFE
+import cdec.sa
+
+# maximum span of a grammar rule in TEST DATA
+MAX_INITIAL_SIZE = 15
+
+class GrammarExtractor:
+    def __init__(self, config):
+        if isinstance(config, str) or isinstance(config, unicode):
+            if not os.path.exists(config):
+                raise IOError('cannot read configuration from {0}'.format(config))
+            config = cdec.configobj.ConfigObj(config, unrepr=True)
+        alignment = cdec.sa.Alignment(from_binary=config['a_file'])
+        self.factory = cdec.sa.HieroCachingRuleFactory(
+                # compiled alignment object (REQUIRED)
+                alignment,
+                # name of generic nonterminal used by Hiero
+                category="[X]",
+                # maximum number of contiguous chunks of terminal symbols in RHS of a rule
+                max_chunks=config['max_nt']+1,
+                # maximum span of a grammar rule in TEST DATA
+                max_initial_size=MAX_INITIAL_SIZE,
+                # maximum number of symbols (both T and NT) allowed in a rule
+                max_length=config['max_len'],
+                # maximum number of nonterminals allowed in a rule (set >2 at your own risk)
+                max_nonterminals=config['max_nt'],
+                # maximum number of contiguous chunks of terminal symbols
+                # in target-side RHS of a rule.
+                max_target_chunks=config['max_nt']+1,
+                # maximum number of target side symbols (both T and NT) allowed in a rule.
+                max_target_length=MAX_INITIAL_SIZE,
+                # minimum span of a nonterminal in the RHS of a rule in TEST DATA
+                min_gap_size=1,
+                # filename of file containing precomputed collocations
+                precompute_file=config['precompute_file'],
+                # maximum frequency rank of patterns used to compute triples (< 20)
+                precompute_secondary_rank=config['rank2'],
+                # maximum frequency rank of patterns used to compute collocations (< 300)
+                precompute_rank=config['rank1'],
+                # require extracted rules to have at least one aligned word
+                require_aligned_terminal=True,
+                # require each contiguous chunk of extracted rules
+                # to have at least one aligned word
+                require_aligned_chunks=False,
+                # maximum span of a grammar rule extracted from TRAINING DATA
+                train_max_initial_size=config['max_size'],
+                # minimum span of an RHS nonterminal in a rule extracted from TRAINING DATA
+                train_min_gap_size=config['min_gap'],
+                # True if phrases should be tight, False otherwise (better but slower)
+                tight_phrases=True,
+                )
+
+        # lexical weighting tables
+        tt = cdec.sa.BiLex(from_binary=config['lex_file'])
+
+        self.models = (EgivenFCoherent, SampleCountF, CountEF, 
+                MaxLexFgivenE(tt), MaxLexEgivenF(tt), IsSingletonF, IsSingletonFE)
+
+        fsarray = cdec.sa.SuffixArray(from_binary=config['f_sa_file'])
+        edarray = cdec.sa.DataArray(from_binary=config['e_file'])
+
+        # lower=faster, higher=better; improvements level off above 200-300 range,
+        # -1 = don't sample, use all data (VERY SLOW!)
+        sampler = cdec.sa.Sampler(300, fsarray)
+
+        self.factory.configure(fsarray, edarray, sampler)
+
+    def grammar(self, sentence):
+        if isinstance(sentence, unicode):
+            sentence = sentence.encode('utf8')
+        cnet = chain(('<s>',), sentence.split(), ('</s>',))
+        cnet = (cdec.sa.sym_fromstring(word, terminal=True) for word in cnet)
+        cnet = tuple(((word, None, 1), ) for word in cnet)
+        return self.factory.input(cnet, self.models)
diff --git a/python/pkg/cdec/sa/features.py b/python/pkg/cdec/sa/features.py
new file mode 100644
index 00000000..325b9e13
--- /dev/null
+++ b/python/pkg/cdec/sa/features.py
@@ -0,0 +1,57 @@
+from __future__ import division
+import math
+
+MAXSCORE = 99
+
+def EgivenF(fphrase, ephrase, paircount, fcount, fsample_count): # p(e|f)
+    return -math.log10(paircount/fcount)
+
+def CountEF(fphrase, ephrase, paircount, fcount, fsample_count):
+    return math.log10(1 + paircount)
+
+def SampleCountF(fphrase, ephrase, paircount, fcount, fsample_count):
+    return math.log10(1 + fsample_count)
+
+def EgivenFCoherent(fphrase, ephrase, paircount, fcount, fsample_count):
+    prob = paircount/fsample_count
+    return -math.log10(prob) if prob > 0 else MAXSCORE
+
+def CoherenceProb(fphrase, ephrase, paircount, fcount, fsample_count):
+    return -math.log10(fcount/fsample_count)
+
+def MaxLexEgivenF(ttable):
+    def feature(fphrase, ephrase, paircount, fcount, fsample_count):
+        fwords = fphrase.words
+        fwords.append('NULL')
+        def score():
+            for e in ephrase.words:
+              maxScore = max(ttable.get_score(f, e, 0) for f in fwords)
+              yield -math.log10(maxScore) if maxScore > 0 else MAXSCORE
+        return sum(score())
+    return feature
+
+def MaxLexFgivenE(ttable):
+    def feature(fphrase, ephrase, paircount, fcount, fsample_count):
+        ewords = ephrase.words
+        ewords.append('NULL')
+        def score():
+            for f in fphrase.words:
+              maxScore = max(ttable.get_score(f, e, 1) for e in ewords)
+              yield -math.log10(maxScore) if maxScore > 0 else MAXSCORE
+        return sum(score())
+    return feature
+
+def IsSingletonF(fphrase, ephrase, paircount, fcount, fsample_count):
+    return (fcount == 1)
+
+def IsSingletonFE(fphrase, ephrase, paircount, fcount, fsample_count):
+    return (paircount == 1)
+
+def IsNotSingletonF(fphrase, ephrase, paircount, fcount, fsample_count):
+    return (fcount > 1)
+
+def IsNotSingletonFE(fphrase, ephrase, paircount, fcount, fsample_count):
+    return (paircount > 1)
+
+def IsFEGreaterThanZero(fphrase, ephrase, paircount, fcount, fsample_count):
+    return (paircount > 0.01)
diff --git a/python/pkg/cdec/score.py b/python/pkg/cdec/score.py
new file mode 100644
index 00000000..22257774
--- /dev/null
+++ b/python/pkg/cdec/score.py
@@ -0,0 +1 @@
+from _cdec import BLEU, TER, CER, Metric
diff --git a/python/setup.py b/python/setup.py
index 1d1d7e45..7be976e8 100644
--- a/python/setup.py
+++ b/python/setup.py
@@ -48,5 +48,6 @@ setup(
     name='cdec',
     ext_modules=ext_modules,
     requires=['configobj'],
-    packages=['cdec', 'cdec.sa']
+    packages=['cdec', 'cdec.sa'],
+    package_dir={'': 'pkg'}
 )
diff --git a/python/src/sa/_sa.c b/python/src/sa/_sa.c
index 34f170bf..b7f3627a 100644
--- a/python/src/sa/_sa.c
+++ b/python/src/sa/_sa.c
@@ -1,4 +1,4 @@
-/* Generated by Cython 0.17.beta1 on Fri Jul 27 22:15:31 2012 */
+/* Generated by Cython 0.17.beta1 on Fri Jul 27 23:31:04 2012 */
 
 #define PY_SSIZE_T_CLEAN
 #include "Python.h"
@@ -2013,7 +2013,7 @@ static int __pyx_pf_3_sa_8Alphabet___cinit__(struct __pyx_obj_3_sa_Alphabet *__p
 static void __pyx_pf_3_sa_8Alphabet_2__dealloc__(CYTHON_UNUSED struct __pyx_obj_3_sa_Alphabet *__pyx_v_self); /* proto */
 static PyObject *__pyx_pf_3_sa_8Alphabet_9terminals___get__(struct __pyx_obj_3_sa_Alphabet *__pyx_v_self); /* proto */
 static PyObject *__pyx_pf_3_sa_8Alphabet_12nonterminals___get__(struct __pyx_obj_3_sa_Alphabet *__pyx_v_self); /* proto */
-static PyObject *__pyx_pf_3_sa_2sym_fromstring(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_string, int __pyx_v_terminal); /* proto */
+static PyObject *__pyx_pf_3_sa_2sym_fromstring(CYTHON_UNUSED PyObject *__pyx_self, char *__pyx_v_string, int __pyx_v_terminal); /* proto */
 static int __pyx_pf_3_sa_6Phrase___cinit__(struct __pyx_obj_3_sa_Phrase *__pyx_v_self, PyObject *__pyx_v_words); /* proto */
 static void __pyx_pf_3_sa_6Phrase_2__dealloc__(struct __pyx_obj_3_sa_Phrase *__pyx_v_self); /* proto */
 static PyObject *__pyx_pf_3_sa_6Phrase_4__str__(struct __pyx_obj_3_sa_Phrase *__pyx_v_self); /* proto */
@@ -21750,7 +21750,7 @@ static int __pyx_f_3_sa_sym_setindex(int __pyx_v_sym, int __pyx_v_id) {
  * cdef int sym_setindex(int sym, int id):
  *     return ALPHABET.setindex(sym, id)             # <<<<<<<<<<<<<<
  * 
- * def sym_fromstring(bytes string, bint terminal):
+ * def sym_fromstring(char* string, bint terminal):
  */
   __pyx_r = ((struct __pyx_vtabstruct_3_sa_Alphabet *)__pyx_v_3_sa_ALPHABET->__pyx_vtab)->setindex(__pyx_v_3_sa_ALPHABET, __pyx_v_sym, __pyx_v_id);
   goto __pyx_L0;
@@ -21765,7 +21765,7 @@ static int __pyx_f_3_sa_sym_setindex(int __pyx_v_sym, int __pyx_v_id) {
 static PyObject *__pyx_pw_3_sa_3sym_fromstring(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/
 static PyMethodDef __pyx_mdef_3_sa_3sym_fromstring = {__Pyx_NAMESTR("sym_fromstring"), (PyCFunction)__pyx_pw_3_sa_3sym_fromstring, METH_VARARGS|METH_KEYWORDS, __Pyx_DOCSTR(0)};
 static PyObject *__pyx_pw_3_sa_3sym_fromstring(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds) {
-  PyObject *__pyx_v_string = 0;
+  char *__pyx_v_string;
   int __pyx_v_terminal;
   PyObject *__pyx_r = 0;
   __Pyx_RefNannyDeclarations
@@ -21802,7 +21802,7 @@ static PyObject *__pyx_pw_3_sa_3sym_fromstring(PyObject *__pyx_self, PyObject *_
       values[0] = PyTuple_GET_ITEM(__pyx_args, 0);
       values[1] = PyTuple_GET_ITEM(__pyx_args, 1);
     }
-    __pyx_v_string = ((PyObject*)values[0]);
+    __pyx_v_string = PyBytes_AsString(values[0]); if (unlikely((!__pyx_v_string) && PyErr_Occurred())) {__pyx_filename = __pyx_f[10]; __pyx_lineno = 104; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
     __pyx_v_terminal = __Pyx_PyObject_IsTrue(values[1]); if (unlikely((__pyx_v_terminal == (int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[10]; __pyx_lineno = 104; __pyx_clineno = __LINE__; goto __pyx_L3_error;}
   }
   goto __pyx_L4_argument_unpacking_done;
@@ -21813,12 +21813,7 @@ static PyObject *__pyx_pw_3_sa_3sym_fromstring(PyObject *__pyx_self, PyObject *_
   __Pyx_RefNannyFinishContext();
   return NULL;
   __pyx_L4_argument_unpacking_done:;
-  if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_string), (&PyBytes_Type), 1, "string", 1))) {__pyx_filename = __pyx_f[10]; __pyx_lineno = 104; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
   __pyx_r = __pyx_pf_3_sa_2sym_fromstring(__pyx_self, __pyx_v_string, __pyx_v_terminal);
-  goto __pyx_L0;
-  __pyx_L1_error:;
-  __pyx_r = NULL;
-  __pyx_L0:;
   __Pyx_RefNannyFinishContext();
   return __pyx_r;
 }
@@ -21826,15 +21821,14 @@ static PyObject *__pyx_pw_3_sa_3sym_fromstring(PyObject *__pyx_self, PyObject *_
 /* "/Users/vchahun/Sandbox/cdec/python/src/sa/sym.pxi":104
  *     return ALPHABET.setindex(sym, id)
  * 
- * def sym_fromstring(bytes string, bint terminal):             # <<<<<<<<<<<<<<
+ * def sym_fromstring(char* string, bint terminal):             # <<<<<<<<<<<<<<
  *     return ALPHABET.fromstring(string, terminal)
  */
 
-static PyObject *__pyx_pf_3_sa_2sym_fromstring(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_string, int __pyx_v_terminal) {
+static PyObject *__pyx_pf_3_sa_2sym_fromstring(CYTHON_UNUSED PyObject *__pyx_self, char *__pyx_v_string, int __pyx_v_terminal) {
   PyObject *__pyx_r = NULL;
   __Pyx_RefNannyDeclarations
-  char *__pyx_t_1;
-  PyObject *__pyx_t_2 = NULL;
+  PyObject *__pyx_t_1 = NULL;
   int __pyx_lineno = 0;
   const char *__pyx_filename = NULL;
   int __pyx_clineno = 0;
@@ -21842,21 +21836,20 @@ static PyObject *__pyx_pf_3_sa_2sym_fromstring(CYTHON_UNUSED PyObject *__pyx_sel
 
   /* "/Users/vchahun/Sandbox/cdec/python/src/sa/sym.pxi":105
  * 
- * def sym_fromstring(bytes string, bint terminal):
+ * def sym_fromstring(char* string, bint terminal):
  *     return ALPHABET.fromstring(string, terminal)             # <<<<<<<<<<<<<<
  */
   __Pyx_XDECREF(__pyx_r);
-  __pyx_t_1 = PyBytes_AsString(((PyObject *)__pyx_v_string)); if (unlikely((!__pyx_t_1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[10]; __pyx_lineno = 105; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __pyx_t_2 = PyInt_FromLong(((struct __pyx_vtabstruct_3_sa_Alphabet *)__pyx_v_3_sa_ALPHABET->__pyx_vtab)->fromstring(__pyx_v_3_sa_ALPHABET, __pyx_t_1, __pyx_v_terminal)); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[10]; __pyx_lineno = 105; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
-  __Pyx_GOTREF(__pyx_t_2);
-  __pyx_r = __pyx_t_2;
-  __pyx_t_2 = 0;
+  __pyx_t_1 = PyInt_FromLong(((struct __pyx_vtabstruct_3_sa_Alphabet *)__pyx_v_3_sa_ALPHABET->__pyx_vtab)->fromstring(__pyx_v_3_sa_ALPHABET, __pyx_v_string, __pyx_v_terminal)); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[10]; __pyx_lineno = 105; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
+  __Pyx_GOTREF(__pyx_t_1);
+  __pyx_r = __pyx_t_1;
+  __pyx_t_1 = 0;
   goto __pyx_L0;
 
   __pyx_r = Py_None; __Pyx_INCREF(Py_None);
   goto __pyx_L0;
   __pyx_L1_error:;
-  __Pyx_XDECREF(__pyx_t_2);
+  __Pyx_XDECREF(__pyx_t_1);
   __Pyx_AddTraceback("_sa.sym_fromstring", __pyx_clineno, __pyx_lineno, __pyx_filename);
   __pyx_r = NULL;
   __pyx_L0:;
@@ -60511,7 +60504,7 @@ static int __Pyx_InitCachedConstants(void) {
   /* "/Users/vchahun/Sandbox/cdec/python/src/sa/sym.pxi":104
  *     return ALPHABET.setindex(sym, id)
  * 
- * def sym_fromstring(bytes string, bint terminal):             # <<<<<<<<<<<<<<
+ * def sym_fromstring(char* string, bint terminal):             # <<<<<<<<<<<<<<
  *     return ALPHABET.fromstring(string, terminal)
  */
   __pyx_k_tuple_137 = PyTuple_New(2); if (unlikely(!__pyx_k_tuple_137)) {__pyx_filename = __pyx_f[10]; __pyx_lineno = 104; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
@@ -60933,7 +60926,7 @@ PyMODINIT_FUNC PyInit__sa(void)
   /* "/Users/vchahun/Sandbox/cdec/python/src/sa/sym.pxi":104
  *     return ALPHABET.setindex(sym, id)
  * 
- * def sym_fromstring(bytes string, bint terminal):             # <<<<<<<<<<<<<<
+ * def sym_fromstring(char* string, bint terminal):             # <<<<<<<<<<<<<<
  *     return ALPHABET.fromstring(string, terminal)
  */
   __pyx_t_1 = PyCFunction_NewEx(&__pyx_mdef_3_sa_3sym_fromstring, NULL, __pyx_n_s___sa); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[10]; __pyx_lineno = 104; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
diff --git a/python/src/sa/sym.pxi b/python/src/sa/sym.pxi
index 4b41886f..132925f6 100644
--- a/python/src/sa/sym.pxi
+++ b/python/src/sa/sym.pxi
@@ -101,5 +101,5 @@ cdef int sym_getindex(int sym):
 cdef int sym_setindex(int sym, int id):
     return ALPHABET.setindex(sym, id)
 
-def sym_fromstring(bytes string, bint terminal):
+def sym_fromstring(char* string, bint terminal):
     return ALPHABET.fromstring(string, terminal)
-- 
cgit v1.2.3