human
Complete this python program:
def check_grad(layer, x0, seed=1, eps=None, rtol=None, atol=None):
assistant
#Here is the Python code you requested.

    """Numerical gradient checking of layer bprop.
    """
    def fun(x):
        ca.random.seed(seed)
        y = np.array(layer.fprop(ca.array(x))).astype(np.float_)
        return np.sum(y)
    def fun_grad(x):
        y = layer.fprop(ca.array(x))
        y_grad = ca.ones_like(y, dtype=ca.float_)
        x_grad = np.array(layer.bprop(y_grad))
        return x_grad
    g_approx = approx_fprime(x0, fun, eps)
    g_true = fun_grad(x0)
    assert gradclose(g_true, g_approx, rtol, atol)
    if isinstance(layer, ParamMixin):
        def fun(x, p_idx):
            ca.random.seed(seed)
            param_array = layer.params[p_idx].array
            param_array *= 0
            param_array += ca.array(x)
            y = np.array(layer.fprop(ca.array(x0))).astype(np.float_)
            return np.sum(y)
        def fun_grad(x, p_idx):
            param_array = layer.params[p_idx].array
            param_array *= 0
            param_array += ca.array(x)
            out = layer.fprop(ca.array(x0))
            y_grad = ca.ones_like(out, dtype=ca.float_)
            layer.bprop(y_grad)
            param_grad = np.array(layer.params[p_idx].grad())
            return param_grad.astype(np.float_)
        for (p_idx, p) in enumerate(layer.params):
            x = np.array(layer.params[p_idx].array)
            g_true = fun_grad(x, p_idx)
            g_approx = approx_fprime(x, fun, eps, p_idx)
            assert gradclose(g_true, g_approx, rtol, atol)