Skip to content
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
12 changes: 2 additions & 10 deletions Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,5 @@ version = "0.6.5"
MathOptInterface = "b8f27783-ece8-5eb3-8dc8-9495eed66fee"

[compat]
JuMP = "~0.21.1"
MathOptInterface = "~0.9.5"
julia = "1"

[extras]
JuMP = "4076af6c-e467-56ae-b986-b466b2749572"
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"

[targets]
test = ["JuMP", "Test"]
MathOptInterface = "0.10.9"
julia = "1.6"
4 changes: 4 additions & 0 deletions src/BARON.jl
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ end
SYNTAX_ERROR = 10
LICENSING_ERROR = 11
USER_HEURISTIC_TERMINATION = 12
CALL_TO_EXEC_FAILED = 99 # TODO allow reach here
end

@enum BaronModelStatus begin
Expand Down Expand Up @@ -79,6 +80,8 @@ mutable struct BaronModel

solution_info::Union{Nothing, SolutionStatus}

print_input_file::Bool

function BaronModel(; kwargs...)
options = Dict{String, Any}(string(key) => val for (key,val) in kwargs)
model = new()
Expand All @@ -94,6 +97,7 @@ mutable struct BaronModel
model.summary_file_name = get!(options, "SumName", joinpath(temp_dir, "sum.lst"))
model.result_file_name = get!(options, "ResName", joinpath(temp_dir, "res.lst"))
model.solution_info = nothing
model.print_input_file = false
return model
end
end
Expand Down
35 changes: 27 additions & 8 deletions src/MOI_wrapper.jl
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ const VI = MOI.VariableIndex
const CI = MOI.ConstraintIndex

# function aliases
const SV = MOI.SingleVariable
const SAF = MOI.ScalarAffineFunction{Float64}
const SQF = MOI.ScalarQuadraticFunction{Float64}

Expand Down Expand Up @@ -42,9 +41,10 @@ function MOI.empty!(model::Optimizer)
end

# copy
MOIU.supports_default_copy_to(model::Optimizer, copy_names::Bool) = !copy_names
# MOIU.supports_default_copy_to(::Optimizer, copy_names::Bool) = !copy_names
MOI.supports_incremental_interface(::Optimizer) = true
function MOI.copy_to(dest::Optimizer, src::MOI.ModelLike; kws...)
return MOIU.automatic_copy_to(dest, src; kws...)
return MOIU.default_copy_to(dest, src; kws...)
end

# optimize
Expand All @@ -54,17 +54,27 @@ function MOI.optimize!(model::Optimizer)
Set the environment variable `BARON_EXEC` and run `using Pkg; Pkg.build("BARON")`."""))
end
write_bar_file(model.inner)
run(`$baron_exec $(model.inner.problem_file_name)`)
if model.inner.print_input_file
println("\nBARON input file: $(model.inner.problem_file_name)\n")
println(read(model.inner.problem_file_name, String))
end
try
run(`$baron_exec $(model.inner.problem_file_name)`)
catch e
println("$e")
println(read(model.inner.problem_file_name, String))
error("failed to call BARON exec $baron_exec")
end
read_results(model.inner)
end

# RawParameter
MOI.supports(::Optimizer, ::MOI.RawParameter) = true
function MOI.set(model::Optimizer, param::MOI.RawParameter, value)
# RawOptimizerAttribute
MOI.supports(::Optimizer, ::MOI.RawOptimizerAttribute) = true
function MOI.set(model::Optimizer, param::MOI.RawOptimizerAttribute, value)
model.inner.options[param.name] = value
return
end
function MOI.get(model::Optimizer, param::MOI.RawParameter)
function MOI.get(model::Optimizer, param::MOI.RawOptimizerAttribute)
return get(model.inner.options, param.name) do
throw(ErrorException("Requested parameter $(param.name) is not set."))
end
Expand All @@ -82,6 +92,15 @@ function MOI.get(model::Optimizer, ::MOI.TimeLimitSec)
return get(model.inner.options, "MaxTime", 1000.0)
end

struct PrintInputFile <: MOI.AbstractOptimizerAttribute end
function MOI.set(model::Optimizer, ::PrintInputFile, val::Bool)
model.inner.print_input_file = val
return
end
function MOI.get(model::Optimizer, ::PrintInputFile)
model.inner.print_input_file
end

include(joinpath("moi", "util.jl"))
include(joinpath("moi", "variables.jl"))
include(joinpath("moi", "constraints.jl"))
Expand Down
64 changes: 32 additions & 32 deletions src/moi/constraints.jl
Original file line number Diff line number Diff line change
Expand Up @@ -16,59 +16,59 @@ function set_bounds(info::Union{VariableInfo, ConstraintInfo}, set::MOI.Interval
set_upper_bound(info, set.upper)
end

MOI.supports_constraint(::Optimizer, ::Type{SV}, ::Type{<:Bounds}) = true
MOI.supports_constraint(::Optimizer, ::Type{MOI.VariableIndex}, ::Type{<:Bounds{Float64}}) = true

function MOI.add_constraint(model::Optimizer, f::SV, set::S) where {S <: Bounds}
variable_info = find_variable_info(model, f.variable)
function MOI.add_constraint(model::Optimizer, f::MOI.VariableIndex, set::S) where {S <: Bounds{Float64}}
variable_info = find_variable_info(model, f)
set_bounds(variable_info, set)
return CI{SV, S}(f.variable.value)
return CI{MOI.VariableIndex, S}(f.value)
end

MOI.supports_constraint(::Optimizer, ::Type{<:Union{SAF, SQF}}, ::Type{<:Bounds}) = true
MOI.supports_constraint(::Optimizer, ::Type{<:Union{SAF, SQF}}, ::Type{<:Bounds{Float64}}) = true

function MOI.add_constraint(model::Optimizer, f::F, set::S) where {F <: Union{SAF, SQF}, S <: Bounds}
function MOI.add_constraint(model::Optimizer, f::F, set::S) where {F <: Union{SAF, SQF}, S <: Bounds{Float64}}
ci = ConstraintInfo()
ci.expression = to_expr(f)
set_bounds(ci, set)
push!(model.inner.constraint_info, ci)
return CI{F, S}(length(model.inner.constraint_info))
end

MOI.supports(::Optimizer, ::MOI.ConstraintName, ::Type{CI}) = true

function MOI.set(model::Optimizer, attr::MOI.ConstraintName, ci::CI{SV}, value)
error("No support for naming constraints imposed on variables.")
end
function MOI.set(model::Optimizer, attr::MOI.ConstraintName, ci::CI, value)
check_constraint_indices(model, ci)
model.inner.constraint_info[ci.value].name = value
end
function MOI.get(model::Optimizer, ::MOI.ConstraintName, ci::CI)
return model.inner.constraint_info[ci.value].name
end

function MOI.get(model::Optimizer, ::Type{MathOptInterface.ConstraintIndex}, name::String)
for (i,c) in enumerate(model.inner.constraint_info)
if name == c.name
return CI(i)
end
end
error("Unrecognized constraint name $name.")
end
# see comment in: write_bar_file
# MOI.supports(::Optimizer, ::MOI.ConstraintName, ::Type{CI}) = true
# function MOI.set(model::Optimizer, attr::MOI.ConstraintName, ci::CI{MOI.VariableIndex}, value)
# error("No support for naming constraints imposed on variables.")
# end
# function MOI.set(model::Optimizer, attr::MOI.ConstraintName, ci::CI, value)
# check_constraint_indices(model, ci)
# model.inner.constraint_info[ci.value].name = value
# end
# function MOI.get(model::Optimizer, ::MOI.ConstraintName, ci::CI)
# return model.inner.constraint_info[ci.value].name
# end
# function MOI.get(model::Optimizer, ::Type{MathOptInterface.ConstraintIndex}, name::String)
# for (i,c) in enumerate(model.inner.constraint_info)
# if name == c.name
# return CI(i)
# end
# end
# error("Unrecognized constraint name $name.")
# end

MOI.supports_constraint(::Optimizer, ::Type{SV}, ::Type{MOI.ZeroOne}) = true
MOI.supports_constraint(::Optimizer, ::Type{SV}, ::Type{MOI.Integer}) = true
MOI.supports_constraint(::Optimizer, ::Type{MOI.VariableIndex}, ::Type{MOI.ZeroOne}) = true
MOI.supports_constraint(::Optimizer, ::Type{MOI.VariableIndex}, ::Type{MOI.Integer}) = true

function MOI.add_constraint(model::Optimizer, f::SV, set::S) where {S <: Union{MOI.ZeroOne, MOI.Integer}}
variable_info = find_variable_info(model, f.variable)
function MOI.add_constraint(model::Optimizer, f::MOI.VariableIndex, set::S
) where {S <: Union{MOI.ZeroOne, MOI.Integer}}
variable_info = find_variable_info(model, f)
if set isa MOI.ZeroOne
variable_info.category = :Bin
elseif set isa MOI.Integer
variable_info.category = :Int
else
error("Unsupported variable type $set.")
end
return CI{SV, S}(f.variable.value)
return CI{MOI.VariableIndex, S}(f.value)
end

# MOI.supports(::Optimizer, ::MOI.NLPBlock) = true
Expand Down
13 changes: 10 additions & 3 deletions src/moi/nlp.jl
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,19 @@ function MOI.set(model::Optimizer, ::MOI.NLPBlock, nlp_data::MOI.NLPBlockData)
MOI.initialize(nlp_eval, [:ExprGraph])

if nlp_data.has_objective
if model.inner.objective_expr !== nothing
error("Two objectives set: One linear, one nonlinear.")
end
# according to test: test_nonlinear_objective_and_moi_objective_test
# from MOI 0.10.9, linear objectives are just ignores if the noliena exists
# if model.inner.objective_expr !== nothing
# error("Two objectives set: One linear, one nonlinear.")
# end
obj = verify_support(MOI.objective_expr(nlp_eval))
walk_and_strip_variable_index!(obj)

model.inner.objective_expr = obj
# if obj == :NaN
# model.inner.objective_expr = 0.0
# else
# end
end

for i in 1:length(nlp_data.constraint_bounds)
Expand Down
2 changes: 1 addition & 1 deletion src/moi/objective.jl
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ end
MOI.supports(::Optimizer, ::MOI.ObjectiveFunction{SAF}) = true
MOI.supports(::Optimizer, ::MOI.ObjectiveFunction{SQF}) = true

function MOI.set(model::Optimizer, ::MOI.ObjectiveFunction{F}, obj::F) where {F<:Union{SV, SAF, SQF}}
function MOI.set(model::Optimizer, ::MOI.ObjectiveFunction{F}, obj::F) where {F<:Union{VI, SAF, SQF}}
model.inner.objective_expr = to_expr(obj)
return
end
36 changes: 31 additions & 5 deletions src/moi/results.jl
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,14 @@ function MOI.get(model::Optimizer, ::MOI.ResultCount)
return (model.inner.solution_info.feasible_point === nothing) ? 0 : 1
end

function MOI.get(model::Optimizer, ::MOI.PrimalStatus)
function MOI.get(model::Optimizer, ::MOI.DualStatus)
MOI.NO_SOLUTION
end

function MOI.get(model::Optimizer, attr::MOI.PrimalStatus)
if attr.result_index != 1
return MOI.NO_SOLUTION
end
solution_info = model.inner.solution_info
if solution_info === nothing || solution_info.feasible_point === nothing
return MOI.NO_SOLUTION
Expand All @@ -56,9 +63,22 @@ function MOI.get(model::Optimizer, ::MOI.PrimalStatus)
end
end

MOI.get(model::Optimizer, ::MOI.ObjectiveValue) = model.inner.solution_info.objective_value
function MOI.get(model::Optimizer, attr::MOI.ObjectiveValue)
MOI.check_result_index_bounds(model, attr)
# if model.inner.solution_info.model_status == UNBOUNDED
# # BARON will set the same large number
# # for both abj and variables in case of unbounded
# # this would make it retur MOI consistent values
# # but getters are no define and NL one would be messy
# return MOIU.get_fallback(model, attr)
# else
model.inner.solution_info.objective_value
# end
end

function MOI.get(model::Optimizer, ::MOI.VariablePrimal, vi::VI)
function MOI.get(model::Optimizer, attr::MOI.VariablePrimal, vi::VI)
MOI.check_result_index_bounds(model, attr)
# MOI.throw_if_not_valid(model, vi) # TODO implement is_valid
solution_info = model.inner.solution_info
if solution_info === nothing || solution_info.feasible_point === nothing
error("VariablePrimal not available.")
Expand All @@ -72,15 +92,21 @@ function MOI.get(model::Optimizer, ::MOI.ObjectiveBound)
return solution_info.dual_bound
end

function MOI.get(model::Optimizer, ::MOI.SolveTime)
function MOI.get(model::Optimizer, ::MOI.SolveTimeSec)
solution_info = model.inner.solution_info
return solution_info.wall_time
end

function MOI.get(model::Optimizer, ::MOI.RawStatusString)
info = model.inner.solution_info
return "solver: $(info.solver_status), model: $(info.model_status)"
end

# TODO: desirable?
function MOI.get(model::MOIU.CachingOptimizer{BARON.Optimizer}, attr::MOI.ConstraintPrimal, ci::MOI.ConstraintIndex)
return MOIU.get_fallback(model, attr, ci)
end

# TODO: MOI getter for solvetime
function MOI.supports(::Optimizer, ::MOI.SolverVersion)
false
end
20 changes: 10 additions & 10 deletions src/moi/util.jl
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
# to_expr
to_expr(sv::SV) = :(x[$(sv.variable.value)])
to_expr(vi::MOI.VariableIndex) = :(x[$(vi.value)])

function to_expr(f::SAF)
f = MOIU.canonical(f)
if isempty(f.terms)
return f.constant
else
linear_term_exprs = map(f.terms) do term
:($(term.coefficient) * x[$(term.variable_index.value)])
:($(term.coefficient) * x[$(term.variable.value)])
end
expr = :(+($(linear_term_exprs...)))
if !iszero(f.constant)
Expand All @@ -20,12 +20,12 @@ end
function to_expr(f::SQF)
f = MOIU.canonical(f)
linear_term_exprs = map(f.affine_terms) do term
i = term.variable_index.value
i = term.variable.value
:($(term.coefficient) * x[$i])
end
quadratic_term_exprs = map(f.quadratic_terms) do term
i = term.variable_index_1.value
j = term.variable_index_2.value
i = term.variable_1.value
j = term.variable_2.value
if i == j
:($(term.coefficient / 2) * x[$i] * x[$j])
else
Expand All @@ -46,17 +46,17 @@ end

function check_variable_indices(model::Optimizer, f::SAF)
for term in f.terms
check_variable_indices(model, term.variable_index)
check_variable_indices(model, term.variable)
end
end

function check_variable_indices(model::Optimizer, f::SQF)
for term in f.affine_terms
check_variable_indices(model, term.variable_index)
check_variable_indices(model, term.variable)
end
for term in f.quadratic_terms
check_variable_indices(model, term.variable_index_1)
check_variable_indices(model, term.variable_index_2)
check_variable_indices(model, term.variable_1)
check_variable_indices(model, term.variable_2)
end
end

Expand All @@ -65,7 +65,7 @@ function find_variable_info(model::Optimizer, vi::VI)
model.inner.variable_info[vi.value]
end

function check_constraint_indices(model::Optimizer, index::CI{SV})
function check_constraint_indices(model::Optimizer, index::CI{MOI.VariableIndex})
@assert 1 <= index.value <= length(model.inner.variable_info)
end

Expand Down
Loading