Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MOI interface moved to ext #268

Merged
merged 6 commits into from
Mar 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 7 additions & 3 deletions Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,8 @@ uuid = "2621e9c9-9eb4-46b1-8089-e8c72242dfb6"
version = "0.7.0"

[deps]
Libdl = "8f399da3-3557-5675-b5ff-fb832c97cbdb"
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
Logging = "56ddb016-857b-54e1-b83d-db4d58db5568"
MathOptInterface = "b8f27783-ece8-5eb3-8dc8-9495eed66fee"
NLPModels = "a4795742-8479-5a88-8948-cc11e1c8c1a6"
Pkg = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f"
Printf = "de0858da-6303-5e67-8744-51eddeeeb8d7"
Expand All @@ -22,6 +20,12 @@ NLPModels = "~0.17.2, 0.18, 0.19, 0.20"
SolverCore = "~0.3"
julia = "1.9"

[weakdeps]
MathOptInterface = "b8f27783-ece8-5eb3-8dc8-9495eed66fee"

[extensions]
MadNLPMOI = "MathOptInterface"

[extras]
MINLPTests = "ee0a3090-8ee9-5cdb-b8cb-8eeba3165522"
Quadmath = "be4d8f0f-7fa4-5f49-b795-2f01399ab2dd"
Expand All @@ -30,4 +34,4 @@ Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"

[targets]
test = ["Test", "MadNLPTests", "MINLPTests", "Random", "Quadmath"]
test = ["Test", "MadNLPTests", "MINLPTests", "Random", "MathOptInterface", "Quadmath"]
100 changes: 51 additions & 49 deletions src/Interfaces/MOI_interface.jl → ext/MadNLPMOI/MadNLPMOI.jl
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# MadNLP.jl
# Modified from Ipopt.jl (https://github.com/jump-dev/Ipopt.jl)
module MadNLPMOI

import MadNLP, MathOptInterface, NLPModels

const MOI = MathOptInterface
const MOIU = MathOptInterface.Utilities

include("utils.jl")

Expand All @@ -15,9 +19,9 @@ _is_parameter(term::MOI.ScalarAffineTerm) = _is_parameter(term.variable)
Create a new MadNLP optimizer.
"""
mutable struct Optimizer <: MOI.AbstractOptimizer
solver::Union{Nothing,MadNLPSolver}
nlp::Union{Nothing,AbstractNLPModel}
result::Union{Nothing,MadNLPExecutionStats{Float64}}
solver::Union{Nothing,MadNLP.MadNLPSolver}
nlp::Union{Nothing,NLPModels.AbstractNLPModel}
result::Union{Nothing,MadNLP.MadNLPExecutionStats{Float64}}

name::String
invalid_model::Bool
Expand All @@ -41,7 +45,7 @@ mutable struct Optimizer <: MOI.AbstractOptimizer
nlp_model::Union{Nothing,MOI.Nonlinear.Model}
end

function Optimizer(; kwargs...)
function MadNLP.Optimizer(; kwargs...)
option_dict = Dict{Symbol, Any}()
for (name, value) in kwargs
option_dict[name] = value
Expand Down Expand Up @@ -83,7 +87,7 @@ const _FUNCTIONS = Union{
MOI.ScalarNonlinearFunction,
}

MOI.get(::Optimizer, ::MOI.SolverVersion) = version()
MOI.get(::Optimizer, ::MOI.SolverVersion) = MadNLP.version()

### _EmptyNLPEvaluator

Expand Down Expand Up @@ -739,31 +743,31 @@ function MOI.eval_hessian_lagrangian(model::Optimizer, H, x, σ, μ)
end

### NLPModels wrapper
struct MOIModel{T} <: AbstractNLPModel{T,Vector{T}}
meta::NLPModelMeta{T, Vector{T}}
struct MOIModel{T} <: NLPModels.AbstractNLPModel{T,Vector{T}}
meta::NLPModels.NLPModelMeta{T, Vector{T}}
model::Optimizer
counters::NLPModels.Counters
end

obj(nlp::MOIModel, x::AbstractVector{Float64}) = MOI.eval_objective(nlp.model,x)
NLPModels.obj(nlp::MOIModel, x::AbstractVector{Float64}) = MOI.eval_objective(nlp.model,x)

function grad!(nlp::MOIModel, x::AbstractVector{Float64}, g::AbstractVector{Float64})
function NLPModels. grad!(nlp::MOIModel, x::AbstractVector{Float64}, g::AbstractVector{Float64})
MOI.eval_objective_gradient(nlp.model, g, x)
end

function cons!(nlp::MOIModel, x::AbstractVector{Float64}, c::AbstractVector{Float64})
function NLPModels. cons!(nlp::MOIModel, x::AbstractVector{Float64}, c::AbstractVector{Float64})
MOI.eval_constraint(nlp.model, c, x)
end

function jac_coord!(nlp::MOIModel, x::AbstractVector{Float64}, jac::AbstractVector{Float64})
function NLPModels. jac_coord!(nlp::MOIModel, x::AbstractVector{Float64}, jac::AbstractVector{Float64})
MOI.eval_constraint_jacobian(nlp.model, jac, x)
end

function hess_coord!(nlp::MOIModel, x::AbstractVector{Float64}, l::AbstractVector{Float64}, hess::AbstractVector{Float64}; obj_weight::Float64=1.0)
function NLPModels. hess_coord!(nlp::MOIModel, x::AbstractVector{Float64}, l::AbstractVector{Float64}, hess::AbstractVector{Float64}; obj_weight::Float64=1.0)
MOI.eval_hessian_lagrangian(nlp.model, hess, x, obj_weight, l)
end

function hess_structure!(nlp::MOIModel, I::AbstractVector{T}, J::AbstractVector{T}) where T
function NLPModels. hess_structure!(nlp::MOIModel, I::AbstractVector{T}, J::AbstractVector{T}) where T
@assert length(I) == length(J) == length(MOI.hessian_lagrangian_structure(nlp.model))
cnt = 1
for (row, col) in MOI.hessian_lagrangian_structure(nlp.model)
Expand All @@ -772,7 +776,7 @@ function hess_structure!(nlp::MOIModel, I::AbstractVector{T}, J::AbstractVector{
end
end

function jac_structure!(nlp::MOIModel, I::AbstractVector{T}, J::AbstractVector{T}) where T
function NLPModels.jac_structure!(nlp::MOIModel, I::AbstractVector{T}, J::AbstractVector{T}) where T
@assert length(I) == length(J) == length(MOI.jacobian_structure(nlp.model))
cnt = 1
for (row, col) in MOI.jacobian_structure(nlp.model)
Expand Down Expand Up @@ -856,7 +860,7 @@ function MOIModel(model::Optimizer)
end

return MOIModel(
NLPModelMeta(
NLPModels.NLPModelMeta(
nvar,
x0 = x0,
lvar = model.variables.lower,
Expand Down Expand Up @@ -894,37 +898,34 @@ function MOI.optimize!(model::Optimizer)
if model.silent
model.options[:print_level] = MadNLP.ERROR
end
model.solver = MadNLPSolver(model.nlp; model.options...)
model.result = solve!(model.solver)
model.solver = MadNLP.MadNLPSolver(model.nlp; model.options...)
model.result = MadNLP.solve!(model.solver)
model.solve_time = model.solver.cnt.total_time
model.solve_iterations = model.solver.cnt.k
return
end

# From Ipopt/src/Interfaces/IpReturnCodes_inc.h
const _STATUS_CODES = Dict{Status,MOI.TerminationStatusCode}(
SOLVE_SUCCEEDED => MOI.LOCALLY_SOLVED,
SOLVED_TO_ACCEPTABLE_LEVEL => MOI.ALMOST_LOCALLY_SOLVED,
SEARCH_DIRECTION_BECOMES_TOO_SMALL => MOI.SLOW_PROGRESS,
DIVERGING_ITERATES => MOI.INFEASIBLE_OR_UNBOUNDED,
INFEASIBLE_PROBLEM_DETECTED => MOI.LOCALLY_INFEASIBLE,
MAXIMUM_ITERATIONS_EXCEEDED => MOI.ITERATION_LIMIT,
MAXIMUM_WALLTIME_EXCEEDED => MOI.TIME_LIMIT,
INITIAL => MOI.OPTIMIZE_NOT_CALLED,
# REGULAR
# RESTORE
# ROBUST
RESTORATION_FAILED => MOI.NUMERICAL_ERROR,
INVALID_NUMBER_DETECTED => MOI.INVALID_MODEL,
ERROR_IN_STEP_COMPUTATION => MOI.NUMERICAL_ERROR,
NOT_ENOUGH_DEGREES_OF_FREEDOM => MOI.INVALID_MODEL,
USER_REQUESTED_STOP => MOI.INTERRUPTED,
INTERNAL_ERROR => MOI.OTHER_ERROR,
INVALID_NUMBER_OBJECTIVE => MOI.INVALID_MODEL,
INVALID_NUMBER_GRADIENT => MOI.INVALID_MODEL,
INVALID_NUMBER_CONSTRAINTS => MOI.INVALID_MODEL,
INVALID_NUMBER_JACOBIAN => MOI.INVALID_MODEL,
INVALID_NUMBER_HESSIAN_LAGRANGIAN => MOI.INVALID_MODEL,
const _STATUS_CODES = Dict{MadNLP.Status,MOI.TerminationStatusCode}(
MadNLP.SOLVE_SUCCEEDED => MOI.LOCALLY_SOLVED,
MadNLP.SOLVED_TO_ACCEPTABLE_LEVEL => MOI.ALMOST_LOCALLY_SOLVED,
MadNLP.SEARCH_DIRECTION_BECOMES_TOO_SMALL => MOI.SLOW_PROGRESS,
MadNLP.DIVERGING_ITERATES => MOI.INFEASIBLE_OR_UNBOUNDED,
MadNLP.INFEASIBLE_PROBLEM_DETECTED => MOI.LOCALLY_INFEASIBLE,
MadNLP.MAXIMUM_ITERATIONS_EXCEEDED => MOI.ITERATION_LIMIT,
MadNLP.MAXIMUM_WALLTIME_EXCEEDED => MOI.TIME_LIMIT,
MadNLP.INITIAL => MOI.OPTIMIZE_NOT_CALLED,
MadNLP.RESTORATION_FAILED => MOI.NUMERICAL_ERROR,
MadNLP.INVALID_NUMBER_DETECTED => MOI.INVALID_MODEL,
MadNLP.ERROR_IN_STEP_COMPUTATION => MOI.NUMERICAL_ERROR,
MadNLP.NOT_ENOUGH_DEGREES_OF_FREEDOM => MOI.INVALID_MODEL,
MadNLP.USER_REQUESTED_STOP => MOI.INTERRUPTED,
MadNLP.INTERNAL_ERROR => MOI.OTHER_ERROR,
MadNLP.INVALID_NUMBER_OBJECTIVE => MOI.INVALID_MODEL,
MadNLP.INVALID_NUMBER_GRADIENT => MOI.INVALID_MODEL,
MadNLP.INVALID_NUMBER_CONSTRAINTS => MOI.INVALID_MODEL,
MadNLP.INVALID_NUMBER_JACOBIAN => MOI.INVALID_MODEL,
MadNLP.INVALID_NUMBER_HESSIAN_LAGRANGIAN => MOI.INVALID_MODEL,
)

### MOI.ResultCount
Expand Down Expand Up @@ -953,7 +954,7 @@ function MOI.get(model::Optimizer, ::MOI.RawStatusString)
elseif model.solver === nothing
return "Optimize not called"
end
return get_status_output(model.result.status, model.result.options)
return MadNLP.get_status_output(model.result.status, model.result.options)
end


Expand All @@ -964,11 +965,11 @@ function MOI.get(model::Optimizer, attr::MOI.PrimalStatus)
return MOI.NO_SOLUTION
end
status = model.result.status
if status == SOLVE_SUCCEEDED
if status == MadNLP.SOLVE_SUCCEEDED
return MOI.FEASIBLE_POINT
elseif status == SOLVED_TO_ACCEPTABLE_LEVEL
elseif status == MadNLP.SOLVED_TO_ACCEPTABLE_LEVEL
return MOI.NEARLY_FEASIBLE_POINT
elseif status == INFEASIBLE_PROBLEM_DETECTED
elseif status == MadNLP.INFEASIBLE_PROBLEM_DETECTED
return MOI.INFEASIBLE_POINT
else
return MOI.UNKNOWN_RESULT_STATUS
Expand All @@ -982,11 +983,11 @@ function MOI.get(model::Optimizer, attr::MOI.DualStatus)
return MOI.NO_SOLUTION
end
status = model.result.status
if status == SOLVE_SUCCEEDED
if status == MadNLP.SOLVE_SUCCEEDED
return MOI.FEASIBLE_POINT
elseif status == SOLVED_TO_ACCEPTABLE_LEVEL
elseif status == MadNLP.SOLVED_TO_ACCEPTABLE_LEVEL
return MOI.NEARLY_FEASIBLE_POINT
elseif status == INFEASIBLE_PROBLEM_DETECTED
elseif status == MadNLP.INFEASIBLE_PROBLEM_DETECTED
return MOI.INFEASIBLE_POINT
else
return MOI.UNKNOWN_RESULT_STATUS
Expand Down Expand Up @@ -1122,3 +1123,4 @@ end
### MOI.BarrierIterations
MOI.get(model::Optimizer,::MOI.BarrierIterations) = model.solve_iterations

end # module
File renamed without changes.
1 change: 0 additions & 1 deletion src/Interfaces/interfaces.jl

This file was deleted.

1 change: 0 additions & 1 deletion src/LinearSolvers/linearsolvers.jl
Original file line number Diff line number Diff line change
Expand Up @@ -145,4 +145,3 @@ include("lapack.jl")
include("umfpack.jl")
include("cholmod.jl")
include("ldl.jl")

10 changes: 2 additions & 8 deletions src/MadNLP.jl
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
module MadNLP

import Pkg.TOML: parsefile
import MathOptInterface
import Libdl: dlopen, dlext, RTLD_DEEPBIND, RTLD_GLOBAL
import Printf: @sprintf
import LinearAlgebra: BLAS, Adjoint, Symmetric, mul!, ldiv!, norm, dot, diagind, normInf, transpose!, issuccess
import LinearAlgebra: cholesky, qr, lu, cholesky!, axpy!
Expand All @@ -11,12 +9,8 @@ import SparseArrays: SparseArrays, AbstractSparseMatrix, SparseMatrixCSC, sparse
import Base: string, show, print, size, getindex, copyto!, @kwdef
import SuiteSparse: UMFPACK, CHOLMOD
import NLPModels
import NLPModels: finalize, AbstractNLPModel, obj, grad!, cons!, jac_coord!, hess_coord!, hess_structure!, jac_structure!, NLPModelMeta, get_nvar, get_ncon, get_minimize, get_x0, get_y0, get_nnzj, get_nnzh, get_lvar, get_uvar, get_lcon, get_ucon, Counters as _Counters # get_zl,get_zu
import NLPModels: finalize, AbstractNLPModel, obj, grad!, cons!, jac_coord!, hess_coord!, hess_structure!, jac_structure!, NLPModelMeta, get_nvar, get_ncon, get_minimize, get_x0, get_y0, get_nnzj, get_nnzh, get_lvar, get_uvar, get_lcon, get_ucon
import SolverCore: solve!, getStatus, AbstractOptimizationSolver, AbstractExecutionStats

const MOI = MathOptInterface
const MOIU = MathOptInterface.Utilities

export MadNLPSolver, MadNLPOptions, UmfpackSolver, LDLSolver, CHOLMODSolver, LapackCPUSolver, madnlp, solve!

# Version info
Expand All @@ -32,6 +26,6 @@ include(joinpath("KKT", "KKTsystem.jl"))
include(joinpath("LinearSolvers","linearsolvers.jl"))
include("options.jl")
include(joinpath("IPM", "IPM.jl"))
include(joinpath("Interfaces","interfaces.jl"))
include("extension_templates.jl")

end # end module
6 changes: 6 additions & 0 deletions src/extension_templates.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
"""
Optimizer()

Create a new MadNLP optimizer.
"""
function Optimizer end
3 changes: 2 additions & 1 deletion test/MOI_interface_test.jl
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ module TestMOIWrapper
using MadNLP
using Test

const MOI = MadNLP.MathOptInterface
using MathOptInterface
const MOI = MathOptInterface

function runtests()
for name in names(@__MODULE__; all = true)
Expand Down
Loading