# Path: deeppy/base.py
# class ParamMixin(object):
#     @property
#     def params(self):
#         """ List of Parameter objects. """
#         raise NotImplementedError()
# 
#     @params.setter
#     def params(self, params):
#         raise NotImplementedError()
# 
# Path: deeppy/parameter.py
# class Parameter(PickleMixin):
#     def __init__(self, fill, name='', learn_rate=1.0, weight_decay=0.0,
#                  monitor=False):
#         self.filler = Filler.from_any(fill)
#         self.name = name
#         self.learn_rate = learn_rate
#         self._monitor = monitor
#         self.weight_decay = weight_decay
#         self._array = None
#         self._tmp_grad_array = None
#         self._tmp_step = None
#         self.shares = []
# 
#     @classmethod
#     def from_any(cls, arg):
#         if isinstance(arg, Parameter):
#             return arg
#         elif isinstance(arg, (int, float, np.ndarray, ca.ndarray, Filler)):
#             return cls(arg)
#         raise ValueError('Invalid parameter arguments')
# 
#     def setup(self, shape):
#         if self._array is None:
#             self._array = self.filler.array(shape)
#         else:
#             if isinstance(shape, int):
#                 shape = (shape,)
#             if self._array.shape != shape:
#                 raise ValueError('Shape %s does not match existing shape %s' %
#                                  (shape, self._array.shape))
# 
#     @property
#     def array(self):
#         return self._array
# 
#     @property
#     def grad_array(self):
#         ''' Returns the gradient array. '''
#         if self._tmp_grad_array is None:
#             if self.array is None:
#                 raise ValueError('Parameter not setup')
#             self._tmp_grad_array = ca.zeros_like(self.array)
#         return self._tmp_grad_array
# 
#     def grad(self):
#         ''' Returns a parameter step calculated from the gradient.
#         This differs from grad_array() as the parameter may be shared such
#         that its gradient has multiple sources. '''
#         grad = self.grad_array
#         for param in self.shares:
#             grad += param.grad_array
#         grad = self._add_penalty(grad)
#         return grad
# 
#     def step(self, step):
#         ''' Update the parameter values according to the given step. '''
#         if self._monitor:
#             self._tmp_step = step
#         self._array += step
# 
#     def _add_penalty(self, grad):
#         if self.weight_decay == 0.0:
#             return grad
#         else:
#             grad += 2*self.weight_decay * self._array
#             return grad
# 
#     def monitor(self):
#         if not self._monitor:
#             return
#         val_mean_abs = np.array(ca.mean(ca.fabs(self._array)))
#         grad_mean_abs = np.array(ca.mean(ca.fabs(self._tmp_grad_array)))
#         step_mean_abs = np.array(ca.mean(ca.fabs(self._tmp_step)))
#         log.info('%s:\t%.1e  [%.1e, %.1e]', self.name, val_mean_abs,
#                  grad_mean_abs, step_mean_abs)
# 
#     def share(self):
#         param = SharedParameter(self)
#         self.shares.append(param)
#         return param
# 
# Path: deeppy/expr/base.py
# class Unary(Op):
#     x = None
# 
#     def __call__(self, x):
#         x = _require_op(x)
#         self.x = x
#         if isinstance(x, Constant):
#             # Propagate constant.
#             self.setup()
#             self.fprop()
#             return Constant(self.array)
#         self.bpropable = x.bpropable
#         self.inputs = [x]
#         return self


import cudarray as ca
from ...base import ParamMixin
from ...parameter import Parameter
from ..base import Unary
        super(Linear, self).__call__(x)
        self.bpropable = True
        return self

    def setup(self):
        batch_size, n_in = self.x.shape
        self.shape = (batch_size, self.n_out)
        self.array = ca.zeros(self.shape)
        self.grad_array = ca.zeros(self.shape)
        self.weights.setup((n_in, self.n_out))

    def fprop(self):
        ca.dot(self.x.array, self.weights.array, self.array)

    def bprop(self):
        ca.dot(self.x.array.T, self.grad_array, self.weights.grad_array)
        ca.dot(self.grad_array, self.weights.array.T, self.x.grad_array)

    @property
    def params(self):
        return self.weights,

    @params.setter
    def params(self, params):
        self.weights, = params


class Affine(Linear):
    def __init__(self, n_out, weights, bias=0.0):
        super(Affine, self).__init__(n_out, weights)

# Path: deeppy/base.py
# class ParamMixin(object):
#     @property
#     def params(self):
#         """ List of Parameter objects. """
#         raise NotImplementedError()
# 
#     @params.setter
#     def params(self, params):
#         raise NotImplementedError()
# 
# Path: deeppy/parameter.py
# class Parameter(PickleMixin):
#     def __init__(self, fill, name='', learn_rate=1.0, weight_decay=0.0,
#                  monitor=False):
#         self.filler = Filler.from_any(fill)
#         self.name = name
#         self.learn_rate = learn_rate
#         self._monitor = monitor
#         self.weight_decay = weight_decay
#         self._array = None
#         self._tmp_grad_array = None
#         self._tmp_step = None
#         self.shares = []
# 
#     @classmethod
#     def from_any(cls, arg):
#         if isinstance(arg, Parameter):
#             return arg
#         elif isinstance(arg, (int, float, np.ndarray, ca.ndarray, Filler)):
#             return cls(arg)
#         raise ValueError('Invalid parameter arguments')
# 
#     def setup(self, shape):
#         if self._array is None:
#             self._array = self.filler.array(shape)
#         else:
#             if isinstance(shape, int):
#                 shape = (shape,)
#             if self._array.shape != shape:
#                 raise ValueError('Shape %s does not match existing shape %s' %
#                                  (shape, self._array.shape))
# 
#     @property
#     def array(self):
#         return self._array
# 
#     @property
#     def grad_array(self):
#         ''' Returns the gradient array. '''
#         if self._tmp_grad_array is None:
#             if self.array is None:
#                 raise ValueError('Parameter not setup')
#             self._tmp_grad_array = ca.zeros_like(self.array)
#         return self._tmp_grad_array
# 
#     def grad(self):
#         ''' Returns a parameter step calculated from the gradient.
#         This differs from grad_array() as the parameter may be shared such
#         that its gradient has multiple sources. '''
#         grad = self.grad_array
#         for param in self.shares:
#             grad += param.grad_array
#         grad = self._add_penalty(grad)
#         return grad
# 
#     def step(self, step):
#         ''' Update the parameter values according to the given step. '''
#         if self._monitor:
#             self._tmp_step = step
#         self._array += step
# 
#     def _add_penalty(self, grad):
#         if self.weight_decay == 0.0:
#             return grad
#         else:
#             grad += 2*self.weight_decay * self._array
#             return grad
# 
#     def monitor(self):
#         if not self._monitor:
#             return
#         val_mean_abs = np.array(ca.mean(ca.fabs(self._array)))
#         grad_mean_abs = np.array(ca.mean(ca.fabs(self._tmp_grad_array)))
#         step_mean_abs = np.array(ca.mean(ca.fabs(self._tmp_step)))
#         log.info('%s:\t%.1e  [%.1e, %.1e]', self.name, val_mean_abs,
#                  grad_mean_abs, step_mean_abs)
# 
#     def share(self):
#         param = SharedParameter(self)
#         self.shares.append(param)
#         return param
# 
# Path: deeppy/expr/base.py
# class Unary(Op):
#     x = None
# 
#     def __call__(self, x):
#         x = _require_op(x)
#         self.x = x
#         if isinstance(x, Constant):
#             # Propagate constant.
#             self.setup()
#             self.fprop()
#             return Constant(self.array)
#         self.bpropable = x.bpropable
#         self.inputs = [x]
#         return self


# Path: deeppy/expr/nnet/affine.py
import cudarray as ca
from ...base import ParamMixin
from ...parameter import Parameter
from ..base import Unary

        super(Linear, self).__call__(x)
        self.bpropable = True
        return self

    def setup(self):
        batch_size, n_in = self.x.shape
        self.shape = (batch_size, self.n_out)
        self.array = ca.zeros(self.shape)
        self.grad_array = ca.zeros(self.shape)
        self.weights.setup((n_in, self.n_out))

    def fprop(self):
        ca.dot(self.x.array, self.weights.array, self.array)

    def bprop(self):
        ca.dot(self.x.array.T, self.grad_array, self.weights.grad_array)
        ca.dot(self.grad_array, self.weights.array.T, self.x.grad_array)

    @property
    def params(self):
        return self.weights,

    @params.setter
    def params(self, params):
        self.weights, = params


class Affine(Linear):
    def __init__(self, n_out, weights, bias=0.0):
        super(Affine, self).__init__(n_out, weights)

        self.bias = Parameter.from_any(bias)