'Gives the (sub/super)gradient of the expression w.r.t. each variable.
Matrix expressions are vectorized, so the gradient is a matrix.
None indicates variable values unknown or outside domain.
Returns:
A map of variable to SciPy CSC sparse matrix or None.'

@property
def grad(self):

    if self.is_constant():
        return u.grad.constant_grad(self)
    arg_values = []
    for arg in self.args:
        if (arg.value is None):
            return u.grad.error_grad(self)
        else:
            arg_values.append(arg.value)
    grad_self = self._grad(arg_values)
    result = {}
    for (idx, arg) in enumerate(self.args):
        grad_arg = arg.grad
        for key in grad_arg:
            if ((grad_arg[key] is None) or (grad_self[idx] is None)):
                result[key] = None
            else:
                D = (grad_arg[key] * grad_self[idx])
                if ((not np.isscalar(D)) and (D.shape == (1, 1))):
                    D = D[(0, 0)]
                if (key in result):
                    result[key] += D
                else:
                    result[key] = D
    return result
