diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f29f833..ce5d335 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -17,10 +17,10 @@ jobs: - version: '1' os: ubuntu-latest arch: x64 - - version: '1.0' + - version: '1.6' os: ubuntu-latest arch: x64 - - version: '1.0' + - version: '1.6' os: ubuntu-latest arch: x86 steps: diff --git a/.github/workflows/documentation.yml b/.github/workflows/documentation.yml index e8de6b8..c10e032 100644 --- a/.github/workflows/documentation.yml +++ b/.github/workflows/documentation.yml @@ -13,11 +13,10 @@ jobs: - uses: julia-actions/setup-julia@latest with: # Build documentation on Julia 1.0 - version: '1.0' + version: '1.6' - name: Install dependencies run: julia --project=docs/ -e 'using Pkg; Pkg.develop(PackageSpec(path=pwd())); Pkg.instantiate()' - name: Build and deploy env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # For authentication with GitHub Actions token - DOCUMENTER_KEY: ${{ secrets.DOCUMENTER_KEY }} # For authentication with SSH deploy key run: julia --project=docs/ docs/make.jl diff --git a/Project.toml b/Project.toml index 9131177..81175a3 100644 --- a/Project.toml +++ b/Project.toml @@ -1,23 +1,13 @@ name = "Dualization" uuid = "191a621a-6537-11e9-281d-650236a99e60" authors = ["guilhermebodin "] -version = "0.4.0" +version = "0.5.0" [deps] JuMP = "4076af6c-e467-56ae-b986-b466b2749572" MathOptInterface = "b8f27783-ece8-5eb3-8dc8-9495eed66fee" [compat] -JuMP = "0.22" -MathOptInterface = "0.10" -julia = "1" - -[extras] -CSDP = "0a46da34-8e4b-519e-b418-48813639ff34" -ECOS = "e2685f51-7e38-5353-a97d-a921fd2c8199" -GLPK = "60bf3e95-4087-53dc-ae20-288a0d20c6a6" -SCS = "c946c3f1-0d1f-5ce8-9dea-7daa1f7e2d13" -Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" - -[targets] -test = ["Test", "GLPK", "ECOS", "CSDP", "SCS"] +JuMP = "0.23" +MathOptInterface = "1" +julia = "1.6" diff --git a/README.md b/README.md index a462f54..c6b75c5 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,7 @@ Dualization.jl has two main features. dual_model = dualize(model) ``` - * The `DualOptimizer` that will pass the dual representation of the model to the solver of your choice. + * The `DualOptimizer` that will pass the dual representation of the model to the `SOLVER` of your choice. ```julia model = Model(dual_optimizer(SOLVER.Optimizer)) diff --git a/src/MOI_wrapper.jl b/src/MOI_wrapper.jl index 136cab1..99125ca 100644 --- a/src/MOI_wrapper.jl +++ b/src/MOI_wrapper.jl @@ -28,15 +28,15 @@ The user can define the model providing the `DualOptimizer` and the solver of it Example: ```julia -julia> using Dualization, JuMP, GLPK +julia> using Dualization, JuMP, HiGHS -julia> model = Model(dual_optimizer(GLPK.Optimizer)) +julia> model = Model(dual_optimizer(HiGHS.Optimizer)) A JuMP Model Feasibility problem with: Variables: 0 Model mode: AUTOMATIC CachingOptimizer state: EMPTY_OPTIMIZER -Solver name: Dual model with GLPK attached +Solver name: Dual model with HiGHS attached ``` """ function DualOptimizer(dual_optimizer::OT) where {OT<:MOI.ModelLike} diff --git a/test/Project.toml b/test/Project.toml new file mode 100644 index 0000000..8cde073 --- /dev/null +++ b/test/Project.toml @@ -0,0 +1,12 @@ +[deps] +CSDP = "0a46da34-8e4b-519e-b418-48813639ff34" +HiGHS = "87dc4568-4c63-4d18-b0c0-bb2238e4078b" +JuMP = "4076af6c-e467-56ae-b986-b466b2749572" +MathOptInterface = "b8f27783-ece8-5eb3-8dc8-9495eed66fee" +SCS = "c946c3f1-0d1f-5ce8-9dea-7daa1f7e2d13" +Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" + +[compat] +CSDP = "1.0.0" +HiGHS = "1.1.0" +SCS = "1.0.1" \ No newline at end of file diff --git a/test/Solvers/ecos_test.jl b/test/Solvers/ecos_test.jl deleted file mode 100644 index ca78573..0000000 --- a/test/Solvers/ecos_test.jl +++ /dev/null @@ -1,28 +0,0 @@ -using ECOS -const ECOS_PRIMAL_FACTORY = - MOI.OptimizerWithAttributes(ECOS.Optimizer, MOI.Silent() => true) -const ECOS_DUAL_FACTORY = dual_optimizer(ECOS_PRIMAL_FACTORY) -const ECOS_PRIMAL_OPT = MOI.instantiate(ECOS_PRIMAL_FACTORY) -const ECOS_DUAL_OPT = MOI.instantiate(ECOS_DUAL_FACTORY) - -# Warm up to pass tests on x86 -dual_problem = dualize(soc1_test()) -test_strong_duality( - soc1_test(), - dual_problem.dual_model, - ECOS_PRIMAL_FACTORY, - 1e-3, - 1e-3, -) - -@testset "ECOS conic Problems" begin - @testset "ECOS SOC problems" begin - list_of_soc_problems = - [soc1_test, soc2_test, soc3_test, soc4_test, soc5_test, soc6_test] - test_strong_duality(list_of_soc_problems, ECOS_PRIMAL_FACTORY) - end - @testset "ECOS RotatedSOC problems" begin - list_of_rsoc_problems = [rsoc1_test, rsoc2_test, rsoc3_test, rsoc4_test] - test_strong_duality(list_of_rsoc_problems, ECOS_PRIMAL_FACTORY) - end -end diff --git a/test/Solvers/glpk_test.jl b/test/Solvers/glpk_test.jl deleted file mode 100644 index 9f189f1..0000000 --- a/test/Solvers/glpk_test.jl +++ /dev/null @@ -1,30 +0,0 @@ -using GLPK -const GLPK_PRIMAL_FACTORY = - MOI.OptimizerWithAttributes(GLPK.Optimizer, MOI.Silent() => true) -const GLPK_DUAL_FACTORY = dual_optimizer(GLPK_PRIMAL_FACTORY) -const GLPK_PRIMAL_OPT = MOI.instantiate(GLPK_PRIMAL_FACTORY) -const GLPK_DUAL_OPT = MOI.instantiate(GLPK_DUAL_FACTORY) - -push!(primal_linear_factory, GLPK_PRIMAL_FACTORY) -push!(dual_linear_factory, GLPK_DUAL_FACTORY) -push!(dual_linear_optimizer, GLPK_DUAL_OPT) -push!(primal_linear_optimizer, GLPK_PRIMAL_OPT) - -@testset "GLPK Linear Problems" begin - list_of_linear_problems = [ - lp1_test, - lp2_test, - lp3_test, - lp4_test, - lp5_test, - lp6_test, - lp7_test, - # lp8_test, Int64 problem, does not work - # lp9_test, Interval is not implemented - lp10_test, - # lp11_test, Feasibility not supported - lp12_test, - lp13_test, - ] - test_strong_duality(list_of_linear_problems, GLPK_PRIMAL_FACTORY) -end diff --git a/test/Solvers/highs_test.jl b/test/Solvers/highs_test.jl new file mode 100644 index 0000000..d727a7a --- /dev/null +++ b/test/Solvers/highs_test.jl @@ -0,0 +1,35 @@ +using HiGHS +const HiGHS_PRIMAL_FACTORY = + MOI.OptimizerWithAttributes(HiGHS.Optimizer, MOI.Silent() => true) +const HiGHS_DUAL_FACTORY = dual_optimizer(HiGHS_PRIMAL_FACTORY) +const HiGHS_PRIMAL_OPT = MOI.instantiate(HiGHS_PRIMAL_FACTORY) +const HiGHS_DUAL_OPT = MOI.instantiate(HiGHS_DUAL_FACTORY) + +push!(primal_linear_factory, HiGHS_PRIMAL_FACTORY) +push!(dual_linear_factory, HiGHS_DUAL_FACTORY) +push!(dual_linear_optimizer, HiGHS_DUAL_OPT) +push!(primal_linear_optimizer, HiGHS_PRIMAL_OPT) + +@testset "HiGHS Linear Problems" begin + list_of_linear_problems = [ + lp1_test, + lp2_test, + lp3_test, + lp4_test, + lp5_test, + lp6_test, + lp7_test, + # lp8_test, Int64 problem, does not work + # lp9_test, Interval is not implemented + lp10_test, + # lp11_test, Feasibility not supported + lp12_test, + lp13_test, + ] + test_strong_duality(list_of_linear_problems, HiGHS_PRIMAL_FACTORY) +end + +@testset "HiGHS Quadratic Problems" begin + list_of_quad_problems = [qp1_test, qp2_test] + test_strong_duality(list_of_quad_problems, HiGHS_PRIMAL_FACTORY) +end diff --git a/test/Solvers/scs_test.jl b/test/Solvers/scs_test.jl index d953f42..978fb91 100644 --- a/test/Solvers/scs_test.jl +++ b/test/Solvers/scs_test.jl @@ -10,7 +10,42 @@ push!(dual_power_cone_factory, SCS_DUAL_FACTORY) push!(dual_power_cone_optimizer, SCS_DUAL_OPT) push!(primal_power_cone_optimizer, SCS_PRIMAL_OPT) -@testset "SCS Exponential Cone Problems" begin +@testset "SCS Exponential Cone problems" begin list_of_exp_problems = [exp1_test, exp2_test] test_strong_duality(list_of_exp_problems, SCS_PRIMAL_FACTORY) end + +@testset "SCS SOC problems" begin + list_of_soc_problems = [soc3_test, soc4_test, soc5_test, soc6_test] + test_strong_duality(list_of_soc_problems, SCS_PRIMAL_FACTORY) + list_of_soc_problems = [soc1_test, soc2_test] + test_strong_duality( + list_of_soc_problems, + SCS_PRIMAL_FACTORY, + atol = 1e-3, + rtol = 1e-3, + ) +end + +@testset "SCS RotatedSOC problems" begin + list_of_rsoc_problems = [rsoc1_test, rsoc2_test, rsoc3_test] + test_strong_duality(list_of_rsoc_problems, SCS_PRIMAL_FACTORY) + list_of_rsoc_problems = [rsoc4_test] + test_strong_duality( + list_of_rsoc_problems, + SCS_PRIMAL_FACTORY, + atol = 1e-3, + rtol = 1e-3, + ) +end + +@testset "SCS SDP triangle problems" begin + list_of_sdp_triang_problems = + [sdpt1_test, sdpt2_test, sdpt3_test, sdpt4_test] + test_strong_duality(list_of_sdp_triang_problems, SCS_PRIMAL_FACTORY) +end + +@testset "SCS Power Cone problems" begin + list_of_pow_problems = [pow1_test, pow2_test] + test_strong_duality(list_of_pow_problems, SCS_PRIMAL_FACTORY) +end diff --git a/test/Tests/test_JuMP_dualize.jl b/test/Tests/test_JuMP_dualize.jl index bed0564..d4e213a 100644 --- a/test/Tests/test_JuMP_dualize.jl +++ b/test/Tests/test_JuMP_dualize.jl @@ -27,7 +27,7 @@ end dual_JuMP_model = dualize(JuMP_model, primal_linear_factory[i]) @test backend(dual_JuMP_model).state == MOIU.EMPTY_OPTIMIZER @test MOI.get(backend(dual_JuMP_model), MOI.SolverName()) == - MOI.get(primal_linear_optimizer[i], MOI.SolverName())#"GLPK" + MOI.get(primal_linear_optimizer[i], MOI.SolverName()) end end @testset "set_dot on different sets" begin diff --git a/test/Tests/test_dualize_linear.jl b/test/Tests/test_dualize_linear.jl index 2c9d02b..dbb53d8 100644 --- a/test/Tests/test_dualize_linear.jl +++ b/test/Tests/test_dualize_linear.jl @@ -93,8 +93,7 @@ @test obj_type == SAF{Float64} obj = MOI.get(dual_model, MOI.ObjectiveFunction{obj_type}()) @test MOI.constant(obj) == -1.0 - @test MOI.coefficient.(obj.terms) == - (Sys.WORD_SIZE == 32 ? [1.0, 3.0, 3.0] : [3.0; 1.0; 3.0]) + @test Set(MOI.coefficient.(obj.terms)) == Set([3.0; 1.0; 3.0]) end @testset "lp10_test" begin diff --git a/test/Tests/test_modify.jl b/test/Tests/test_modify.jl index 198cd91..89a6b6e 100644 --- a/test/Tests/test_modify.jl +++ b/test/Tests/test_modify.jl @@ -1,5 +1,5 @@ @testset "modify" begin - model = Model(GLPK_DUAL_FACTORY) + model = Model(HiGHS_DUAL_FACTORY) @variable(model, x[1:2] >= 0) @constraint(model, 2x[1] + x[2] <= 4) @constraint(model, x[1] + 2x[2] <= 4) @@ -10,7 +10,7 @@ optimize!(model) @test objective_value(model) ≈ 10.6666666666 - model = Model(GLPK_DUAL_FACTORY) + model = Model(HiGHS_DUAL_FACTORY) @variable(model, x[1:2] >= 0) @constraint(model, 2x[1] + x[2] <= 4) @constraint(model, x[1] + 2x[2] <= 4) diff --git a/test/optimize_abstract_models.jl b/test/optimize_abstract_models.jl index a8c5675..5c9c54e 100644 --- a/test/optimize_abstract_models.jl +++ b/test/optimize_abstract_models.jl @@ -11,7 +11,11 @@ function solve_abstract_model( set_optimizer(JuMP_model, optimizer_constructor) optimize!(JuMP_model) termination_status = JuMP.termination_status(JuMP_model) - obj_val = JuMP.objective_value(JuMP_model) + obj_val = try + JuMP.objective_value(JuMP_model) + catch + NaN + end return termination_status, obj_val end @@ -45,11 +49,13 @@ function test_strong_duality( (dual_term_status == MOI.DUAL_INFEASIBLE) return true end + @show primal_term_status, primal_obj_val + @show dual_term_status, dual_obj_val return false # In case strong duality doesn't hold end function test_strong_duality( - primal_problems::Array{Function}, + primal_problems::Vector, optimizer_constructor; atol = 1e-6, rtol = 1e-4, diff --git a/test/runtests.jl b/test/runtests.jl index b12a2fd..43146eb 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -103,8 +103,7 @@ primal_power_cone_optimizer = [] # Load & Test strong duality in linear/conic problems # Comment the solver that are not available for development -include("Solvers/glpk_test.jl") -include("Solvers/ecos_test.jl") +include("Solvers/highs_test.jl") include("Solvers/csdp_test.jl") include("Solvers/scs_test.jl")