# Path: mozi/layers/template.py
# class Template(object):
#     """
#     DESCRIPTION:
#         The interface to be implemented by any layer.
#     """
#     def __init__(self):
#         '''
#         FIELDS:
#             self.params: any params from the layer that needs to be updated
#                          by backpropagation can be put inside self.params
#             self.updates: use for updating any shared variables
#         '''
#         self.params = []
#         self.updates = []
# 
#     def _test_fprop(self, state_below):
#         '''
#         DESCRIPTION:
#             This is called during validating/testing of the model.
#         PARAM:
#             state_below: the input to layer
#         '''
#         return self._train_fprop(state_below)
# 
#     def _train_fprop(self, state_below):
#         '''
#         DESCRIPTION:
#             This is called during every training batch whereby the output from the
#             model will be used to update the parameters during error backpropagation.
#         PARAM:
#             state_below: the input to layer
#         '''
#         raise NotImplementedError()
# 
# 
#     def _layer_stats(self, state_below, layer_output):
#         """
#         DESCRIPTION:
#             Layer stats is used for debugging the layer by allowing user to peek
#             at the weight values or the layer output or any parameters of interest
#             during training. By computing the values of parameter of interest,
#             for example T.max(self.W) and put in the return list, the training will
#             print the maximum of the weight in the layer after every epoch.
#         PARAM:
#             state_below: the input to layer
#             layer_output: the output from the layer
#         RETURN:
#             A list of tuples of [('name_a', var_a), ('name_b', var_b)] whereby var is scalar
#         """
#         return []
# 
# Path: mozi/utils/theano_utils.py
# def sharedX(value, dtype=floatX, name=None, borrow=False, **kwargs):
#     return theano.shared(np.asarray(value, dtype=dtype), name=name, borrow=borrow, **kwargs)
# 
# Path: mozi/weight_init.py
# class UniformWeight(WeightInitialization):
#     def __init__(self, scale=0.05):
#         self.scale = scale
# 
#     def __call__(self, dim, name='W', **kwargs):
#         W_values = np.random.uniform(low=-self.scale, high=self.scale, size=dim)
#         return sharedX(name=name, value=W_values, borrow=True, **kwargs)


from mozi.layers.template import Template
from mozi.utils.theano_utils import sharedX
from mozi.weight_init import UniformWeight


class Embedding(Template):
    '''
        Turn positive integers (indexes) into denses vectors of fixed size.
        eg. [[4], [20]] -> [[0.25, 0.1], [0.6, -0.2]]

        @input_dim: size of vocabulary (highest input integer + 1)
        @output_dim: size of dense representation
    '''
    def __init__(self, input_dim, output_dim, init=UniformWeight(scale=0.1), weights=None):

        self.input_dim = input_dim
        self.output_dim = output_dim
        if weights is None:
            self.W = init((input_dim, output_dim))
        else:

# Path: mozi/layers/template.py
# class Template(object):
#     """
#     DESCRIPTION:
#         The interface to be implemented by any layer.
#     """
#     def __init__(self):
#         '''
#         FIELDS:
#             self.params: any params from the layer that needs to be updated
#                          by backpropagation can be put inside self.params
#             self.updates: use for updating any shared variables
#         '''
#         self.params = []
#         self.updates = []
# 
#     def _test_fprop(self, state_below):
#         '''
#         DESCRIPTION:
#             This is called during validating/testing of the model.
#         PARAM:
#             state_below: the input to layer
#         '''
#         return self._train_fprop(state_below)
# 
#     def _train_fprop(self, state_below):
#         '''
#         DESCRIPTION:
#             This is called during every training batch whereby the output from the
#             model will be used to update the parameters during error backpropagation.
#         PARAM:
#             state_below: the input to layer
#         '''
#         raise NotImplementedError()
# 
# 
#     def _layer_stats(self, state_below, layer_output):
#         """
#         DESCRIPTION:
#             Layer stats is used for debugging the layer by allowing user to peek
#             at the weight values or the layer output or any parameters of interest
#             during training. By computing the values of parameter of interest,
#             for example T.max(self.W) and put in the return list, the training will
#             print the maximum of the weight in the layer after every epoch.
#         PARAM:
#             state_below: the input to layer
#             layer_output: the output from the layer
#         RETURN:
#             A list of tuples of [('name_a', var_a), ('name_b', var_b)] whereby var is scalar
#         """
#         return []
# 
# Path: mozi/utils/theano_utils.py
# def sharedX(value, dtype=floatX, name=None, borrow=False, **kwargs):
#     return theano.shared(np.asarray(value, dtype=dtype), name=name, borrow=borrow, **kwargs)
# 
# Path: mozi/weight_init.py
# class UniformWeight(WeightInitialization):
#     def __init__(self, scale=0.05):
#         self.scale = scale
# 
#     def __call__(self, dim, name='W', **kwargs):
#         W_values = np.random.uniform(low=-self.scale, high=self.scale, size=dim)
#         return sharedX(name=name, value=W_values, borrow=True, **kwargs)


# Path: mozi/layers/embedding.py
from mozi.layers.template import Template
from mozi.utils.theano_utils import sharedX
from mozi.weight_init import UniformWeight



class Embedding(Template):
    '''
        Turn positive integers (indexes) into denses vectors of fixed size.
        eg. [[4], [20]] -> [[0.25, 0.1], [0.6, -0.2]]

        @input_dim: size of vocabulary (highest input integer + 1)
        @output_dim: size of dense representation
    '''
    def __init__(self, input_dim, output_dim, init=UniformWeight(scale=0.1), weights=None):

        self.input_dim = input_dim
        self.output_dim = output_dim
        if weights is None:
            self.W = init((input_dim, output_dim))
        else:

            self.W = sharedX(weights)