class BaseSenser(object):
    """Abstract class for sense disambiguation of connectives.

    Attributes:
      explicit (or None):
        classifier for predicting senses of explicit connectives
      implicit (or None):
        classifier for predicting senses of implicit connectives

    """

    def __init__(self):
        """Class constructor.

        """
        self.explicit = None
        self.implicit = None

    def train(self, a_train_data, a_dev_data=None, a_n_y=-1,
              a_i=-1, a_train_out=None, a_dev_out=None):
        """Method for training the model.

        Args:
          a_train_data (2-tuple(list, dict)):
            list of gold relations and dict with parses
          a_dev_data (2-tuple(list, dict) or None):
            list of development relations and dict with parses
          a_n_y (int):
            number of distinct classes
          a_i (int):
            row index for the output predictions
          a_train_out (np.array or None):
            predictions for the training set
          a_dev_out (np.array or None):
            predictions for the training set

        Returns:
          void:

        """
        self.n_y = a_n_y
        explicit_train, implicit_train = self._divide_ds(a_train_data)
        explicit_dev, implicit_dev = self._divide_ds(a_dev_data)
        self.implicit.train(implicit_train, implicit_dev, a_n_y,
                            a_i, a_train_out, a_dev_out)
        self.explicit.train(explicit_train, explicit_dev, a_n_y,
                            a_i, a_train_out, a_dev_out)

    def batch_predict(self, a_rels, a_data, a_ret):
        """Method for predicting sense of multiple relations.

        Args:
          a_rels (list):
            list of input relations
          a_data (2-tuple(dict, dict)):
            list of input JSON data
          a_ret (np.array):
            prediction matrix

        Returns:
          void:

        Note:
          modifies ``a_ret`` in place

        """
        for i, irel in enumerate(a_rels):
            self.predict(irel, a_data, a_ret, i)

    def predict(self, a_rel, a_data, a_ret, a_i):
        """Method for predicting sense of single relation.

        Args:
          a_rel (dict):
            discourse relation whose sense should be predicted
          a_data (2-tuple(dict, dict)):
            list of input JSON data
          a_ret (np.array):
            output prediction vector
          a_i (int):
            row index in the output vector

        Returns:
          void:

        Note:
          modifies ``a_ret[a_i]`` in place

        """
        if is_explicit(a_rel):
            return self.explicit.predict(a_rel, a_data, a_ret, a_i)
        return self.implicit.predict(a_rel, a_data, a_ret, a_i)

    def _free(self):
        """Free resources used by the model.

        """
        del self.explicit
        del self.implicit
        self.n_y = -1

    def _divide_ds(self, a_ds):
        """Separate dataset into explicit and implicit instances.

        Args:
          a_ds (tuple):
            list of gold relations and dict with parses

        Returns:
          tuple:
            trainings set with explicit and implicit connectives

        """
        if not a_ds:
            return (([], {}), ([], {}))
        explicit_instances = []
        implicit_instances = []
        for i, irel in enumerate(a_ds[0]):
            if is_explicit(irel):
                explicit_instances.append((i, irel))
            else:
                implicit_instances.append((i, irel))
        ret = ((explicit_instances, a_ds[1]),
               (implicit_instances, a_ds[1]))
        return ret

    def _normalize_conn(self, a_conn):
        """Normalize connective form.

        Args:
          a_conn (str):
            connectve to be normalized

        Returns:
          str: normalized connective

        """
        a_conn = a_conn.strip().lower()
        if a_conn:
            return CHM.map_raw_connective(a_conn)[0]
        return a_conn

    def _get_toks_pos(self, a_parses, a_rel, a_arg):
        """Method for getting raw tokens with their parts of speech.

        Args:
          a_parses (dict):
            parsed sentences
          a_rel (dict):
            discourse relation whose tokens should be obtained
          a_arg (str):
            relation argument to obtain senses for

        Returns:
          list: list of tokens and their parts of speech

        """
        ret = []
        snt = wrd = None
        for s_id, w_ids in \
                self._get_snt2tok(a_rel[a_arg][TOK_LIST]).iteritems():
            snt = a_parses[s_id][WORDS]
            for w_id in w_ids:
                wrd = snt[w_id]
                ret.append((wrd[TOK_IDX].lower(), wrd[1].get(POS)))
        return ret

    def _get_snt2tok(self, a_tok_list):
        """Generate mapping from sentence indices to token lists.

        Args:
          a_tok_list (list):
            list of sentence and token indices pertaining to the argument

        Returns:
          defaultdict:
            mapping from sentence indices to token lists

        """
        snt2tok_pos = defaultdict(set)
        for el in a_tok_list:
            snt_id = el[SNT_ID]
            snt2tok_pos[snt_id].add(el[TOK_ID])
        return snt2tok_pos ARG1 = "Arg1" ARG2 = "Arg2" CONNECTIVE = "Connective" DOC_ID = "DocID" ENCODING = "utf-8" RAW_TEXT = "RawText" SENTENCES = "sentences" SENSE = "Sense" TOK_IDX = 0 WORDS = "words" CHM = ConnHeadMapper() def floatX(a_data, a_dtype=config.floatX):
def rmsprop(tparams, grads, x, y, cost):
MAX_ITERS = 150  # 450
CONV_EPS = 1e-5
DFLT_VDIM = 100
_HE_NORMAL = HeNormal()
HE_NORMAL = lambda x: floatX(_HE_NORMAL.sample(x))
_HE_UNIFORM = HeUniform()
HE_UNIFORM = lambda x: floatX(_HE_UNIFORM.sample(x))
_HE_UNIFORM_RELU = HeUniform(gain=np.sqrt(2))
HE_UNIFORM_RELU = lambda x: floatX(_HE_UNIFORM_RELU.sample(x))
_RELU_ALPHA = 0.
_HE_UNIFORM_LEAKY_RELU = HeUniform(
    gain=np.sqrt(2. / (1 + (_RELU_ALPHA or 1e-6)**2)))
HE_UNIFORM_LEAKY_RELU = lambda x: \
    floatX(_HE_UNIFORM_LEAKY_RELU.sample(x))
_ORTHOGONAL = Orthogonal()
ORTHOGONAL = lambda x: floatX(_ORTHOGONAL.sample(x))
TRNG = RandomStreams() class Word2Vec(object):
    """Class for cached retrieval of word embeddings.

    """

    def __init__(self, a_w2v=W2V):
        """Class cosntructor.

        Args:
          a_w2v (gensim.Word2Vec):
            dictionary with original word embeddings

        """
        self._w2v = a_w2v
        self._cache = {}
        self.ndim = -1

    def __contains__(self, a_word):
        """Proxy method for looking up a word in the resource.

        Args:
        a_word (str): word to look up in the resource

        Returns:
        (bool):
        true if the word is present in the underlying resource

        """
        if a_word in self._cache:
            return True
        elif a_word in self._w2v:
            self._cache[a_word] = self._w2v[a_word]
            return True
        return False

    def __getitem__(self, a_word):
        """Proxy method for looking up a word in the resource.

        Args:
        a_word (str): word to look up in the resource

        Returns:
        (bool):
        true if the word is present in the underlying resource

        """
        if a_word in self._cache:
            return self._cache[a_word]
        elif a_word in self._w2v:
            emb = self._cache[a_word] = self._w2v[a_word]
            return emb
        raise KeyError

    def load(self):
        """Load the word2vec resource.

        Args:
        (void):

        Returns:
        (void):
        load the resource in place

        """
        self._w2v.load()
        self.ndim = self._w2v.resource.vector_size

    def unload(self):
        """Unload the word2vec resource.

        Args:
        (void):

        Returns:
        (void):
        load the resource in place

        """
        self._cache.clear()
        self._w2v.unload()
from dsenser.base import BaseSenser
from dsenser.constants import ARG1, ARG2, CONNECTIVE, DOC_ID, ENCODING, \
    RAW_TEXT, SENTENCES, SENSE, TOK_IDX, WORDS
from dsenser.resources import CHM
from dsenser.theano_utils import config, floatX, rmsprop, theano, \
    CONV_EPS, HE_UNIFORM, MAX_ITERS, TT, TRNG, DFLT_VDIM
from dsenser.word2vec import Word2Vec
from collections import Counter
from datetime import datetime
import abc
import numpy as np
import re
import sys
        Args:
          a_grads (theano.shared or None):
            gradients of the trainign function

        Returns:
          void:

        Note:
          modifies instance variables in place

        """
        if a_grads:
            self._grad_shared, self._update, \
                self._rms_params = rmsprop(self._params, a_grads,
                                           [self.W_INDICES_ARG1,
                                            self.W_INDICES_ARG2,
                                            self.CONN_INDEX],
                                           self.Y_gold,
                                           self._cost)
        if self._predict_class is None:
            self._predict_class = theano.function([self.W_INDICES_ARG1,
                                                   self.W_INDICES_ARG2,
                                                   self.CONN_INDEX],
                                                  self._pred_class,
                                                  name="_predict_class")
        if self._compute_dev_cost is None:
            self._compute_dev_cost = theano.function([self.W_INDICES_ARG1,
                                                      self.W_INDICES_ARG2,
                                                      self.CONN_INDEX,
                                                      self.Y_gold],
                                                     self._dev_cost,
                                                     name="_compute_dev_cost")

        # initialize prediction function
        if self._predict_func is None:
            self._predict_func = theano.function([self.W_INDICES_ARG1,
                                                  self.W_INDICES_ARG2,
                                                  self.CONN_INDEX],
                                                 self.Y_pred,
                                                 name="_predict_func")
            self._predict_func_emb = theano.function([self.EMB_ARG1,
                                                      self.EMB_ARG2,
                                                      self.CONN_INDEX],
                                                     self.Y_pred,
                                                     name="_predict_func_emb")
        # initialize debug function
        if self._debug_nn is None:
            self._debug_nn = theano.function([self.W_INDICES_ARG1,
                                              self.W_INDICES_ARG2,
                                              self.CONN_INDEX],
                                             [self.Y_pred],
                                             name="_debug_nn")

    def _init_wemb_funcs(self):
        """Initialize functions for obtaining word embeddings.

        """
        if self._plain_w2v:
            if self.w2v is None:
                self.w2v = Word2Vec
            self.w2v.load()
            self.ndim = self.w2v.ndim
            self.get_train_w_emb_i = self._get_train_w2v_emb_i
            self.init_w_emb = self._init_w2v_emb
            if self._trained:
                self.get_test_w_emb_i = self._get_test_w2v_emb_i
                self._predict_func = self._predict_func_emb
            else:
                self.get_test_w_emb_i = self._get_train_w2v_emb_i
        elif self.lstsq:
            self.ndim = DFLT_VDIM
            self.get_train_w_emb_i = self._get_train_w2v_emb_i
            self.init_w_emb = self._init_w_emb
            if self._trained:
                if self.w2v is None:
                    self.w2v = Word2Vec
                    self.w2v.load()
                self.get_test_w_emb_i = self._get_test_w2v_lstsq_emb_i
                self._predict_func = self._predict_func_emb
            else:
                self.get_test_w_emb_i = self._get_train_w2v_emb_i
        else:
            # checked
            self.ndim = DFLT_VDIM
            self.get_train_w_emb_i = self._get_train_w_emb_i
            self.get_test_w_emb_i = self._get_test_w_emb_i
            self.init_w_emb = self._init_w_emb

    def _reset_funcs(self):
        """Set all compiled theano functions to None.

        Note:
          modifies instance variables in place

        """
        self._grad_shared = None
        self._update = None
        self._predict_class = None
        self._predict_func = None
        self._compute_dev_cost = None
        self._debug_nn = None
        self.get_train_w_emb_i = None
        self.get_test_w_emb_i = None
        self.init_w_emb = None

    def _compute_w_stat(self, a_parses):
        """Compute word frequencies on the corpus.

        Args:
          a_parses (dict): CoNLL parses

        Returns:
          void:

        Note:
          modifies instance variables in place

        """
        self._w_stat = Counter(_norm_word(w[TOK_IDX])
                               for doc in a_parses.itervalues()

                               for sent in doc[SENTENCES]