scipy.optimize_scalar() gives "UnboundLocalError: local variable 'fu' referenced before assignment"

Viewed 416

I am solving some consumer's problem, optimizing over some choices. I am trying to use the optimize.minimize_scalar() function from scipy, but I get an error:

Traceback (most recent call last):
  File "/Users/User/Documents/GitHub/dynamic_programming/model_our_paper.py", line 238, in <module>
    sol_C, sol_V = model.solve()
  File "/Users/User/Documents/GitHub/dynamic_programming/model_our_paper.py", line 69, in solve
    obj_func, bounds=[0, k], method='bounded'
  File "/Users/User/opt/anaconda3/lib/python3.7/site-packages/scipy/optimize/_minimize.py", line 790, in minimize_scalar
    return _minimize_scalar_bounded(fun, bounds, args, **options)
  File "/Users/User/opt/anaconda3/lib/python3.7/site-packages/scipy/optimize/optimize.py", line 1880, in _minimize_scalar_bounded
    if np.isnan(xf) or np.isnan(fx) or np.isnan(fu):
UnboundLocalError: local variable 'fu' referenced before assignment

I'm not sure how much of the code you need, as I can't think of a way to provide my code with an example so that you can reproduce. If you have any suggestions, please comment. But the parts of the code which raises the error is the following:

def solve(self):
    shape = (self.T, 2, 50)
    sol_C = np.nan * np.zeros(shape)
    sol_V = np.nan * np.zeros(shape)

    # Last period, consume all.
    for L in (0, 1):
        sol_C[self.T-1, L, :] = self.grid_K.copy()
        sol_V[self.T-1, L, :] = self.utility_f(sol_C[self.T-1, L, :], L)

    # Loop over all other periods.
    for t in range(self.T-2, -1, -1):
        for L in (0, 1):
            for k_i, k in enumerate(self.grid_K):
                obj_func = lambda x: -self.value_of_choice(
                    x, L, k, self.grid_K, sol_V[t+1, :, :]
                )
                result = optimize.minimize_scalar(
                    obj_func, bounds=[0, k], method='bounded'
                )

                sol_C[t, L, k_i] = result.x
                sol_V[t, L, k_i] = result.fun
    return sol_C, sol_V

def value_of_choice(self, x, L, k, K_next, V_next):
    K_plus = k*(1 - self.delta) + L
    EV_next = self.interp_linear_1d_scalar(
        K_next, V_next[L, :], K_plus
    )

    V_guess = self.utility_f(x, L) + self.beta*EV_next
    return V_guess

I tried the following, which worked:

from scipy import optimize

f = lambda x: (x - 2)*x*(x - 1)**2
k = 10
res = optimize.minimize_scalar(f, bounds=[0, k], method='bounded')
print(res.x)

I am on a Macbook with updated MacOS. Tried to update Scipy, and reinstalled my python build, which I have from Anaconda.

1 Answers

Thanks to @rpoleski and @WarrenWeckesser for helping me solve this. It seems to be a bug that occurs when the bounds are equal, which is the case. There seems to be an update for this bug, but it still seems to be in development.

So my work around is to just add a little to the upper bound. Interestingly, this does not work:

result = optimize.minimize_scalar(
                        obj_func, bounds=[0, k+1.0e-5], method='bounded'
                    )

But this works:

result = optimize.minimize_scalar(
                        obj_func, bounds=[0, k+1.0e-4], method='bounded'
                    )
Related