def check_gradients(x, model=None, delta=1e-10):
    """Compute gradients using symmetric differences.

    x:     The expression to compute gradients of.
    model: Optional list of parameters to compute gradients with respect to.

    This is extremely slow and is used only for debugging."""

    if model is None:
        model = [subx for subx in expr.topological(x) if isinstance(subx, expr.parameter)]

    gradients = {}
    for param in model:
        g = numpy.empty_like(param.value)
        it = numpy.nditer([param.value, g], [], [['readwrite'], ['writeonly']])
        for pi, gi in it:
            save = pi
            pi -= delta/2
            val_minus = compute_values(x)[x]
            pi += delta
            val_plus = compute_values(x)[x]
            pi[...] = save
            gi[...] = (val_plus-val_minus)/delta
        gradients[param] = g
    return gradients
def compute_values(x, initvalues={}):
    """Evaluate an expression and all its subexpressions.

    x:          The expression to evaluate.
    initvalues: Optional dictionary from subexpressions to
                precomputed values; can be used to continue a
                computation when the expression grows.
    """
    values = collections.OrderedDict()

    for subx in expr.topological(x):
        if subx in initvalues:
            values[subx] = initvalues[subx]
        else:
            try:
                subx.forward(values)
            except:
                if logging.debug:
                    sys.stderr.write("Expression traceback (most recent call last):\n" + "".join(logging.format_list(subx.stack)))
                raise
            if logging.trace:
                sys.stdout.write("<%s> = %s = %s" % (subx.serial, subx, format_value(values[subx])))

    return values