How to call nonlinear solver in MathOptInterface

I am trying to move from MathProgBase to MathOptInterface. My code works for the former package, but after I rewrote it using the latter package, I got an error saying Ipopt: Failed to construct problem. I believe it is because I could not find the correct way to construct the non-linear model. In MathProgBase, it is

model = MathProgBase.NonlinearModel(IpoptSolver())

But I couldn’t find the corresponding one in MathOptInterface. Currently, I wrote

model = Ipopt.Optimizer()

I think it should be something like Ipopt.NLOptimizer() instead. Just incase the other part of my code is wrong, I post all the codes below.

ipopt_gradient(x) = FiniteDiff.finite_difference_gradient(fun_objective, x)

mutable struct matching_ipopt <: MOI.AbstractNLPEvaluator
    enable_hessian::Bool
end

function MOI.initialize(d::matching_ipopt, requested_features::Vector{Symbol})
    for feat in requested_features
        if !(feat in MOI.features_available(d))
            error("Unsupported feature $feat")
        end
    end
end

function MOI.features_available(d::matching_ipopt)
    if d.enable_hessian
        return [:Grad, :Hess]
    else
        return [:Grad]
    end
end

MOI.eval_objective(d::matching_ipopt, x) = fun_objective(x)

MOI.eval_constraint(d::matching_ipopt, g, x) = nothing

function MOI.eval_objective_gradient(d::matching_ipopt, grad_f, x)
    gradient_temp = ipopt_gradient(x)
    grad_f[1] = gradient_temp[1]
    grad_f[2] = gradient_temp[2]
    grad_f[3] = gradient_temp[3]
    grad_f[4] = gradient_temp[4]
    grad_f[5] = gradient_temp[5]
end

model = Ipopt.Optimizer() # How to construct the nonlinear model?

l = [-20.0, 0.0, -20.0, -20.0, -20.0]
u = [20.0, 0.0, 20.0, 20.0, 20.0]
lb = Float64[]
ub = Float64[]
start = [1.0, 1.0, 1.0, 1.0, 1.0]
block_data = MOI.NLPBlockData(MOI.NLPBoundsPair.(lb, ub), matching_ipopt(0), true)
MOI.set(model, MOI.NLPBlock(), block_data)
MOI.set(model, MOI.ObjectiveSense(), MOI.MIN_SENSE)
MOI.optimize!(model)

Ipopt.Optimizer is correct.

In your example, you need to add some variables with MOI.add_variables(model, 5).

Note that it’s easier to help if you can provide a complete working example: PSA: make it easier to help you. In this case, I don’t know what fun_objective is, or which packages you are using.

Thank you. I believe you are correct. Now the code works.

Could you tell me what the following code means in the nlp example? Thank you.

MOI.supports(model, MOI.NLPBlock())
MOI.supports_constraint(model, MOI.SingleVariable, MOI.LessThan{Float64})
MOI.supports_constraint(model, MOI.SingleVariable, MOI.GreaterThan{Float64})
MOI.supports(model, MOI.VariablePrimalStart(), MOI.VariableIndex)

I am not sure if I should include it in my code.


It seems that I also forgot to add_constraint. I corrected it and attached the new code for anyone interested.

mutable struct matching_ipopt <: MOI.AbstractNLPEvaluator
    enable_hessian::Bool
end

function MOI.initialize(d::matching_ipopt, requested_features::Vector{Symbol})
    for feat in requested_features
        if !(feat in MOI.features_available(d))
            error("Unsupported feature $feat")
        end
    end
end

function MOI.features_available(d::matching_ipopt)
    if d.enable_hessian
        return [:Grad, :Hess]
    else
        return [:Grad]
    end
end

MOI.eval_objective(d::matching_ipopt, x) = fun_objective(x)

MOI.eval_constraint(d::matching_ipopt, g, x) = nothing

function MOI.eval_objective_gradient(d::matching_ipopt, grad_f, x)
    gradient_temp = fun_gradient(fun_objective, x)
    grad_f[1] = gradient_temp[1]
    grad_f[2] = gradient_temp[2]
    grad_f[3] = gradient_temp[3]
    grad_f[4] = gradient_temp[4]
    grad_f[5] = gradient_temp[5]
end

model = Ipopt.Optimizer(max_iter=1000)
lb = Float64[]
ub = Float64[]
block_data = MOI.NLPBlockData(MOI.NLPBoundsPair.(lb, ub), matching_ipopt(0), true)
v = MOI.add_variables(model, 5)
l = [-20.0, 0.0, -20.0, -20.0, -20.0]
u = [20.0, 20.0, 20.0, 20.0, 20.0]
start = [1.0, 1.0, 1.0, 1.0, 1.0] # starting value
for i in 1:5
    cub = MOI.add_constraint(model, MOI.SingleVariable(v[i]), MOI.LessThan(u[i]))
    clb = MOI.add_constraint(model, MOI.SingleVariable(v[i]), MOI.GreaterThan(l[i]))
    MOI.set(model, MOI.VariablePrimalStart(), v[i], start[i])
end

MOI.set(model, MOI.NLPBlock(), block_data)
MOI.set(model, MOI.ObjectiveSense(), MOI.MIN_SENSE)
@time MOI.optimize!(model)

#get results
ipopt_status = MOI.get(model, MOI.TerminationStatus())
ipopt_solution = MOI.get(model, MOI.VariablePrimal(), v)
ipopt_objval = MOI.get(model, MOI.ObjectiveValue())