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

Add caching #173

Closed
wants to merge 4 commits into from
Closed
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
64 changes: 40 additions & 24 deletions src/MOI_wrapper/MOI_wrapper.jl
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,14 @@ mutable struct Optimizer <: MOI.AbstractOptimizer
objective_constant::Float64
solve_time::Float64
termination_status::Cint
# A cache for the primal solution vector to avoid having to query the full
# vector in order to lookup one element.
primal_solution_cache::Vector{Float64}
# Similar cache for constraints evaluated at primal solution.
primal_constraint_cache::Vector{Float64}

solution_status::MOI.TerminationStatusCode
num_integers::Int

"""
Optimizer(; kwargs...)
Expand All @@ -26,6 +34,10 @@ mutable struct Optimizer <: MOI.AbstractOptimizer
0.0,
0.0,
Cint(-1),
Float64[],
Float64[],
MOI.OPTIMIZE_NOT_CALLED,
0,
)
for (key, value) in kwargs
MOI.set(model, MOI.RawParameter(key), value)
Expand Down Expand Up @@ -111,6 +123,10 @@ function MOI.empty!(model::Optimizer)
Cbc_setParameter(model, "logLevel", "0")
end
empty!(model.variable_start)
model.primal_solution_cache = Float64[]
model.primal_constraint_cache = Float64[]
model.solution_status = MOI.OPTIMIZE_NOT_CALLED
model.num_integers = 0
return
end

Expand Down Expand Up @@ -728,16 +744,14 @@ end
function _unsafe_wrap_cbc_array(
model::Optimizer,
f::F,
n::Integer,
indices;
n::Integer;
own::Bool = false,
) where {F<:Function}
p = f(model)
if p == C_NULL
return map(x -> NaN, indices)
return fill(NaN, n)
end
x = unsafe_wrap(Array, p, (n,); own = own)
return x[indices]
return unsafe_wrap(Array, p, (n,); own = own)
end

function MOI.optimize!(model::Optimizer)
Expand All @@ -753,6 +767,20 @@ function MOI.optimize!(model::Optimizer)
t = time()
model.termination_status = Cbc_solve(model)
model.solve_time = time() - t
model.solution_status = _get_solution_status(model)
model.num_integers = Cbc_getNumIntegers(model)
if MOI.get(model, MOI.PrimalStatus()) == MOI.FEASIBLE_POINT
model.primal_solution_cache = _unsafe_wrap_cbc_array(
model,
Cbc_getColSolution,
Cbc_getNumCols(model),
)
model.primal_constraint_cache = _unsafe_wrap_cbc_array(
model,
Cbc_getRowActivity,
Cbc_getNumRows(model),
)
end
return
end

Expand Down Expand Up @@ -795,12 +823,7 @@ function MOI.get(
x::MOI.VariableIndex,
)
MOI.check_result_index_bounds(model, attr)
return _unsafe_wrap_cbc_array(
model,
Cbc_getColSolution,
Cbc_getNumCols(model),
x.value,
)
return model.primal_solution_cache[x.value]
end

function MOI.get(
Expand All @@ -809,12 +832,7 @@ function MOI.get(
x::Vector{MOI.VariableIndex},
)
MOI.check_result_index_bounds(model, attr)
return _unsafe_wrap_cbc_array(
model,
Cbc_getColSolution,
Cbc_getNumCols(model),
[xi.value for xi in x],
)
return Float64[model.primal_solution_cache[xi.value] for xi in x]
end

function MOI.get(
Expand All @@ -823,12 +841,7 @@ function MOI.get(
index::MOI.ConstraintIndex{MOI.ScalarAffineFunction{Float64},<:Any},
)
MOI.check_result_index_bounds(model, attr)
return _unsafe_wrap_cbc_array(
model,
Cbc_getRowActivity,
Cbc_getNumRows(model),
index.value,
)
return model.primal_constraint_cache[index.value]
end

function MOI.get(
Expand Down Expand Up @@ -897,7 +910,7 @@ function MOI.get(model::Optimizer, ::MOI.ResultCount)
# can be removed when we drop support for Julia 1.0 and the 2.10.3 JLL.
return Cbc_numberSavedSolutions(model) > 0 ? 1 : 0
end
if Cbc_getNumIntegers(model) == 0
if model.num_integers == 0
# Cbc forwards the solve to the LP solver if there are no integers, so
# check the termination status for the result count.
return model.termination_status == 0 ? 1 : 0
Expand All @@ -906,6 +919,9 @@ function MOI.get(model::Optimizer, ::MOI.ResultCount)
end

function MOI.get(model::Optimizer, ::MOI.TerminationStatus)
return model.solution_status
end
function _get_solution_status(model::Optimizer)
status = model.termination_status
if status == -1
return MOI.OPTIMIZE_NOT_CALLED
Expand Down