# Path: deeppy/expr/base.py
# class Op(PickleMixin):
#     _pickle_ignore = ['_tmp_', 'array', 'grad_array']
#     inputs = []
#     bpropable = True
#     shape = None
#     array = None
#     grad_array = None
# 
#     def setup(self):
#         pass
# 
#     def fprop(self):
#         raise NotImplementedError()
# 
#     def bprop(self):
#         raise NotImplementedError()
# 
#     def __add__(self, other):
#         return deeppy.expr.Add()(self, other)
# 
#     def __radd__(self, other):
#         return deeppy.expr.Add()(other, self)
# 
#     def __iadd__(self, other):
#         return self.__add__(other)
# 
#     def __sub__(self, other):
#         return deeppy.expr.Subtract()(self, other)
# 
#     def __rsub__(self, other):
#         return deeppy.expr.Subtract()(other, self)
# 
#     def __isub__(self, other):
#         return self.__sub__(other)
# 
#     def __mul__(self, other):
#         return deeppy.expr.Multiply()(self, other)
# 
#     def __rmul__(self, other):
#         return deeppy.expr.Multiply()(other, self)
# 
#     def __imul__(self, other):
#         return self.__mul__(other)
# 
#     def __div__(self, other):
#         return deeppy.expr.Divide()(self, other)
# 
#     def __rdiv__(self, other):
#         return deeppy.expr.Divide()(other, self)
# 
#     def __idiv__(self, other):
#         return self.__div__(other)
# 
#     def __truediv__(self, other):
#         return deeppy.expr.Divide()(self, other)
# 
#     def __rtruediv__(self, other):
#         return deeppy.expr.Divide()(other, self)
# 
#     def __itruediv__(self, other):
#         return self.__truediv__(other)
# 
#     def __pow__(self, other):
#         return deeppy.expr.Power()(self, other)
# 
#     def __rpow__(self, other):
#         return deeppy.expr.Power()(other, self)
# 
#     def __ipow__(self, other):
#         return self.__pow__(other)
# 
#     def __neg__(self):
#         return deeppy.expr.Negative()(self)
# 
#     @property
#     def T(self):
#         return deeppy.expr.transpose(self)
# 
# class Output(Op, NoBPropMixin, NoFPropMixin):
#     def __call__(self, x):
#         self.inputs = [x]
#         return self
# 
#     def setup(self):
#         pass
# 
# class SplitMixin(object):
#     pass
# 
# 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 numpy as np
import cudarray as ca
from .base import Op, Output, SplitMixin, Unary
        for i, (start, end) in enumerate(self.slices):
            ca.copyto(self.x.grad_array[start:end], self.outputs[i].grad_array)


class Transpose(Unary):
    def __init__(self, contiguous=False):
        self.contiguous = contiguous

    def setup(self):
        if len(self.x.shape) == 1:
            self.shape = (1,) + self.x.shape
        elif len(self.x.shape) == 2:
            self.shape = tuple(reversed(self.x.shape))
        else:
            raise ValueError('invalid shape for transpose: %s'
                             % str(self.x.shape))
        self.array = ca.zeros(self.shape)
        self.grad_array = ca.zeros(self.shape)

    def fprop(self):
        self.array = ca.transpose(self.x.array)
        if self.contiguous:
            self.array = ca.ascontiguousarray(self.array)

    def bprop(self):
        self.x.grad_array = ca.transpose(self.grad_array)
        if self.contiguous:
            self.array = ca.ascontiguousarray(self.x.grad_array)



# Path: deeppy/expr/base.py
# class Op(PickleMixin):
#     _pickle_ignore = ['_tmp_', 'array', 'grad_array']
#     inputs = []
#     bpropable = True
#     shape = None
#     array = None
#     grad_array = None
# 
#     def setup(self):
#         pass
# 
#     def fprop(self):
#         raise NotImplementedError()
# 
#     def bprop(self):
#         raise NotImplementedError()
# 
#     def __add__(self, other):
#         return deeppy.expr.Add()(self, other)
# 
#     def __radd__(self, other):
#         return deeppy.expr.Add()(other, self)
# 
#     def __iadd__(self, other):
#         return self.__add__(other)
# 
#     def __sub__(self, other):
#         return deeppy.expr.Subtract()(self, other)
# 
#     def __rsub__(self, other):
#         return deeppy.expr.Subtract()(other, self)
# 
#     def __isub__(self, other):
#         return self.__sub__(other)
# 
#     def __mul__(self, other):
#         return deeppy.expr.Multiply()(self, other)
# 
#     def __rmul__(self, other):
#         return deeppy.expr.Multiply()(other, self)
# 
#     def __imul__(self, other):
#         return self.__mul__(other)
# 
#     def __div__(self, other):
#         return deeppy.expr.Divide()(self, other)
# 
#     def __rdiv__(self, other):
#         return deeppy.expr.Divide()(other, self)
# 
#     def __idiv__(self, other):
#         return self.__div__(other)
# 
#     def __truediv__(self, other):
#         return deeppy.expr.Divide()(self, other)
# 
#     def __rtruediv__(self, other):
#         return deeppy.expr.Divide()(other, self)
# 
#     def __itruediv__(self, other):
#         return self.__truediv__(other)
# 
#     def __pow__(self, other):
#         return deeppy.expr.Power()(self, other)
# 
#     def __rpow__(self, other):
#         return deeppy.expr.Power()(other, self)
# 
#     def __ipow__(self, other):
#         return self.__pow__(other)
# 
#     def __neg__(self):
#         return deeppy.expr.Negative()(self)
# 
#     @property
#     def T(self):
#         return deeppy.expr.transpose(self)
# 
# class Output(Op, NoBPropMixin, NoFPropMixin):
#     def __call__(self, x):
#         self.inputs = [x]
#         return self
# 
#     def setup(self):
#         pass
# 
# class SplitMixin(object):
#     pass
# 
# 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/array.py
import numpy as np
import cudarray as ca
from .base import Op, Output, SplitMixin, Unary

        for i, (start, end) in enumerate(self.slices):
            ca.copyto(self.x.grad_array[start:end], self.outputs[i].grad_array)


class Transpose(Unary):
    def __init__(self, contiguous=False):
        self.contiguous = contiguous

    def setup(self):
        if len(self.x.shape) == 1:
            self.shape = (1,) + self.x.shape
        elif len(self.x.shape) == 2:
            self.shape = tuple(reversed(self.x.shape))
        else:
            raise ValueError('invalid shape for transpose: %s'
                             % str(self.x.shape))
        self.array = ca.zeros(self.shape)
        self.grad_array = ca.zeros(self.shape)

    def fprop(self):
        self.array = ca.transpose(self.x.array)
        if self.contiguous:
            self.array = ca.ascontiguousarray(self.array)

    def bprop(self):
        self.x.grad_array = ca.transpose(self.grad_array)
        if self.contiguous:
            self.array = ca.ascontiguousarray(self.x.grad_array)



class VSplit(Op, SplitMixin):