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

Update to MOI v1 #16

Merged
merged 1 commit into from
Mar 2, 2022
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
6 changes: 3 additions & 3 deletions Project.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name = "DSDP"
uuid = "2714ae6b-e930-5b4e-9c21-d0bacf577842"
repo = "https://github.com/joehuchette/DSDP.jl.git"
version = "0.0.1"
repo = "https://github.com/jump-dev/DSDP.jl.git"
version = "0.1.0"

[deps]
BinDeps = "9e28174c-4ba2-5203-b857-d8d62c4213ee"
Expand All @@ -10,7 +10,7 @@ LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
MathOptInterface = "b8f27783-ece8-5eb3-8dc8-9495eed66fee"

[compat]
MathOptInterface = "0.10"
MathOptInterface = "1"
julia = "1.6"

[extras]
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
| [![Build Status][build-img]][build-url] |
| [![Codecov branch][codecov-img]][codecov-url] |

**Important note**: this is still a work on progress. The use of semidefinite matrices in linear equality constraints has not been implemented yet so only linear programs can be solved at the moment with DSDP.
**Important note**: this is still a work on progress. The use of positive semidefinite matrices in linear equality constraints has not been implemented yet so only linear programs can be solved at the moment with DSDP.

Julia wrapper for the [DSDP](http://www.mcs.anl.gov/hs/software/DSDP/) semidefinite programming solver.

Expand Down
14 changes: 10 additions & 4 deletions src/MOI_wrapper.jl
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,9 @@ end

MOI.supports_add_constrained_variables(::Optimizer, ::Type{MOI.Reals}) = false
const SupportedSets = Union{MOI.Nonnegatives, MOI.PositiveSemidefiniteConeTriangle}
MOI.supports_add_constrained_variables(::Optimizer, ::Type{<:SupportedSets}) = true
# TODO positive semidefinite matrix variables not supported yet in linear equality constraints
#MOI.supports_add_constrained_variables(::Optimizer, ::Type{<:SupportedSets}) = true
MOI.supports_add_constrained_variables(::Optimizer, ::Type{<:MOI.Nonnegatives}) = true
function MOI.supports_constraint(
::Optimizer, ::Type{MOI.ScalarAffineFunction{Cdouble}},
::Type{MOI.EqualTo{Cdouble}})
Expand Down Expand Up @@ -266,12 +268,12 @@ function _setcoefficient!(m::Optimizer, coef, constr::Integer, blk::Integer, i::
push!(m.lpdrows, m.blk[blk] + i - 1) # -1 because indexing starts at 0 in DSDP
push!(m.lpcoefs, coef)
else
error("Semidefinite matrix variables are not supported yet so only linear programs are supported at the moment.")
error("Positive semidefinite matrix variables are not supported yet so only linear programs are supported at the moment.")
end
end

# Loads objective coefficient α * vi
function load_objective_term!(optimizer::Optimizer, α, vi::MOI.VariableIndex)
function load_objective_term!(optimizer::Optimizer, index_map, α, vi::MOI.VariableIndex)
blk, i, j = varmap(optimizer, vi)
coef = optimizer.objective_sign * α
if i != j
Expand Down Expand Up @@ -301,6 +303,9 @@ function MOI.copy_to(dest::Optimizer, src::MOI.ModelLike)
)
end
cis_src = MOI.get(src, MOI.ListOfConstraintIndices{AFF,EQ}())
if isempty(cis_src)
throw(ArgumentError("DSDP does not support problems with no constraint."))
end
dest.b = Vector{Cdouble}(undef, length(cis_src))

_free(dest)
Expand Down Expand Up @@ -352,7 +357,7 @@ function MOI.copy_to(dest::Optimizer, src::MOI.ModelLike)
SetDualObjective(dest.dsdp, k, MOI.constant(set))
for t in func.terms
if !iszero(t.coefficient)
blk, i, j = varmap(dest, t.variable)
blk, i, j = varmap(dest, index_map[t.variable])
coef = t.coefficient
if i != j
coef /= 2
Expand Down Expand Up @@ -390,6 +395,7 @@ function MOI.copy_to(dest::Optimizer, src::MOI.ModelLike)
if !iszero(term.coefficient)
load_objective_term!(
dest,
index_map,
term.coefficient,
index_map[term.variable],
)
Expand Down
178 changes: 119 additions & 59 deletions test/MOI_wrapper.jl
Original file line number Diff line number Diff line change
@@ -1,71 +1,131 @@
module TestDSDP

using Test
using MathOptInterface
import DSDP

const MOI = MathOptInterface
const MOIT = MOI.DeprecatedTest
const MOIU = MOI.Utilities
const MOIB = MOI.Bridges

import DSDP
const optimizer = DSDP.Optimizer()

@testset "SolverName" begin
@test MOI.get(optimizer, MOI.SolverName()) == "DSDP"
function runtests()
for name in names(@__MODULE__; all = true)
if startswith("$(name)", "test_")
@testset "$(name)" begin
getfield(@__MODULE__, name)()
end
end
end
return
end

const cache = MOIU.UniversalFallback(MOIU.Model{Float64}())
const cached = MOIU.CachingOptimizer(cache, optimizer)
const bridged = MOIB.full_bridge_optimizer(cached, Float64)
const config = MOIT.Config(atol=1e-2, rtol=1e-2)
function test_solver_name()
@test MOI.get(DSDP.Optimizer(), MOI.SolverName()) == "DSDP"
end

@testset "Unit" begin
MOIT.unittest(bridged, config, [
# To investigate...
"solve_duplicate_terms_obj", "solve_with_lowerbound",
"solve_blank_obj", "solve_affine_interval",
"solve_singlevariable_obj", "solve_constant_obj",
"solve_affine_deletion_edge_cases",
"solve_with_upperbound",
# Expression: MOI.get(model, MOI.TerminationStatus()) == MOI.INFEASIBLE
# Evaluated: MathOptInterface.OPTIMAL == MathOptInterface.INFEASIBLE
"solve_farkas_equalto_lower",
"solve_farkas_equalto_upper",
"solve_farkas_variable_lessthan",
"solve_farkas_variable_lessthan_max",
"solve_farkas_greaterthan",
"solve_farkas_interval_upper",
"solve_farkas_lessthan",
"solve_farkas_interval_lower",
# TODO should work when SDP is complete
"solve_qp_zero_offdiag",
"solve_start_soc",
# `NumberOfThreads` not supported.
"number_threads",
# `TimeLimitSec` not supported.
"time_limit_sec",
# `SolveTime` not supported.
"solve_time",
# Quadratic functions are not supported
"solve_qcp_edge_cases", "solve_qp_edge_cases",
# Integer and ZeroOne sets are not supported
"solve_integer_edge_cases", "solve_objbound_edge_cases",
"solve_zero_one_with_bounds_1",
"solve_zero_one_with_bounds_2",
"solve_zero_one_with_bounds_3"
])
function test_options()
param = MOI.RawOptimizerAttribute("bad_option")
err = MOI.UnsupportedAttribute(param)
@test_throws err MOI.set(
DSDP.Optimizer(),
MOI.RawOptimizerAttribute("bad_option"),
0,
)
end

@testset "Continuous Linear" begin
# See explanation in `MOI/test/Bridges/lazy_bridge_optimizer.jl`.
# This is to avoid `Variable.VectorizeBridge` which does not support
# `ConstraintSet` modification.
MOIB.remove_bridge(bridged, MOIB.Constraint.ScalarSlackBridge{Float64})
MOIT.contlineartest(bridged, config, [
# To investigate...
"linear1", "linear2", "linear3", "linear5", "linear8a", "linear9", "linear10", "linear10b", "linear11", "linear12", "linear14", "partial_start"
])
function test_runtests()
model = MOI.Utilities.CachingOptimizer(
MOI.Utilities.UniversalFallback(MOI.Utilities.Model{Float64}()),
MOI.instantiate(DSDP.Optimizer, with_bridge_type = Float64),
)
# `Variable.ZerosBridge` makes dual needed by some tests fail.
MOI.Bridges.remove_bridge(
model.optimizer,
MathOptInterface.Bridges.Variable.ZerosBridge{Float64},
)
MOI.set(model, MOI.Silent(), true)
MOI.Test.runtests(
model,
MOI.Test.Config(
rtol = 1e-3,
atol = 1e-3,
exclude = Any[
MOI.ConstraintBasisStatus,
MOI.VariableBasisStatus,
MOI.ObjectiveBound,
MOI.SolverVersion,
],
),
exclude = String[
# ArgumentError: DSDP does not support problems with no constraint.
# See https://github.com/jump-dev/MathOptInterface.jl/issues/1741#issuecomment-1057286739
"test_solve_optimize_twice",
"test_solve_result_index",
"test_quadratic_nonhomogeneous",
"test_quadratic_integration",
"test_objective_ObjectiveFunction_constant",
"test_objective_ObjectiveFunction_VariableIndex",
"test_objective_FEASIBILITY_SENSE_clears_objective",
"test_modification_transform_singlevariable_lessthan",
"test_modification_set_singlevariable_lessthan",
"test_modification_delete_variables_in_a_batch",
"test_modification_delete_variable_with_single_variable_obj",
"test_modification_const_scalar_objective",
"test_modification_coef_scalar_objective",
"test_attribute_RawStatusString",
"test_attribute_SolveTimeSec",
"test_objective_ObjectiveFunction_blank",
"test_objective_ObjectiveFunction_duplicate_terms",
"test_solve_TerminationStatus_DUAL_INFEASIBLE",
# TODO investigate
# Expression: MOI.get(model, MOI.TerminationStatus()) == config.infeasible_status
# Evaluated: MathOptInterface.OPTIMAL == MathOptInterface.INFEASIBLE
"test_conic_NormInfinityCone_INFEASIBLE",
"test_conic_NormOneCone_INFEASIBLE",
"test_conic_linear_INFEASIBLE",
"test_conic_linear_INFEASIBLE_2",
"test_solve_DualStatus_INFEASIBILITY_CERTIFICATE_EqualTo_lower",
"test_solve_DualStatus_INFEASIBILITY_CERTIFICATE_EqualTo_upper",
"test_solve_DualStatus_INFEASIBILITY_CERTIFICATE_GreaterThan",
"test_solve_DualStatus_INFEASIBILITY_CERTIFICATE_Interval_lower",
"test_solve_DualStatus_INFEASIBILITY_CERTIFICATE_Interval_upper",
"test_solve_DualStatus_INFEASIBILITY_CERTIFICATE_LessThan",
"test_solve_DualStatus_INFEASIBILITY_CERTIFICATE_VariableIndex_LessThan",
# TODO investigate
# Incorrect result value
"test_conic_NormInfinityCone_3",
"test_conic_NormInfinityCone_VectorAffineFunction",
"test_conic_NormInfinityCone_VectorOfVariables",
"test_conic_NormOneCone",
"test_conic_NormOneCone_VectorAffineFunction",
"test_conic_NormOneCone_VectorOfVariables",
"test_conic_linear_VectorAffineFunction",
"test_conic_linear_VectorAffineFunction_2",
"test_conic_linear_VectorOfVariables",
"test_constraint_ScalarAffineFunction_Interval",
# Incorrect objective
# See https://github.com/jump-dev/MathOptInterface.jl/issues/1759
"test_infeasible_MAX_SENSE",
"test_infeasible_MAX_SENSE_offset",
"test_infeasible_MIN_SENSE",
"test_infeasible_MIN_SENSE_offset",
"test_infeasible_affine_MAX_SENSE",
"test_infeasible_affine_MAX_SENSE_offset",
"test_infeasible_affine_MIN_SENSE",
"test_infeasible_affine_MIN_SENSE_offset",
"test_linear_Interval_inactive",
"test_linear_integration",
"test_linear_integration_Interval",
"test_linear_integration_delete_variables",
"test_linear_transform",
"test_modification_affine_deletion_edge_cases",
"test_modification_multirow_vectoraffine_nonpos",
"test_modification_set_scalaraffine_lessthan",
"test_variable_solve_with_lowerbound",
"test_variable_solve_with_upperbound",
],
)
return
end

#@testset "Conic tests" begin
# contconictest(bridged, config)
#end
end # module

TestDSDP.runtests()