# Buggy code
def _minimize_scalar_bounded(
    func, bounds, args=(), xatol=1e-5, maxiter=500, disp=0, **unknown_options
):
    """
    Options
    -------
    maxiter : int
        Maximum number of iterations to perform.
    disp: int, optional
        If non-zero, print messages.
            0 : no message printing.
            1 : non-convergence notification messages only.
            2 : print a message on convergence too.
            3 : print iteration results.
    xatol : float
        Absolute error in solution `xopt` acceptable for convergence.

    """
    _check_unknown_options(unknown_options)
    maxfun = maxiter
    # Test bounds are of correct form
    if len(bounds) != 2:
        raise ValueError("bounds must have two elements.")
    x1, x2 = bounds

    if not (is_array_scalar(x1) and is_array_scalar(x2)):
        raise ValueError("Optimization bounds must be scalars or array scalars.")
    if x1 > x2:
        raise ValueError("The lower bound exceeds the upper bound.")

    flag = 0
    header = " Func-count     x          f(x)          Procedure"
    step = "       initial"

    sqrt_eps = sqrt(2.2e-16)
    golden_mean = 0.5 * (3.0 - sqrt(5.0))
    a, b = x1, x2
    fulc = a + golden_mean * (b - a)
    nfc, xf = fulc, fulc
    rat = e = 0.0
    x = xf
    fx = func(x, *args)
    num = 1
    fmin_data = (1, xf, fx)

    ffulc = fnfc = fx
    xm = 0.5 * (a + b)
    tol1 = sqrt_eps * numpy.abs(xf) + xatol / 3.0
    tol2 = 2.0 * tol1

    if disp > 2:
        print(" ")
        print(header)
        print("%5.0f   %12.6g %12.6g %s" % (fmin_data + (step,)))

    while numpy.abs(xf - xm) > (tol2 - 0.5 * (b - a)):
        golden = 1
        # Check for parabolic fit
        if numpy.abs(e) > tol1:
            golden = 0
            r = (xf - nfc) * (fx - ffulc)
            q = (xf - fulc) * (fx - fnfc)
            p = (xf - fulc) * q - (xf - nfc) * r
            q = 2.0 * (q - r)
            if q > 0.0:
                p = -p
            q = numpy.abs(q)
            r = e
            e = rat

            # Check for acceptability of parabola
            if (
                (numpy.abs(p) < numpy.abs(0.5 * q * r))
                and (p > q * (a - xf))
                and (p < q * (b - xf))
            ):
                rat = (p + 0.0) / q
                x = xf + rat
                step = "       parabolic"

                if ((x - a) < tol2) or ((b - x) < tol2):
                    si = numpy.sign(xm - xf) + ((xm - xf) == 0)
                    rat = tol1 * si
            else:  # do a golden-section step
                golden = 1

        if golden:  # do a golden-section step
            if xf >= xm:
                e = a - xf
            else:
                e = b - xf
            rat = golden_mean * e
            step = "       golden"

        si = numpy.sign(rat) + (rat == 0)
        x = xf + si * numpy.max([numpy.abs(rat), tol1])
        fu = func(x, *args)
        num += 1
        fmin_data = (num, x, fu)
        if disp > 2:
            print("%5.0f   %12.6g %12.6g %s" % (fmin_data + (step,)))

        if fu <= fx:
            if x >= xf:
                a = xf
            else:
                b = xf
            fulc, ffulc = nfc, fnfc
            nfc, fnfc = xf, fx
            xf, fx = x, fu
        else:
            if x < xf:
                a = x
            else:
                b = x
            if (fu <= fnfc) or (nfc == xf):
                fulc, ffulc = nfc, fnfc
                nfc, fnfc = x, fu
            elif (fu <= ffulc) or (fulc == xf) or (fulc == nfc):
                fulc, ffulc = x, fu

        xm = 0.5 * (a + b)
        tol1 = sqrt_eps * numpy.abs(xf) + xatol / 3.0
        tol2 = 2.0 * tol1

        if num >= maxfun:
            flag = 1
            break

    if np.isnan(xf) or np.isnan(fx) or np.isnan(fu):
        flag = 2

    fval = fx
    if disp > 0:
        _endprint(x, flag, fval, maxfun, xatol, disp)

    result = OptimizeResult(
        fun=fval,
        status=flag,
        success=(flag == 0),
        message={
            0: "Solution found.",
            1: "Maximum number of function calls reached.",
            2: _status_message["nan"],
        }.get(flag, ""),
        x=xf,
        nfev=num,
    )

    return result


# Traceback (UnboundLocalError)
---------------------------------------------------------------------------
UnboundLocalError                         Traceback (most recent call last)
<ipython-input-1-b2f64640c4d5> in <module>
1 import chaospy as cp
2 dist=cp.J(cp.Uniform(0, 1), cp.Uniform(0, 1))
----> 3 points = cp.generate_quadrature(2, dist, rule="Leja", sparse=True)

/usr/local/lib/python3.7/dist-packages/chaospy/quadrature/frontend.py in generate_quadrature(order, dist, rule, sparse, accuracy, growth, recurrence_algorithm)
134         from . import sparse_grid
135         return sparse_grid.construct_sparse_grid(
--> 136             order, dist, rule=rule, accuracy=accuracy, growth=growth)
137
138     if not isinstance(rule, str):

/usr/local/lib/python3.7/dist-packages/chaospy/quadrature/sparse_grid.py in construct_sparse_grid(order, dist, rule, accuracy, growth, recurrence_algorithm)
122
123     x_lookup, w_lookup = _construct_lookup(
--> 124         orders, dist, rule, accuracy, growth, recurrence_algorithm)
125     collection = _construct_collection(
126         order, dist, x_lookup, w_lookup)

/usr/local/lib/python3.7/dist-packages/chaospy/quadrature/sparse_grid.py in _construct_lookup(orders, dists, rules, accuracy, growth, recurrence_algorithm)
182                 rule=rule,
183                 growth=growth,
--> 184                 recurrence_algorithm=recurrence_algorithm,
185             )
186             x_lookup[-1].append(abscissas)

/usr/local/lib/python3.7/dist-packages/chaospy/quadrature/frontend.py in generate_quadrature(order, dist, rule, sparse, accuracy, growth, recurrence_algorithm)
157
158     quad_function = QUAD_FUNCTIONS[rule]
--> 159     abscissas, weights = quad_function(order, dist, **kwargs)
160
161     assert len(weights) == abscissas.shape[1]

/usr/local/lib/python3.7/dist-packages/chaospy/quadrature/leja.py in quad_leja(order, dist, rule, accuracy, recurrence_algorithm)
104             *[fminbound(
105                 objective, abscissas[idx], abscissas[idx+1], full_output=1)[:2]
--> 106               for idx in range(len(abscissas)-1)]
107         )
108         index = numpy.argmin(vals)

/usr/local/lib/python3.7/dist-packages/chaospy/quadrature/leja.py in <listcomp>(.0)
104             *[fminbound(
105                 objective, abscissas[idx], abscissas[idx+1], full_output=1)[:2]
--> 106               for idx in range(len(abscissas)-1)]
107         )
108         index = numpy.argmin(vals)

/usr/local/lib/python3.7/dist-packages/scipy/optimize/optimize.py in fminbound(func, x1, x2, args, xtol, maxfun, full_output, disp)
1734                'disp': disp}
1735
-> 1736     res = _minimize_scalar_bounded(func, (x1, x2), args, **options)
1737     if full_output:
1738         return res['x'], res['fun'], res['status'], res['nfev']

/usr/local/lib/python3.7/dist-packages/scipy/optimize/optimize.py in _minimize_scalar_bounded(func, bounds, args, xatol, maxiter, disp, **unknown_options)
1868             break
1869
-> 1870     if np.isnan(xf) or np.isnan(fx) or np.isnan(fu):
1871         flag = 2
1872

UnboundLocalError: local variable 'fu' referenced before assignment

# Fixed code
def _minimize_scalar_bounded(
    func, bounds, args=(), xatol=1e-5, maxiter=500, disp=0, **unknown_options
):
    """
    Options
    -------
    maxiter : int
        Maximum number of iterations to perform.
    disp: int, optional
        If non-zero, print messages.
            0 : no message printing.
            1 : non-convergence notification messages only.
            2 : print a message on convergence too.
            3 : print iteration results.
    xatol : float
        Absolute error in solution `xopt` acceptable for convergence.

    """
    _check_unknown_options(unknown_options)
    maxfun = maxiter
    # Test bounds are of correct form
    if len(bounds) != 2:
        raise ValueError("bounds must have two elements.")
    x1, x2 = bounds

    if not (is_array_scalar(x1) and is_array_scalar(x2)):
        raise ValueError("Optimization bounds must be scalars or array scalars.")
    if x1 > x2:
        raise ValueError("The lower bound exceeds the upper bound.")

    flag = 0
    header = " Func-count     x          f(x)          Procedure"
    step = "       initial"

    sqrt_eps = sqrt(2.2e-16)
    golden_mean = 0.5 * (3.0 - sqrt(5.0))
    a, b = x1, x2
    fulc = a + golden_mean * (b - a)
    nfc, xf = fulc, fulc
    rat = e = 0.0
    x = xf
    fx = func(x, *args)
    num = 1
    fmin_data = (1, xf, fx)
    fu = np.inf

    ffulc = fnfc = fx
    xm = 0.5 * (a + b)
    tol1 = sqrt_eps * numpy.abs(xf) + xatol / 3.0
    tol2 = 2.0 * tol1

    if disp > 2:
        print(" ")
        print(header)
        print("%5.0f   %12.6g %12.6g %s" % (fmin_data + (step,)))

    while numpy.abs(xf - xm) > (tol2 - 0.5 * (b - a)):
        golden = 1
        # Check for parabolic fit
        if numpy.abs(e) > tol1:
            golden = 0
            r = (xf - nfc) * (fx - ffulc)
            q = (xf - fulc) * (fx - fnfc)
            p = (xf - fulc) * q - (xf - nfc) * r
            q = 2.0 * (q - r)
            if q > 0.0:
                p = -p
            q = numpy.abs(q)
            r = e
            e = rat

            # Check for acceptability of parabola
            if (
                (numpy.abs(p) < numpy.abs(0.5 * q * r))
                and (p > q * (a - xf))
                and (p < q * (b - xf))
            ):
                rat = (p + 0.0) / q
                x = xf + rat
                step = "       parabolic"

                if ((x - a) < tol2) or ((b - x) < tol2):
                    si = numpy.sign(xm - xf) + ((xm - xf) == 0)
                    rat = tol1 * si
            else:  # do a golden-section step
                golden = 1

        if golden:  # do a golden-section step
            if xf >= xm:
                e = a - xf
            else:
                e = b - xf
            rat = golden_mean * e
            step = "       golden"

        si = numpy.sign(rat) + (rat == 0)
        x = xf + si * numpy.max([numpy.abs(rat), tol1])
        fu = func(x, *args)
        num += 1
        fmin_data = (num, x, fu)
        if disp > 2:
            print("%5.0f   %12.6g %12.6g %s" % (fmin_data + (step,)))

        if fu <= fx:
            if x >= xf:
                a = xf
            else:
                b = xf
            fulc, ffulc = nfc, fnfc
            nfc, fnfc = xf, fx
            xf, fx = x, fu
        else:
            if x < xf:
                a = x
            else:
                b = x
            if (fu <= fnfc) or (nfc == xf):
                fulc, ffulc = nfc, fnfc
                nfc, fnfc = x, fu
            elif (fu <= ffulc) or (fulc == xf) or (fulc == nfc):
                fulc, ffulc = x, fu

        xm = 0.5 * (a + b)
        tol1 = sqrt_eps * numpy.abs(xf) + xatol / 3.0
        tol2 = 2.0 * tol1

        if num >= maxfun:
            flag = 1
            break

    if np.isnan(xf) or np.isnan(fx) or np.isnan(fu):
        flag = 2

    fval = fx
    if disp > 0:
        _endprint(x, flag, fval, maxfun, xatol, disp)

    result = OptimizeResult(
        fun=fval,
        status=flag,
        success=(flag == 0),
        message={
            0: "Solution found.",
            1: "Maximum number of function calls reached.",
            2: _status_message["nan"],
        }.get(flag, ""),
        x=xf,
        nfev=num,
    )

    return result