Problem Description
In the docstring for the Optimizer
class, you write that parameters without bounds should get -inf
/ inf
.
When I do this, I get a lot of RuntimeWarnings in minimize.py:640.
Analysis
The relevant lines are 634 and 640:
v = np.sign(self.grad) + (self.grad == 0)
bounds = ((1 + v)*self.lb + (1 - v)*self.ub)/2
The RuntimeWarning
stems not from the infinite values but from a np.nan
that appears when multiplying 0*np.inf
.
Here is an minimal example to see this:
import numpy as np
ub = np.array([3, 3, 3, np.inf])
lb = np.array([-np.inf, 0, 0, 0])
grad = np.array([-3, 0, 3, -3])
# v: -1 where grad < 0, 1 where grad >= 0
v = np.sign(grad) + (grad == 0)
# (1 + v) / 2 = [0, 1, 1, 0], (1 - v) / 2 = [1, 0, 0, 1]
summand1 = (1 + v) / 2 * lb # 0 * -np.inf causes the runtime warning
summand2 = (1 - v) / 2 * ub
bounds = summand1 + summand2
bounds
If I understand your code right, you are implementing an if condition: Choose the lower bounds when the gradient is weakly positive and the upper bound otherwise.
However, there is one exception to this: when the not chosen bound is +/- inf
. In that case your bounds are NaN which is what causes the RuntimeWarning
.
Solution Proposal
If that NaN is not wanted, a one line solution that avoids the RuntimeWarning
is np.where(grad<0, ub, lb)
. If that NaN is important you can still get the same behavior in three lines without triggering the Warning:
bounds2 = np.where(grad<0, ub, lb)
# you need the np.logical_and here because the arrays are numpy bools
bounds2[np.logical_and(grad<0, ~np.isfinite(lb))] = np.nan
bounds2[np.logical_and(grad>=0, ~np.isfinite(ub))] = np.nan
Specification
I am using the latest numpy
: 1.21.4 and the latest Fides: 0.7.1