From 5ff64bd26b1d818605299aaa8d09c2d7e65e7f64 Mon Sep 17 00:00:00 2001 From: Bartolomeo Stellato <bartolomeo.stellato@gmail.com> Date: Sat, 31 Aug 2019 17:15:19 -0400 Subject: [PATCH 1/5] Updated for OSQP v0.6.0. Fixed #60 --- .editorconfig | 12 ++++++++++++ deps/build.jl | 2 +- src/MOI_wrapper.jl | 15 +++++++-------- src/OSQP.jl | 5 +++-- src/constants.jl | 2 +- src/interface.jl | 18 +++++++++++++----- test/MOI_wrapper.jl | 1 + test/basic.jl | 6 ++++-- 8 files changed, 42 insertions(+), 19 deletions(-) create mode 100644 .editorconfig diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..779f99a --- /dev/null +++ b/.editorconfig @@ -0,0 +1,12 @@ +root = true + +[*] +indent_style = space +indent_size = 4 +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true + +[*.md] +trim_trailing_whitespace = false diff --git a/deps/build.jl b/deps/build.jl index f86a7ea..223d260 100644 --- a/deps/build.jl +++ b/deps/build.jl @@ -5,7 +5,7 @@ const verbose = "--verbose" in ARGS const prefix = Prefix(get([a for a in ARGS if a != "--verbose"], 1, joinpath(@__DIR__, "usr"))) # Current version -version = "0.5.0" +version = "0.6.0" # Get current operating system osqp_platform = diff --git a/src/MOI_wrapper.jl b/src/MOI_wrapper.jl index a37531d..ec4c423 100644 --- a/src/MOI_wrapper.jl +++ b/src/MOI_wrapper.jl @@ -88,14 +88,13 @@ MOI.get(::Optimizer, ::MOI.SolverName) = "OSQP" MOI.supports(::Optimizer, ::MOI.Silent) = true function MOI.set(optimizer::Optimizer, ::MOI.Silent, value::Bool) - if optimizer.silent != value - optimizer.silent = value - if !MOI.is_empty(optimizer) - if optimizer.silent - OSQP.update_settings!(optimizer.inner; :verbose => false) - else - OSQP.update_settings!(optimizer.inner; :verbose => optimizer.settings[:verbose]) - end + optimizer.silent = value + optimizer.settings[:verbose] = !value + if !MOI.is_empty(optimizer) + if optimizer.silent + OSQP.update_settings!(optimizer.inner; :verbose => false) + else + OSQP.update_settings!(optimizer.inner; :verbose => optimizer.settings[:verbose]) end end end diff --git a/src/OSQP.jl b/src/OSQP.jl index d6aeb2c..4a7f7d5 100644 --- a/src/OSQP.jl +++ b/src/OSQP.jl @@ -2,6 +2,7 @@ module OSQP export OSQPMathProgBaseInterface using SparseArrays +using LinearAlgebra if isfile(joinpath(dirname(@__FILE__), "..", "deps", "deps.jl")) @@ -19,8 +20,8 @@ function __init__() depsdir = realpath(joinpath(dirname(@__FILE__), "..", "deps")) - if (vnum.major != 0 && vnum.minor != 4) - error("Current OSQP version installed is $(osqp_version()), but we require version 0.4.*. Delete the contents of the `$depsdir` directory except for the files `build.jl` and `.gitignore`, then rerun Pkg.build(\"OSQP\").") + if (vnum.major != 0 && vnum.minor != 6) + error("Current OSQP version installed is $(osqp_version()), but we require version 0.6.*. Delete the contents of the `$depsdir` directory except for the files `build.jl` and `.gitignore`, then rerun Pkg.build(\"OSQP\").") end end diff --git a/src/constants.jl b/src/constants.jl index 41ab7c3..3f4c215 100644 --- a/src/constants.jl +++ b/src/constants.jl @@ -2,7 +2,7 @@ const QDLDL_SOLVER = 0 const MKL_PARDISO_SOLVER = 1 # Define OSQP infinity constants -const OSQP_INFTY = 1e20 +const OSQP_INFTY = 1e30 # OSQP return values # https://github.com/oxfordcontrol/osqp/blob/master/include/constants.h diff --git a/src/interface.jl b/src/interface.jl index 6789df0..89164fd 100644 --- a/src/interface.jl +++ b/src/interface.jl @@ -112,6 +112,11 @@ function setup!(model::OSQP.Model; A = sparse(A) end + # Constructing upper triangular from P + if !istriu(P) + P = triu(P) + end + # Convert lower and upper bounds from Julia infinity to OSQP infinity u = min.(u, OSQP_INFTY) l = max.(l, -OSQP_INFTY) @@ -146,12 +151,16 @@ function setup!(model::OSQP.Model; pointer(q), pointer(l), pointer(u)) + # Perform setup - model.workspace = ccall((:osqp_setup, OSQP.osqp), Ptr{OSQP.Workspace}, - (Ptr{OSQP.Data}, Ptr{OSQP.Settings}), Ref(data), Ref(stgs)) + workspace = Ref{Ptr{OSQP.Workspace}}() + exitflag = ccall((:osqp_setup, OSQP.osqp), Cc_int, + (Ptr{Ptr{OSQP.Workspace}}, Ptr{OSQP.Data}, Ptr{OSQP.Settings}), + workspace, Ref(data), Ref(stgs)) + model.workspace = workspace[] end - if model.workspace == C_NULL + if exitflag != 0 error("Error in OSQP setup") end @@ -160,8 +169,7 @@ end function solve!(model::OSQP.Model, results::Results = Results()) ccall((:osqp_solve, OSQP.osqp), Cc_int, - (Ptr{OSQP.Workspace}, ), - model.workspace) + (Ptr{OSQP.Workspace}, ), model.workspace) workspace = unsafe_load(model.workspace) info = results.info copyto!(info, unsafe_load(workspace.info)) diff --git a/test/MOI_wrapper.jl b/test/MOI_wrapper.jl index 40327f0..0063b6c 100644 --- a/test/MOI_wrapper.jl +++ b/test/MOI_wrapper.jl @@ -342,6 +342,7 @@ term(c, x::MOI.VariableIndex, y::MOI.VariableIndex) = MOI.ScalarQuadraticTerm(c, # update settings @test optimizer.results.info.status_polish == 0 + print("ERROR STUFF") MOI.set(optimizer, OSQPSettings.Polish(), true) MOI.optimize!(optimizer) @test optimizer.results.info.status_polish == 1 diff --git a/test/basic.jl b/test/basic.jl index a9e31f3..5a5372a 100644 --- a/test/basic.jl +++ b/test/basic.jl @@ -145,14 +145,16 @@ tol = 1e-5 model = OSQP.Model() OSQP.setup!(model; P=problem[:P], q=problem[:q], - A=problem[:A], l=problem[:l], u=problem[:u], options...) + A=problem[:A], l=problem[:l], u=problem[:u], options...) results = OSQP.solve!(model) @test results.info.status == :Solved # Ensure solver will time out - OSQP.update_settings!(model, time_limit=1e-6, max_iter=1000000, check_termination=0) + OSQP.update_settings!(model, + eps_abs=1e-20, eps_rel=1e-20, + time_limit=1e-6, max_iter=1000000, check_termination=0) results_time_limit = OSQP.solve!(model) From a8bea98abf91a9a6357dbc96fe745dce813ad29a Mon Sep 17 00:00:00 2001 From: Bartolomeo Stellato <bartolomeo.stellato@gmail.com> Date: Sat, 31 Aug 2019 20:10:20 -0400 Subject: [PATCH 2/5] Add TimeLimitSec. Fixes #58 --- src/MOI_wrapper.jl | 20 ++++++++++++++++++++ test/MOI_wrapper.jl | 5 +---- test/dual_infeasibility.jl | 4 ++-- 3 files changed, 23 insertions(+), 6 deletions(-) diff --git a/src/MOI_wrapper.jl b/src/MOI_wrapper.jl index ec4c423..4b3e292 100644 --- a/src/MOI_wrapper.jl +++ b/src/MOI_wrapper.jl @@ -100,6 +100,26 @@ function MOI.set(optimizer::Optimizer, ::MOI.Silent, value::Bool) end MOI.get(optimizer::Optimizer, ::MOI.Silent) = optimizer.silent + + +MOI.supports(::Optimizer, ::MOI.TimeLimitSec) = true +function MOI.set(model::Optimizer, ::MOI.TimeLimitSec, limit::Real) + MOI.set(model, OSQPSettings.TimeLimit(), limit) + return +end + +function MOI.set(model::Optimizer, attr::MOI.TimeLimitSec, ::Nothing) + delete!(model.settings, :time_limit) + OSQP.update_settings!(model.inner, time_limit=0.0) + return +end + +function MOI.get(model::Optimizer, ::MOI.TimeLimitSec) + return get(model.settings, :time_limit, nothing) +end + + + hasresults(optimizer::Optimizer) = optimizer.hasresults function MOI.empty!(optimizer::Optimizer) diff --git a/test/MOI_wrapper.jl b/test/MOI_wrapper.jl index 0063b6c..8ffe830 100644 --- a/test/MOI_wrapper.jl +++ b/test/MOI_wrapper.jl @@ -112,9 +112,7 @@ function bridged_optimizer() end @testset "CachingOptimizer: unit" begin - excludes = [# TODO - "time_limit_sec", - # Quadratic constraints are not supported + excludes = [# Quadratic constraints are not supported "solve_qcp_edge_cases", # No method get(::Optimizer, ::MathOptInterface.ConstraintPrimal, ::MathOptInterface.ConstraintIndex{MathOptInterface.VectorAffineFunction{Float64},MathOptInterface.Nonpositives}) "solve_duplicate_terms_vector_affine", @@ -342,7 +340,6 @@ term(c, x::MOI.VariableIndex, y::MOI.VariableIndex) = MOI.ScalarQuadraticTerm(c, # update settings @test optimizer.results.info.status_polish == 0 - print("ERROR STUFF") MOI.set(optimizer, OSQPSettings.Polish(), true) MOI.optimize!(optimizer) @test optimizer.results.info.status_polish == 1 diff --git a/test/dual_infeasibility.jl b/test/dual_infeasibility.jl index 76411ad..5e75cd2 100644 --- a/test/dual_infeasibility.jl +++ b/test/dual_infeasibility.jl @@ -2,7 +2,7 @@ function setup_dual_infeasibility() options = Dict(:verbose => false, :eps_abs => 1e-05, :eps_rel => 1e-05, - :eps_prim_inf => 1e-18, + :eps_prim_inf => 1e-15, :check_termination => 1) return options end @@ -56,7 +56,7 @@ tol = 1e-5 OSQP.setup!(model; P=P, q=q, A=A, l=l, u=u, options...) # Warm start to avoid infeasibility detection at first step - OSQP.warm_start!(model, x=[25.; 25], y=[-2.; -2; -2; -2]) + OSQP.warm_start!(model, x=[50.; 30.], y=[-2.; -2; -2; -2]) results = OSQP.solve!(model) From ff9bb43ac89ccd350fc97f51f6e66afd3e7b69a0 Mon Sep 17 00:00:00 2001 From: Bartolomeo Stellato <bartolomeo.stellato@gmail.com> Date: Sun, 1 Sep 2019 11:07:25 -0400 Subject: [PATCH 3/5] Removed editorconfig --- .editorconfig | 12 ------------ .gitignore | 1 + 2 files changed, 1 insertion(+), 12 deletions(-) delete mode 100644 .editorconfig diff --git a/.editorconfig b/.editorconfig deleted file mode 100644 index 779f99a..0000000 --- a/.editorconfig +++ /dev/null @@ -1,12 +0,0 @@ -root = true - -[*] -indent_style = space -indent_size = 4 -end_of_line = lf -charset = utf-8 -trim_trailing_whitespace = true -insert_final_newline = true - -[*.md] -trim_trailing_whitespace = false diff --git a/.gitignore b/.gitignore index d920beb..fdc0eda 100644 --- a/.gitignore +++ b/.gitignore @@ -14,3 +14,4 @@ deps/build.log .vscode/ Manifest.toml +.editorconfig From aa8f4be9615c5d8ae81c828c10d989897e50bffe Mon Sep 17 00:00:00 2001 From: Bartolomeo Stellato <bartolomeo.stellato@gmail.com> Date: Sun, 1 Sep 2019 11:17:21 -0400 Subject: [PATCH 4/5] Restored preferred verbose operation. Now silent broken again --- src/MOI_wrapper.jl | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/MOI_wrapper.jl b/src/MOI_wrapper.jl index 4b3e292..3922fc7 100644 --- a/src/MOI_wrapper.jl +++ b/src/MOI_wrapper.jl @@ -89,12 +89,11 @@ MOI.get(::Optimizer, ::MOI.SolverName) = "OSQP" MOI.supports(::Optimizer, ::MOI.Silent) = true function MOI.set(optimizer::Optimizer, ::MOI.Silent, value::Bool) optimizer.silent = value - optimizer.settings[:verbose] = !value if !MOI.is_empty(optimizer) if optimizer.silent OSQP.update_settings!(optimizer.inner; :verbose => false) else - OSQP.update_settings!(optimizer.inner; :verbose => optimizer.settings[:verbose]) + OSQP.update_settings!(optimizer.inner; :verbose => true) end end end From b7cf688bfef194589c8fa17db1f449a2ee3a0cf3 Mon Sep 17 00:00:00 2001 From: Bartolomeo Stellato <bartolomeo.stellato@gmail.com> Date: Sun, 1 Sep 2019 12:44:36 -0400 Subject: [PATCH 5/5] Another fix for silent --- src/MOI_wrapper.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/MOI_wrapper.jl b/src/MOI_wrapper.jl index 3922fc7..17c1d78 100644 --- a/src/MOI_wrapper.jl +++ b/src/MOI_wrapper.jl @@ -93,7 +93,7 @@ function MOI.set(optimizer::Optimizer, ::MOI.Silent, value::Bool) if optimizer.silent OSQP.update_settings!(optimizer.inner; :verbose => false) else - OSQP.update_settings!(optimizer.inner; :verbose => true) + OSQP.update_settings!(optimizer.inner; :verbose => optimizer.settings[:verbose]) end end end