# Solver BARON with user-defined function in nonlinear constraint

Hello dear Julia-community,

I am having an issue in using BARON for a nonlinear optimization problem. The problem includes nonlinearities in the constraints with a registered user-defined function. I define the function and its gradient.

Here is a snippet of how the constraints are defined, where mvnormcdf is from this library, `inputs` contains the parameters of the model, T is an index set `T = [i for i in 1:24]` and `r, v` are defined model variables:

``````# Define the mvnormcdf and its gradient
function distribution(j, inputs)
norm_pdf(k) = exp(-(k^2) / 2) / sqrt(2 * pi)
f(x...) = mvnormcdf(inputs.Σ[j:j+3, j:j+3], inputs.a[j:j+3]- inputs.μ[j:j+3], vec([x[i] for i in eachindex(x)])- inputs.μ[j:j+3])
function ∇f(g::AbstractVector{T}, x::T...) where {T}
μ_j = inputs.μ[j:j+3]
σ_j = inputs.σ[j:j+3]
Σ_j = inputs.Σ[j:j+3, j:j+3]
a_j = inputs.a[j:j+3]
for i in eachindex(x)
Σ_new = # new definition based on above defined variables
μ_new = # new definition based on above defined variables
g[i] = # new definition based on the previous two lines
end
return
end
return f, ∇f
end

# Register functions and define nonlinear constraints
for j in eachindex(T)
register(m, Symbol("mvncdf_\$j"), 4, distribution(j, inputs), distribution(j, inputs))
x = []
for i in j:j+3
append!(x, [r[i] + v[i]])
end
# Use the mvncdf in the nonlinear constraints
end
``````

BARON’s error output is the following:

``````ERROR: UnrecognizedExpressionException: unrecognized function call expression: mvncdf_1(x + x, x + x, x + x, x + x)
Stacktrace:
 to_str(c::Expr)
@ BARON ~/.julia/packages/BARON/xgWzt/src/util.jl:156
 (::BARON.var"#8#10")(d::Expr)
@ BARON ./none:0
 iterate(::Base.Generator{Vector{Any}, BARON.var"#8#10"})
@ Base ./generator.jl:47
 collect(itr::Base.Generator{Vector{Any}, BARON.var"#8#10"})
@ Base ./array.jl:787
 to_str(c::Expr)
@ BARON ~/.julia/packages/BARON/xgWzt/src/util.jl:130
 (::BARON.var"#11#20"{BARON.BaronModel})(fp::IOStream)
@ BARON ~/.julia/packages/BARON/xgWzt/src/util.jl:230
 open(::BARON.var"#11#20"{BARON.BaronModel}, ::String, ::Vararg{String}; kwargs::Base.Pairs{Symbol, Union{}, Tuple{}, NamedTuple{(), Tuple{}}})
@ Base ./io.jl:384
 open
@ ./io.jl:381 [inlined]
 write_bar_file
@ ~/.julia/packages/BARON/xgWzt/src/util.jl:172 [inlined]
 optimize!(model::BARON.Optimizer)
@ BARON ~/.julia/packages/BARON/xgWzt/src/MOI_wrapper.jl:56
 optimize!
@ ~/.julia/packages/MathOptInterface/cl3eR/src/Bridges/bridge_optimizer.jl:376 [inlined]
 optimize!
@ ~/.julia/packages/MathOptInterface/cl3eR/src/MathOptInterface.jl:83 [inlined]
 optimize!(m::MathOptInterface.Utilities.CachingOptimizer{MathOptInterface.Bridges.LazyBridgeOptimizer{BARON.Optimizer}, MathOptInterface.Utilities.UniversalFallback{MathOptInterface.Utilities.Model{Float64}}})
@ MathOptInterface.Utilities ~/.julia/packages/MathOptInterface/cl3eR/src/Utilities/cachingoptimizer.jl:316
 optimize!(model::Model; ignore_optimize_hook::Bool, _differentiation_backend::MathOptInterface.Nonlinear.SparseReverseMode, kwargs::Base.Pairs{Symbol, Union{}, Tuple{}, NamedTuple{(), Tuple{}}})
@ JuMP ~/.julia/packages/JuMP/yYfHy/src/optimizer_interface.jl:480
 optimize!(model::Model)
@ JuMP ~/.julia/packages/JuMP/yYfHy/src/optimizer_interface.jl:450
 top-level scope
@ ~/project/Code/Main.jl:61
``````

I am not sure why BARON iterates from 190 and 136 for mvncdf_1, the expression for j = 1 should be:
mvncdf_1(r + v, r + v, r + v, r + v)

Is it a problem with my definition or with how BARON interprets this user-defined function with a given first derivative?

IPOPT managed to solve the model with this exact definition of the nonlinear constraints without any issues and with fast convergence. It is when I modify my linear objective function (to include the variable r and v in a simple summation term) that IPOPT doesn’t converge. This is why I turned to BARON, but had the error described above.

I appreciate any thoughts and suggestions!

I just tested this with SCIP as well, and I have the same issue.

I also tried solving a much simpler example, also using the user-defined function `mvnormcdf` with BARON but it didn’t work, although it does with IPOPT and NLopt.

Is it possible that BARON and SCIP can’t deal with the `mvnormcdf` function? Why does it work with IPOPT and NLopt? Can I rephrase my function definition such that it is correctly interpreted by BARON or SCIP?

The difference to note this that of the different requirements between local and global nonlinear solvers.

Local solvers like Ipopt typically only require function values and gradients/hessians that they can evaluate. Hence, they will typically support any registered function.

However, global solvers like Baron, SCIP, and EAGO only support certain functions and will not support user registered functions. The reason for this is that they will evaluate a series of subproblems that are constructed by leveraging the algebraic structure of the optimization problem. Hence, they need an algebraic structure (i.e., an expression tree) with functions that they support.

For instance, information on the functions that Baron supports is available here: BARON.

Also, the information on the functions supported by SCIP is available here: SCIP Doxygen Documentation: Frequently Asked Questions (FAQ)

2 Likes