# 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
            self.grad_array, self.weights.array, self.x.array,
            filters_d=self.weights.grad_array, to_imgs=False
        )
        self.conv_op.fprop(self.grad_array, self.weights.array,
                           convout=self.x.grad_array)
        if self.bias is not None:
            ca.sum(ca.sum(self.grad_array, axis=(2, 3), keepdims=True), axis=0,
                   keepdims=True, out=self.bias.grad_array)


class Pool(Unary):
    def __init__(self, win_shape=(3, 3), method='max', strides=(2, 2),
                 border_mode='valid'):
        pad = padding(win_shape, border_mode)
        self.pool_op = ca.nnet.PoolB01(win_shape, pad, strides, method)
        self.img_shape = None

    def setup(self):
        self.shape = self.pool_op.fprop(self.x.array).shape
        self.array = ca.zeros(self.shape)
        self.grad_array = ca.zeros(self.shape)

    def fprop(self):
        self.pool_op.fprop(self.x.array, self.array)

    def bprop(self):
        self.pool_op.bprop(self.x.shape[2:], self.grad_array,
                           self.x.grad_array)



# 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/spatial.py
import cudarray as ca
from ...base import ParamMixin
from ...parameter import Parameter
from ..base import Unary

            self.grad_array, self.weights.array, self.x.array,
            filters_d=self.weights.grad_array, to_imgs=False
        )
        self.conv_op.fprop(self.grad_array, self.weights.array,
                           convout=self.x.grad_array)
        if self.bias is not None:
            ca.sum(ca.sum(self.grad_array, axis=(2, 3), keepdims=True), axis=0,
                   keepdims=True, out=self.bias.grad_array)


class Pool(Unary):
    def __init__(self, win_shape=(3, 3), method='max', strides=(2, 2),
                 border_mode='valid'):
        pad = padding(win_shape, border_mode)
        self.pool_op = ca.nnet.PoolB01(win_shape, pad, strides, method)
        self.img_shape = None

    def setup(self):
        self.shape = self.pool_op.fprop(self.x.array).shape
        self.array = ca.zeros(self.shape)
        self.grad_array = ca.zeros(self.shape)

    def fprop(self):
        self.pool_op.fprop(self.x.array, self.array)

    def bprop(self):
        self.pool_op.bprop(self.x.shape[2:], self.grad_array,
                           self.x.grad_array)



class Rescale(Unary):