# Path: sop_embed/layer.py
# class HiddenLayer(Layer):
#     def __init__(self, input, n_in, n_out, W=None, b=None,
#                  activation=T.tanh, rng=None):
#         """
#         Typical hidden layer of an MLP: units are fully connected and have
#         tangente hyperbolic activation function. Weight matrix (W) is of shape
#         (n_in, n_out) and the bias vector (b) is of shape (nout,).
# 
#         Hidden unit activation is given by: tanh(dot(input, w)+ b)
# 
#         :type rng: numpy.random.RandomState
#         :param rng: a random number generator used to initiaze the weights.
# 
#         :type input: theano.tensor.dmatrix
#         :param input: a symbolic tensor of shape (n_examples, n_in)
# 
#         :type n_in: int
#         :param n_in: dimension of the input
# 
#         :type n_out: int
#         :param n_out: number of hidden units
# 
#         :type activation: theano.Op or function
#         :param activation:  Non linearity to be applied in the hidden layer.
#         """
#         if rng is None:
#             rng = np.random.RandomState()
# 
#         super(HiddenLayer, self).__init__(
#             input, n_in, n_out, activation=activation, rng=rng)
#         self.reset_layer()
# 
#         if W is not None:
#             self.W = W
# 
#         if b is not None:
#             self.b = b
# 
#         self.params = [self.W, self.b]
#         self.setup_outputs(input)
# 
#     def setup_outputs(self, input):
#         lin_output = T.dot(input, self.W) + self.b
#         self.output = (
#             lin_output if self.activation is None
#             else self.activation(lin_output))
# 
#     def get_outputs(self, input):
#         self.setup_outputs(input)
#         return self.output
# 
# Path: sop_embed/extra.py
# def get_non_linearity_fn(nonlinearity):
#         if nonlinearity == NonLinearity.SIGMOID:
#             return T.nnet.sigmoid
#         elif nonlinearity == NonLinearity.RELU:
#             return relu
#         elif nonlinearity == NonLinearity.TANH:
#             return T.tanh
#         elif nonlinearity is None:
#             return None


from theano import tensor as T
from theano.tensor.signal import pool
from theano.tensor.nnet import conv2d
from theano.tensor.nnet import conv
from theano.tensor.nnet import abstract_conv
from sop_embed.layer import HiddenLayer
from sop_embed.extra import get_non_linearity_fn
import theano
import numpy


class PoolingLayer(object):
    def __init__(self, input, poolsize, ignore_border, mode="max"):
        """Implement a pooling layer."""
        self.input = input
        self.x = input
        self.output = pool.pool_2d(
            input=self.x,
            ws=poolsize,
            ignore_border=ignore_border,
            mode=mode)
        self.params = []


class UnPoolingLayer(object):
    def __init__(self, input, ratio, use_1D_kernel=False):
        self.input = input
        self.x = input
        self.output = abstract_conv.bilinear_upsampling(
            input=self.x,
            ratio=ratio,
            use_1D_kernel=use_1D_kernel)
        self.params = []


class DeepConvolutionLayer(object):
    """A deep convolution network: convolution, pooling, convolution, pooling,
    ... . Can use it to build Transposed convolution by using unpooling
    instead of pooling."""

# Path: sop_embed/layer.py
# class HiddenLayer(Layer):
#     def __init__(self, input, n_in, n_out, W=None, b=None,
#                  activation=T.tanh, rng=None):
#         """
#         Typical hidden layer of an MLP: units are fully connected and have
#         tangente hyperbolic activation function. Weight matrix (W) is of shape
#         (n_in, n_out) and the bias vector (b) is of shape (nout,).
# 
#         Hidden unit activation is given by: tanh(dot(input, w)+ b)
# 
#         :type rng: numpy.random.RandomState
#         :param rng: a random number generator used to initiaze the weights.
# 
#         :type input: theano.tensor.dmatrix
#         :param input: a symbolic tensor of shape (n_examples, n_in)
# 
#         :type n_in: int
#         :param n_in: dimension of the input
# 
#         :type n_out: int
#         :param n_out: number of hidden units
# 
#         :type activation: theano.Op or function
#         :param activation:  Non linearity to be applied in the hidden layer.
#         """
#         if rng is None:
#             rng = np.random.RandomState()
# 
#         super(HiddenLayer, self).__init__(
#             input, n_in, n_out, activation=activation, rng=rng)
#         self.reset_layer()
# 
#         if W is not None:
#             self.W = W
# 
#         if b is not None:
#             self.b = b
# 
#         self.params = [self.W, self.b]
#         self.setup_outputs(input)
# 
#     def setup_outputs(self, input):
#         lin_output = T.dot(input, self.W) + self.b
#         self.output = (
#             lin_output if self.activation is None
#             else self.activation(lin_output))
# 
#     def get_outputs(self, input):
#         self.setup_outputs(input)
#         return self.output
# 
# Path: sop_embed/extra.py
# def get_non_linearity_fn(nonlinearity):
#         if nonlinearity == NonLinearity.SIGMOID:
#             return T.nnet.sigmoid
#         elif nonlinearity == NonLinearity.RELU:
#             return relu
#         elif nonlinearity == NonLinearity.TANH:
#             return T.tanh
#         elif nonlinearity is None:
#             return None


# Path: sop_embed/layers.py
from theano import tensor as T
from theano.tensor.signal import pool
from theano.tensor.nnet import conv2d
from theano.tensor.nnet import conv
from theano.tensor.nnet import abstract_conv
from sop_embed.layer import HiddenLayer
from sop_embed.extra import get_non_linearity_fn
import theano
import numpy



class PoolingLayer(object):
    def __init__(self, input, poolsize, ignore_border, mode="max"):
        """Implement a pooling layer."""
        self.input = input
        self.x = input
        self.output = pool.pool_2d(
            input=self.x,
            ws=poolsize,
            ignore_border=ignore_border,
            mode=mode)
        self.params = []


class UnPoolingLayer(object):
    def __init__(self, input, ratio, use_1D_kernel=False):
        self.input = input
        self.x = input
        self.output = abstract_conv.bilinear_upsampling(
            input=self.x,
            ratio=ratio,
            use_1D_kernel=use_1D_kernel)
        self.params = []


class DeepConvolutionLayer(object):
    """A deep convolution network: convolution, pooling, convolution, pooling,
    ... . Can use it to build Transposed convolution by using unpooling
    instead of pooling."""

    def __init__(self, input, layers, crop_size):