-
Notifications
You must be signed in to change notification settings - Fork 25
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 MathProgBase solver interface. #9
Merged
Merged
Changes from 1 commit
Commits
Show all changes
23 commits
Select commit
Hold shift + click to select a range
0d9ac6c
Add MathProgBase solver interface.
tkoolen 4f14108
Add MathProgBase solver interface.
tkoolen c27d244
Address review comments.
tkoolen df2f7e0
Copy over relevant parts of MathProgBase test/quadprog.jl.
tkoolen 9b061b6
Refine/implement more of MathProgBase interface.
tkoolen de19e17
Upper bound on MPB.
tkoolen 1510ae3
Added mathprog tests. Basic restructuring. Still need to complete the…
bstellato bce0012
Merged both changes but still need to finish the interface
bstellato 4311dfd
Deleted solver interface in mathprog old file
bstellato ff8f248
Improve test coverage.
tkoolen 938a50b
Add more tests, fix objective bug.
tkoolen 683a6e5
Merged tkoolen changes
bstellato 381c761
Added changes for proper updates without performing setup again. Trie…
bstellato 14e0d97
Added update_settings! to setparameters
bstellato f4b4af9
First tests working but still getting segfaults when I close julia
bstellato 7a46756
Apparently setwarmstart! causes troubles
bstellato 23f3202
Got Twan tests working
bstellato ec0ab49
Got more tests working. Need to fix last ones in linproginterface
bstellato ed9b220
Fixed some bugs
bstellato 1299cc5
Got all mathprogbase tests to work. Fixed dual variables signs
bstellato d11c474
Other adjustments based on comments
bstellato 5094552
Fixed setquadobj! to reset problem status forcing a new solve
bstellato 47f7010
Edited changelog before merging
bstellato File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,186 @@ | ||
module OSQPSolverInterface | ||
|
||
using MathProgBase | ||
import OSQP | ||
|
||
import MathProgBase: numvar, numconstr | ||
|
||
struct OSQPSolver <: MathProgBase.AbstractMathProgSolver | ||
settings::Dict{Symbol,Any} | ||
end | ||
|
||
OSQPSolver() = OSQPSolver(Dict{Symbol, Any}()) | ||
|
||
mutable struct OSQPModel <: MathProgBase.AbstractLinearQuadraticModel | ||
settings::Dict{Symbol, Any} | ||
inner::OSQP.Model | ||
|
||
P::SparseMatrixCSC{Float64, Int} | ||
q::Vector{Float64} | ||
A::SparseMatrixCSC{Float64, Int} | ||
l::Vector{Float64} | ||
u::Vector{Float64} | ||
|
||
results::OSQP.Results | ||
|
||
function OSQPModel(settings::Associative{Symbol, Any}) | ||
P = spzeros(Float64, 0, 0) | ||
q = Float64[] | ||
A = spzeros(Float64, 0, 0) | ||
l = Float64[] | ||
u = Float64[] | ||
new(settings, OSQP.Model(), P, q, A, l, u) # leave results undefined | ||
end | ||
end | ||
|
||
function Base.resize!(model::OSQPModel, n, m) | ||
nchange = n != numvar(model) | ||
mchange = m != numconstr(model) | ||
if nchange | ||
model.P = spzeros(Float64, n, n) | ||
resize!(model.q, n) | ||
end | ||
if mchange | ||
resize!(model.l, m) | ||
resize!(model.u, m) | ||
end | ||
if nchange || mchange | ||
model.A = spzeros(Float64, m, n) | ||
end | ||
|
||
model | ||
end | ||
|
||
checksolved(model::OSQPModel) = isdefined(model, :results) || error("Model has not been solved.") | ||
variablebounderror() = error("Variable bounds are not supported (use constraints instead).") | ||
|
||
# http://mathprogbasejl.readthedocs.io/en/latest/solverinterface.html | ||
MathProgBase.LinearQuadraticModel(solver::OSQPSolver) = OSQPModel(solver.settings) | ||
MathProgBase.getsolution(model::OSQPModel) = (checksolved(model); model.results.x) | ||
MathProgBase.getobjval(model::OSQPModel) = (checksolved(model); model.results.info.obj_val) | ||
|
||
function MathProgBase.optimize!(model::OSQPModel) | ||
OSQP.setup!(model.inner; P = model.P, q = model.q, A = model.A, l = model.l, u = model.u, settings = model.settings) | ||
model.results = OSQP.solve!(model.inner) | ||
end | ||
|
||
function MathProgBase.status(model::OSQPModel)::Symbol | ||
checksolved(model) | ||
status = model.results.info.status | ||
ret = status # if OSQP status can't be mapped to a standard return value, just return as is | ||
|
||
# map to standard return status values: | ||
status == :Solved && (ret = :Optimal) | ||
status == :Max_iter_reached && (ret = :UserLimit) | ||
status == :Interrupted && (ret = :UserLimit) # following Gurobi.jl | ||
status == :Primal_infeasible && (ret = :Infeasible) | ||
status == :Primal_infeasible_inaccurate && (ret = :Infeasible) | ||
status == :Dual_infeasible && (ret = :DualityFailure) | ||
|
||
return ret | ||
end | ||
|
||
# TODO: getobjbound | ||
# TODO: getobjgap | ||
MathProgBase.getrawsolver(model::OSQPModel) = model.inner | ||
MathProgBase.getsolvetime(model::OSQPModel) = (checksolved(model); model.results.info.run_time) | ||
# TODO: setsense! | ||
# TODO: getsense | ||
MathProgBase.numvar(model::OSQPModel) = size(model.A, 2) | ||
MathProgBase.numconstr(model::OSQPModel) = size(model.A, 1) | ||
# TODO: freemodel! | ||
# TODO: copy | ||
MathProgBase.setvartype!(model::OSQPModel, v::Vector{Symbol}) = any(x -> x != :Cont, v) && error("OSQP only supports continuous variables.") | ||
MathProgBase.getvartype(model::OSQPModel) = fill(:Cont, numvar(model)) | ||
|
||
function MathProgBase.setparameters!(x::Union{OSQPSolver, OSQPModel}; Silent = nothing) | ||
if Silent != nothing | ||
Silent::Bool | ||
x.settings[:verbose] = !Silent | ||
end | ||
end | ||
|
||
MathProgBase.setwarmstart!(model::OSQPModel, v) = OSQP.warm_start!(model.inner, x = v) | ||
|
||
|
||
# http://mathprogbasejl.readthedocs.io/en/latest/lpqcqp.html#linearquadratic-models | ||
# TODO: loadproblem!(m::AbstractLinearQuadraticModel, filename::String) | ||
|
||
function MathProgBase.loadproblem!(model::OSQPModel, A, l, u, c, lb, ub, sense) | ||
(any(x -> x != -Inf, l) || any(x -> x != Inf, u)) && variablebounderror() | ||
m, n = size(A) | ||
resize!(model, n, m) | ||
|
||
if sense == :Min | ||
copy!(model.q, c) | ||
elseif sense == :Max | ||
model.q .= .-c | ||
else | ||
error("Objective sense not recognized") | ||
end | ||
|
||
copy!(model.l, lb) | ||
copy!(model.u, ub) | ||
copy!(model.A, A) | ||
|
||
model | ||
end | ||
|
||
# TODO: writeproblem | ||
MathProgBase.getvarLB(model::OSQPModel) = fill(-Inf, numvar(model)) | ||
MathProgBase.setvarLB!(model::OSQPModel, l) = variablebounderror() | ||
MathProgBase.getvarUB(model::OSQPModel) = fill(Inf, numvar(model)) | ||
MathProgBase.setvarUB!(model::OSQPModel, l) = variablebounderror() | ||
MathProgBase.getconstrLB(model::OSQPModel) = model.l | ||
MathProgBase.setconstrLB!(model::OSQPModel, lb) = (copy!(model.l, lb); model) | ||
MathProgBase.getconstrUB(model::OSQPModel) = model.u | ||
MathProgBase.setconstrUB!(model::OSQPModel, ub) = (copy!(model.u, ub); model) | ||
MathProgBase.setobj!(model::OSQPModel, c) = (copy!(model.q, c); model) | ||
MathProgBase.getconstrmatrix(model::OSQPModel) = model.A | ||
# TODO: addvar! | ||
# TODO: delvars! | ||
# TODO: addconstr! | ||
# TODO: delconstrs! | ||
# TODO: changecoeffs! | ||
MathProgBase.numlinconstr(model::OSQPModel) = numconstr(model) | ||
MathProgBase.getconstrsolution(model::OSQPModel) = model.A * getsolution(model) | ||
# TODO: getreducedcosts | ||
MathProgBase.getconstrduals(model::OSQPModel) = (checksolved(model); model.results.y) | ||
# TODO: getinfeasibilityray | ||
# TODO: getbasis | ||
# TODO: getunboundedray | ||
# TODO: getsimplexiter | ||
# TODO: getbarrieriter | ||
|
||
|
||
# http://mathprogbasejl.readthedocs.io/en/latest/lpqcqp.html#quadratic-programming | ||
MathProgBase.numquadconstr(model::OSQPModel) = 0 | ||
MathProgBase.setquadobj!(model::OSQPModel, Q) = (copy!(model.P, Q); model) | ||
|
||
function MathProgBase.setquadobj!(model::OSQPModel, rowidx, colidx, quadval) | ||
nterms = length(quadval) | ||
@boundscheck length(rowidx) == nterms || error() | ||
@boundscheck length(colidx) == nterms || error() | ||
|
||
# zero out coeffs | ||
for i = 1 : nterms | ||
@inbounds row = rowidx[i] | ||
@inbounds col = colidx[i] | ||
model.P[row, col] = 0 | ||
end | ||
|
||
# add new coeffs | ||
for i = 1 : nterms | ||
@inbounds row = rowidx[i] | ||
@inbounds col = colidx[i] | ||
@inbounds val = quadval[i] | ||
model.P[row, col] += val | ||
model.P[col, row] = model.P[row, col] | ||
end | ||
|
||
model | ||
end | ||
|
||
# Note: skipping quadconstr methods | ||
|
||
end # module |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe name this
OSQPMPBSolver
to avoid the imminent conflict with MOI?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see this is still the common approach in most of the current MathProgBase interfaces, e.g., EcosSolverInterface.jl.
@mlubin Are you planning to change the other solvers as well or to just drop the MathProgBase interfaces altogether?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
MPB interfaces will all be moved into separate packages when we start releasing the new MOI interfaces. It's up to developer discretion whether the MOI interface will sit in the same package as the direct solver wrapper or in a separate package.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Then it could be better to move this interface to a separate package called
MathProgBaseOSQP.jl
as done in MathProgBaseMosek.jl. In this way we could keepOSQPSolver
in both MPB and MOI interfaces and avoid using both them at the same time. Is this the purpose?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems a bit silly to create a package just for 200 lines of code that are going to be deprecated soon. (I'm reconsidering if we should do this for all solvers.) If we remove the line:
then there's nothing much to worry about with having both MPB and MOI interfaces in the same package.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Renamed the module to
OSQPMathProgBaseInterface
(solver is still namedOSQPSolver
). No longer exportingOSQPSolver
, but exportingOSQPMathProgBaseInterface
instead. What do you think?