# Path: reid/models/block.py
# class Block(object):
#     """Abstract base class for neural network layers and models"""
# 
#     def __init__(self):
#         self._params = []
# 
#     @property
#     def parameters(self):
#         return self._params
# 
#     @parameters.setter
#     def parameters(self, value):
#         self._params = value
# 
#     def get_output(self, x):
#         raise NotImplementedError
# 
#     def get_regularization(self, l):
#         return 0
# 
# Path: reid/models/layers.py
# class FullConnLayer(Block):
#     """Fully connected layer"""
# 
#     def __init__(self, input_size, output_size, active_func=None,
#                  W=None, b=None,
#                  through=False):
#         super(FullConnLayer, self).__init__()
# 
#         self._active_func = active_func
#         self._through = through
# 
#         if W is None:
#             W_bound = numpy.sqrt(6.0 / (input_size + output_size))
# 
#             if active_func == actfuncs.sigmoid: W_bound *= 4
# 
#             init_W = numpy.asarray(numpy_rng.uniform(
#                 low=-W_bound, high=W_bound,
#                 size=(input_size, output_size)), dtype=theano.config.floatX)
# 
#             self._W = theano.shared(value=init_W, borrow=True)
#         else:
#             self._W = W
# 
#         if b is None:
#             init_b = numpy.zeros(output_size, dtype=theano.config.floatX)
# 
#             self._b = theano.shared(value=init_b, borrow=True)
#         else:
#             self._b = b
# 
#         self._params = [self._W, self._b]
# 
#     def get_output(self, x):
#         z = T.dot(x, self._W) + self._b
#         z = z if self._active_func is None else self._active_func(z)
#         return (z, []) if not self._through else (z, [z])
# 
#     def get_regularization(self, l):
#         return self._W.norm(l)


from reid.models.block import Block
from reid.models.layers import FullConnLayer

    The auto-encoder has symmetric structure. Each layer is fully connected.
    """

    def __init__(self, layer_sizes, active_funcs, through=False):
        """Initialize the auto-encoder

        Args:
            layer_sizes: A list of integers. The first one is the input size.
                The last one is the middlest layer's size.
            active_funcs: A list of layer-wise active functions
            through: True if the output should be passed
        """

        n_layers = len(active_funcs)
        assert n_layers == len(layer_sizes) - 1

        self._blocks, self._params = [], []
        self._through = through

        # Build feature extraction layers
        for i in xrange(n_layers):
            layer = FullConnLayer(input_size=layer_sizes[i],
                                  output_size=layer_sizes[i+1],
                                  active_func=active_funcs[i])
            self._blocks.append(layer)
            self._params.extend(layer.parameters)

        # Build reconstruction layers
        for i in xrange(n_layers-1, -1, -1):

# Path: reid/models/block.py
# class Block(object):
#     """Abstract base class for neural network layers and models"""
# 
#     def __init__(self):
#         self._params = []
# 
#     @property
#     def parameters(self):
#         return self._params
# 
#     @parameters.setter
#     def parameters(self, value):
#         self._params = value
# 
#     def get_output(self, x):
#         raise NotImplementedError
# 
#     def get_regularization(self, l):
#         return 0
# 
# Path: reid/models/layers.py
# class FullConnLayer(Block):
#     """Fully connected layer"""
# 
#     def __init__(self, input_size, output_size, active_func=None,
#                  W=None, b=None,
#                  through=False):
#         super(FullConnLayer, self).__init__()
# 
#         self._active_func = active_func
#         self._through = through
# 
#         if W is None:
#             W_bound = numpy.sqrt(6.0 / (input_size + output_size))
# 
#             if active_func == actfuncs.sigmoid: W_bound *= 4
# 
#             init_W = numpy.asarray(numpy_rng.uniform(
#                 low=-W_bound, high=W_bound,
#                 size=(input_size, output_size)), dtype=theano.config.floatX)
# 
#             self._W = theano.shared(value=init_W, borrow=True)
#         else:
#             self._W = W
# 
#         if b is None:
#             init_b = numpy.zeros(output_size, dtype=theano.config.floatX)
# 
#             self._b = theano.shared(value=init_b, borrow=True)
#         else:
#             self._b = b
# 
#         self._params = [self._W, self._b]
# 
#     def get_output(self, x):
#         z = T.dot(x, self._W) + self._b
#         z = z if self._active_func is None else self._active_func(z)
#         return (z, []) if not self._through else (z, [z])
# 
#     def get_regularization(self, l):
#         return self._W.norm(l)


# Path: reid/models/neural_net.py
from reid.models.block import Block
from reid.models.layers import FullConnLayer


    The auto-encoder has symmetric structure. Each layer is fully connected.
    """

    def __init__(self, layer_sizes, active_funcs, through=False):
        """Initialize the auto-encoder

        Args:
            layer_sizes: A list of integers. The first one is the input size.
                The last one is the middlest layer's size.
            active_funcs: A list of layer-wise active functions
            through: True if the output should be passed
        """

        n_layers = len(active_funcs)
        assert n_layers == len(layer_sizes) - 1

        self._blocks, self._params = [], []
        self._through = through

        # Build feature extraction layers
        for i in xrange(n_layers):
            layer = FullConnLayer(input_size=layer_sizes[i],
                                  output_size=layer_sizes[i+1],
                                  active_func=active_funcs[i])
            self._blocks.append(layer)
            self._params.extend(layer.parameters)

        # Build reconstruction layers
        for i in xrange(n_layers-1, -1, -1):

            layer = FullConnLayer(input_size=layer_sizes[i+1],