# Path: mlp.py
# class MLP(object):
#     """Multi-Layer Perceptron Class
# 
#     A multilayer perceptron is a feedforward artificial neural network model
#     that has one layer or more of hidden units and nonlinear activations.
#     Intermediate layers usually have as activation function tanh or the
#     sigmoid function (defined here by a ``HiddenLayer`` class)  while the
#     top layer is a softmax layer (defined here by a ``LogisticRegression``
#     class).
#     """
# 
#     def __init__(self, rng, input, n_in, n_hidden, n_out):
#         """Initialize the parameters for the multilayer perceptron
# 
#         :type rng: numpy.random.RandomState
#         :param rng: a random number generator used to initialize weights
# 
#         :type input: theano.tensor.TensorType
#         :param input: symbolic variable that describes the input of the
#         architecture (one minibatch)
# 
#         :type n_in: int
#         :param n_in: number of input units, the dimension of the space in
#         which the datapoints lie
# 
#         :type n_hidden: int
#         :param n_hidden: number of hidden units
# 
#         :type n_out: int
#         :param n_out: number of output units, the dimension of the space in
#         which the labels lie
# 
#         """
# 
#         # Since we are dealing with a one hidden layer MLP, this will translate
#         # into a HiddenLayer with a tanh activation function connected to the
#         # LogisticRegression layer; the activation function can be replaced by
#         # sigmoid or any other nonlinear function
#         self.hiddenLayer = HiddenLayer(
#             rng=rng,
#             input=input,
#             n_in=n_in,
#             n_out=n_hidden,
#             activation=T.tanh
#         )
# 
#         self.W = theano.shared(name='W',
#                                value=numpy.random.uniform(-0.2, 0.2, (n_hidden * n_out))
#                                .astype(theano.config.floatX))
# 
#         self.b = theano.shared(name='b',
#                                value=numpy.zeros(n_out,).astype(theano.config.floatX))
# 
#         self.outputLayer = T.nnet.softmax(T.dot(self.hiddenLayer.output, self.W) + self.b)
# 
#         # L1 norm ; one regularization option is to enforce L1 norm to
#         # be small
#         self.L1 = (
#             abs(self.hiddenLayer.W).sum()
#             + abs(self.W).sum()
#         )
# 
#         # square of L2 norm ; one regularization option is to enforce
#         # square of L2 norm to be small
#         self.L2_sqr = (
#             (self.hiddenLayer.W ** 2).sum()
#             + (self.W ** 2).sum()
#         )
# 
#         # negative log likelihood of the MLP is given by the negative
#         # log likelihood of the output of the model, computed in the
#         # logistic regression layer
#         self.predProb = theano.function([input], self.outputLayer, name='f_pred_prob')
#         self.pred = theano.function([input], self.outputLayer.argmax(axis=1), name='f_pred')
# 
#         # the parameters of the model are the parameters of the two layer it is
#         # made out of
#         self.params = self.hiddenLayer.params + [self.W + self.b]


from mlp import MLP
from theano import tensor as T
import numpy
import theano


if __name__ == "__main__":
    rng = numpy.random.RandomState(1234)

    index = T.lscalar()
    x = T.matrix('x')
    y = T.ivector('y')

    classifier = MLP (
        rng=rng,
        input=x,
        n_in=2,
        n_hidden=5,
        n_out=2
    )

    data = numpy.asarray([[4., 3, 2], [1, 2, 1]])

    forward = theano.function(
        inputs=[index],
        outputs=classifier.pred(x),
        givens={
            x: data[index:index+2]
        }
    )
    cost = -T.log(classifier.pred[y] + 1e-8).mean() + 0.00 * classifier.L1 + 0.00 * classifier.L2_sqr


# Path: mlp.py
# class MLP(object):
#     """Multi-Layer Perceptron Class
# 
#     A multilayer perceptron is a feedforward artificial neural network model
#     that has one layer or more of hidden units and nonlinear activations.
#     Intermediate layers usually have as activation function tanh or the
#     sigmoid function (defined here by a ``HiddenLayer`` class)  while the
#     top layer is a softmax layer (defined here by a ``LogisticRegression``
#     class).
#     """
# 
#     def __init__(self, rng, input, n_in, n_hidden, n_out):
#         """Initialize the parameters for the multilayer perceptron
# 
#         :type rng: numpy.random.RandomState
#         :param rng: a random number generator used to initialize weights
# 
#         :type input: theano.tensor.TensorType
#         :param input: symbolic variable that describes the input of the
#         architecture (one minibatch)
# 
#         :type n_in: int
#         :param n_in: number of input units, the dimension of the space in
#         which the datapoints lie
# 
#         :type n_hidden: int
#         :param n_hidden: number of hidden units
# 
#         :type n_out: int
#         :param n_out: number of output units, the dimension of the space in
#         which the labels lie
# 
#         """
# 
#         # Since we are dealing with a one hidden layer MLP, this will translate
#         # into a HiddenLayer with a tanh activation function connected to the
#         # LogisticRegression layer; the activation function can be replaced by
#         # sigmoid or any other nonlinear function
#         self.hiddenLayer = HiddenLayer(
#             rng=rng,
#             input=input,
#             n_in=n_in,
#             n_out=n_hidden,
#             activation=T.tanh
#         )
# 
#         self.W = theano.shared(name='W',
#                                value=numpy.random.uniform(-0.2, 0.2, (n_hidden * n_out))
#                                .astype(theano.config.floatX))
# 
#         self.b = theano.shared(name='b',
#                                value=numpy.zeros(n_out,).astype(theano.config.floatX))
# 
#         self.outputLayer = T.nnet.softmax(T.dot(self.hiddenLayer.output, self.W) + self.b)
# 
#         # L1 norm ; one regularization option is to enforce L1 norm to
#         # be small
#         self.L1 = (
#             abs(self.hiddenLayer.W).sum()
#             + abs(self.W).sum()
#         )
# 
#         # square of L2 norm ; one regularization option is to enforce
#         # square of L2 norm to be small
#         self.L2_sqr = (
#             (self.hiddenLayer.W ** 2).sum()
#             + (self.W ** 2).sum()
#         )
# 
#         # negative log likelihood of the MLP is given by the negative
#         # log likelihood of the output of the model, computed in the
#         # logistic regression layer
#         self.predProb = theano.function([input], self.outputLayer, name='f_pred_prob')
#         self.pred = theano.function([input], self.outputLayer.argmax(axis=1), name='f_pred')
# 
#         # the parameters of the model are the parameters of the two layer it is
#         # made out of
#         self.params = self.hiddenLayer.params + [self.W + self.b]


# Path: strap.py
from mlp import MLP
from theano import tensor as T
import numpy
import theano



if __name__ == "__main__":
    rng = numpy.random.RandomState(1234)

    index = T.lscalar()
    x = T.matrix('x')
    y = T.ivector('y')

    classifier = MLP (
        rng=rng,
        input=x,
        n_in=2,
        n_hidden=5,
        n_out=2
    )

    data = numpy.asarray([[4., 3, 2], [1, 2, 1]])

    forward = theano.function(
        inputs=[index],
        outputs=classifier.pred(x),
        givens={
            x: data[index:index+2]
        }
    )
    cost = -T.log(classifier.pred[y] + 1e-8).mean() + 0.00 * classifier.L1 + 0.00 * classifier.L2_sqr


    print forward(0)