jump-dev / JuMP.jl

Modeling language for Mathematical Optimization (linear, mixed-integer, conic, semidefinite, nonlinear)
http://jump.dev/JuMP.jl/
Other
2.22k stars 393 forks source link

erf not defined #1803

Closed b-han closed 3 years ago

b-han commented 5 years ago

I'm solving a non-linear optimization problem with JuMP, there is an erf() called in my objective function. My code throws an error saying that the erf() function is not defined.

Since erf() has been moved from Base to SpecialFunctions I have called Pkg.update(), loaded the SpecialFunctions package, and swtiched among different solvers (NLopt, Itopt). Unfortunately none of them works. It occurs to me a bug in JuMP.

Here follows the environment and the minimized code which I tested.

julia> versioninfo()
Julia Version 1.0.3
Commit 099e826241 (2018-12-18 01:34 UTC)
Platform Info:
  OS: Windows (x86_64-w64-mingw32)
  CPU: Intel(R) Core(TM) i7 CPU         860  @ 2.80GHz
  WORD_SIZE: 64
  LIBM: libopenlibm
  LLVM: libLLVM-6.0.0 (ORCJIT, nehalem)
Environment:
  JULIA_EDITOR = "C:\Users\binha\AppData\Local\atom\app-1.34.0\atom.exe" -a
  JULIA_NUM_THREADS = 4

julia> Pkg.installed()
Dict{String,Union{Nothing, VersionNumber}} with 25 entries:
"Statistics"          => nothing
"GR"                  => v"0.37.0"
"Distributions"       => v"0.16.4"
"Random"              => nothing
"Atom"                => v"0.7.14"
"UUIDs"               => nothing
"FastGaussQuadrature" => v"0.3.2"
"JuMP"                => v"0.18.5"
"Juno"                => v"0.5.4"
"LinearAlgebra"       => nothing
"Ipopt"               => v"0.5.1"
"NLopt"               => v"0.5.1"
"PyCall"              => v"1.18.5"
"LaTeXStrings"        => v"1.0.3"
"SymPy"               => v"0.8.3"
"StatsBase"           => v"0.27.0"
"Plots"               => v"0.22.5"
"PyPlot"              => v"2.7.0"
"ProgressMeter"       => v"0.9.0"
"QuadGK"              => v"2.0.3"
"NLsolve"             => v"3.0.1"
"SpecialFunctions"    => v"0.7.2"
"ECOS"                => v"0.9.4"
"PoissonRandom"       => v"0.4.0"
"PlotlyJS"            => v"0.12.2"

julia> using JuMP
julia> using NLopt
julia> using SpecialFunctions

julia> erf(1)
0.8427007929497149

julia> m=Model(solver=NLoptSolver(algorithm=:LD_MMA))
Feasibility problem with:
 * 0 linear constraints
 * 0 variables
Solver is NLopt

julia> @variable(m,x,start=0.0)
x

julia> @NLobjective(m,Min,erf(x))
JuMP.NonlinearExprData(ReverseDiffSparse.NodeData[NodeData(CALLUNIVAR, 53, -1), NodeData(VARIABLE, 1, 1)], Float64[])

julia> solve(m)
ERROR: UndefVarError: erf not defined
Stacktrace:
 [1] #forward_eval#7(::ReverseDiffSparse.UserOperatorRegistry, ::Function, ::Array{Float64,1}, ::Array{Float64,1}, ::Array{ReverseDiffSparse.NodeData,1}, ::SparseArrays.SparseMatrixCSC{Bool,Int64}, ::Array{Float64,1}, ::Array{Float64,1}, ::Array{Float64,1}, ::Array{Float64,1}, ::Array{Float64,1}, ::Array{Float64,1}) at C:\Users\binha\.julia\packages\ReverseDiffSparse\gvK2V\src\forward.jl:380
 [2] #forward_eval at .\none:0 [inlined]
 [3] forward_eval_all(::JuMP.NLPEvaluator, ::Array{Float64,1}) at C:\Users\binha\.julia\packages\JuMP\PbnIJ\src\nlp.jl:445
 [4] eval_grad_f(::JuMP.NLPEvaluator, ::Array{Float64,1}, ::Array{Float64,1}) at C:\Users\binha\.julia\packages\JuMP\PbnIJ\src\nlp.jl:496
 [5] initialize(::JuMP.NLPEvaluator, ::Array{Symbol,1}) at C:\Users\binha\.julia\packages\JuMP\PbnIJ\src\nlp.jl:403
 [6] loadproblem!(::NLopt.NLoptMathProgModel, ::Int64, ::Int64, ::Array{Float64,1}, ::Array{Float64,1}, ::Array{Float64,1}, ::Array{Float64,1}, ::Symbol, ::JuMP.NLPEvaluator) at C:\Users\binha\.julia\packages\NLopt\eqN9a\src\NLoptSolverInterface.jl:117
 [7] _buildInternalModel_nlp(::Model, ::JuMP.ProblemTraits) at C:\Users\binha\.julia\packages\JuMP\PbnIJ\src\nlp.jl:1244
 [8] #build#123(::Bool, ::Bool, ::JuMP.ProblemTraits, ::Function, ::Model) at C:\Users\binha\.julia\packages\JuMP\PbnIJ\src\solvers.jl:304
 [9] #build at .\none:0 [inlined]
 [10] #solve#120(::Bool, ::Bool, ::Bool, ::Base.Iterators.Pairs{Union{},Union{},Tuple{},NamedTuple{(),Tuple{}}}, ::Function, ::Model) at C:\Users\binha\.julia\packages\JuMP\PbnIJ\src\solvers.jl:168
 [11] solve(::Model) at C:\Users\binha\.julia\packages\JuMP\PbnIJ\src\solvers.jl:150
 [12] top-level scope at none:0
odow commented 5 years ago

I can reproduce this on JuMP master.

odow commented 5 years ago

p.s., in future, please cross-reference when you post in multiple places:

https://github.com/JuliaOpt/NLopt.jl/issues/125#issuecomment-456409188

b-han commented 5 years ago

p.s., in future, please cross-reference when you post in multiple places:

JuliaOpt/NLopt.jl#125 (comment)

Yes - sorry for forgetting that

stevengj commented 5 years ago

As I commented in JuliaOpt/NLopt.jl#125, it seems to be a macro hygiene problem in JuMP, because it is not using the caller's scope to resolve the erf function.

mlubin commented 5 years ago

JuMP doesn't work with nonlinear functions by looking them up in the caller's scope; it has a table of recognized symbols. You can add to this table by calling JuMP.register and providing the proper derivatives.

This is a valid issue because erf used to work before it was moved into a separate module, but given that this affects 0.18 (so it's not a regression in 0.19) and has a workaround, I'll dispute that this issue should be a blocker for 0.19.

mlubin commented 5 years ago

I did a bit of research into transitioning to DiffRules for our built-in derivative rules, which should resolve this issue. It's more complex than I expected, because there's no drop-in replacement for Calculus's symbolic differentiation. JuMP uses symbolic differentiation for second derivatives of built-in univariate functions. Options include: