Ipopt with MathProgBase returns Domain Error for log() function

Hi all,
I have been estimating a nonlinear model using the Ipopt solver through MathProgBase. The objective function takes sum(log.(x)) for a vector x at the end.

From what I understand, if x is ever negative, Ipopt shows the following message:
Warning: Cutting back alpha due to evaluation error
However today I ran into the following error after 200+ iterations for the first time:

ERROR: DomainError with -1.(bunch of digits)e-30:
log will only return a complex result if called with a complex argument. Try log(Complex(x)).

The objective function is quite complicated and I have not been able to come up with a MWE that would lead to the same error during Ipopt optimization. I have been running similar scripts daily for the past few months and this is the first time I see the Core DomainError, instead of Ipopt’s evaluation error message.

The cause for this error might be just some embarrassing bug that I have yet to locate, but my question is: in general, what might lead to the Domain Error during optimization (instead of having Ipopt indicate that there’s an evaluation error and just continue as usual)? I am hoping this would lead me to where my bug might be.

Thanks in advance for any suggestion.

The error is because log(x) is being called with a negative value of x. You should add constraints to prevent this, and/or choose a starting value of x such that x is feasible and non-negative.

1 Like

Hi, thank you for the response. The starting values result in positive x, so the problem doesn’t come up until after 200+ iterations. If I didn’t write a bug (which I probably did), x should be positive for all values of the variables being optimized, given the constraints and bounds I set. I am just puzzled over the difference between negative x that leads to Ipopt’s warning about evaluation error, and the negative x that would trigger the core Domain Error. I was hoping maybe knowing the difference would point me to where my bug was.

1 Like

Even though the initial x is > 0 and the solution is > 0, there’s not guarantee IPOPT won’t try values of x with negative components unless you add the constraint x ≥ 0 to your problem. Perhaps you can turn up the log level and gist IPOPT’s (long) output somewhere. It might reveal what the solver was doing when the error occured. Seeing your model might help too.

1 Like

That’s what I’m puzzled with. I though Ipopt’s evaluation error warning indicates this kind of situation, as Andreas Waechter had stated on the Ipopt mailing list.
The reason I thought this would be a Julia question is that I am getting a Julia core error, not an Ipopt warning. The latter happens frequently when we optimize with log() in the objective function without setting x > 0, whereas this is the first time I see the core Domain Error when estimating this model.
As you and @odow have suggested, it’d be easy to bypass negative x by adding an if x > 0 kind of condition or constraints. I just thought maybe the fact that I am getting the domain error points to potential concerns with my model, and was wondering how the domain error gets triggered when Ipopt already has the evaluation error for negative input to log().
Still, thank you for the response.

Your error message might come from Julia code, not IPOPT, right? Maybe it’s from some AD-related computation?

1 Like

The error comes from Ipopt calling log with a negative value.

julia> log(-1.0)
ERROR: DomainError with -1.0:
log will only return a complex result if called with a complex argument. Try log(Complex(x)).
Stacktrace:
 [1] throw_complex_domainerror(::Symbol, ::Float64) at ./math.jl:31
 [2] log(::Float64) at ./special/log.jl:285
 [3] top-level scope at none:0

In this case, it’s being called with x=-1e-30, which is approximately zero. So even if you have a constraint x >= 0, Ipopt might call it with -1e-30. You need a constraint like x >= 0.001.

1 Like

Setting bound_relax_factor to zero is likely better than introducing epsilon positive bounds: Ipopt: Ipopt Options

2 Likes

Thank you all for the suggestions. I will go ahead with bound_relax_factor, but I also really appreciate all the other input. Many thanks!