Skip to content
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
5 changes: 4 additions & 1 deletion NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ v0.10.0 (In development)

**This is a breaking release.**

Breaking renames:
Breaking renames:

- `ListOfConstraints` has been renamed to `ListOfConstraintTypesPresent`
- `SolveTime` has been renamed to `SolveTimeSec`
Expand All @@ -22,6 +22,9 @@ Breaking behavior changes:
- `CachingOptimizer`s are now initialized as `EMPTY_OPTIMIZER` instead of `ATTACHED_OPTIMIZER`.
If your code relies on the optimizer being attached, call `MOIU.attach_optimizer(model)`
after creation.
- The `dimension` argument to `Complements(dimension::Int)` should now be the
length of the corresponding function, instead of half the length. An
`ArgumentError` is thrown if `dimension` is not even.

v0.9.21 (April 23, 2021)
---------------------------
Expand Down
2 changes: 1 addition & 1 deletion src/FileFormats/MOF/read.jl
Original file line number Diff line number Diff line change
Expand Up @@ -452,7 +452,7 @@ function set_to_moi(::Val{:DualExponentialCone}, ::Object)
end

function set_to_moi(::Val{:Complements}, object::Object)
return MOI.Complements(div(object["dimension"], 2))
return MOI.Complements(object["dimension"])
end

# ========== Typed vector sets ==========
Expand Down
8 changes: 1 addition & 7 deletions src/FileFormats/MOF/write.jl
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,7 @@ end
function head_name(::Type{MOI.PositiveSemidefiniteConeSquare})
return "PositiveSemidefiniteConeSquare"
end
head_name(::Type{MOI.Complements}) = "Complements"

# ========== Typed vector sets ==========
head_name(::Type{<:MOI.PowerCone}) = "PowerCone"
Expand All @@ -302,10 +303,3 @@ function moi_to_object(
"activate_on" => (I == MOI.ACTIVATE_ON_ONE) ? "one" : "zero",
)
end

function moi_to_object(set::MOI.Complements, ::Dict{MOI.VariableIndex,String})
return OrderedObject(
"type" => "Complements",
"dimension" => MOI.dimension(set),
)
end
2 changes: 1 addition & 1 deletion src/Test/UnitTests/basic_constraint_tests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ const BasicConstraintTests = Dict(
(MOI.VectorAffineFunction{Float64}, MOI.Nonnegatives) =>
(dummy_vector_affine, 2, MOI.Nonnegatives(2)),
(MOI.VectorAffineFunction{Float64}, MOI.Complements) =>
(dummy_vector_affine, 2, MOI.Complements(1)),
(dummy_vector_affine, 2, MOI.Complements(2)),
(MOI.VectorAffineFunction{Float64}, MOI.NormInfinityCone) =>
(dummy_vector_affine, 3, MOI.NormInfinityCone(3)),
(MOI.VectorAffineFunction{Float64}, MOI.NormOneCone) =>
Expand Down
4 changes: 2 additions & 2 deletions src/Test/nlp.jl
Original file line number Diff line number Diff line change
Expand Up @@ -527,7 +527,7 @@ function test_linear_mixed_complementarity(
MOI.add_constraint(
model,
MOI.VectorAffineFunction(terms, [q; 0.0; 0.0; 0.0; 0.0]),
MOI.Complements(4),
MOI.Complements(8),
)
@test MOI.get(model, MOI.TerminationStatus()) == MOI.OPTIMIZE_NOT_CALLED
if config.solve
Expand Down Expand Up @@ -631,7 +631,7 @@ function test_qp_complementarity_constraint(
MOI.add_constraint(
model,
MOI.VectorOfVariables([x[3], x[4], x[5], x[6], x[7], x[8]]),
MOI.Complements(3),
MOI.Complements(6),
)
@test MOI.get(model, MOI.TerminationStatus()) == MOI.OPTIMIZE_NOT_CALLED
if config.solve
Expand Down
25 changes: 18 additions & 7 deletions src/sets.jl
Original file line number Diff line number Diff line change
Expand Up @@ -806,10 +806,11 @@ The set corresponding to a mixed complementarity constraint.
Complementarity constraints should be specified with an
[`AbstractVectorFunction`](@ref)-in-`Complements(dimension)` constraint.

The dimension of the vector-valued function `F` must be `2 * dimension`. This
The dimension of the vector-valued function `F` must be `dimension`. This
defines a complementarity constraint between the scalar function `F[i]` and the
variable in `F[i + dimension]`. Thus, `F[i + dimension]` must be interpretable
as a single variable `x_i` (e.g., `1.0 * x + 0.0`).
variable in `F[i + dimension/2]`. Thus, `F[i + dimension/2]` must be
interpretable as a single variable `x_i` (e.g., `1.0 * x + 0.0`), and
`dimension` must be even.

The mixed complementarity problem consists of finding `x_i` in the interval
`[lb, ub]` (i.e., in the set `Interval(lb, ub)`), such that the following holds:
Expand All @@ -826,7 +827,7 @@ Classically, the bounding set for `x_i` is `Interval(0, Inf)`, which recovers:
The problem:

x -in- Interval(-1, 1)
[-4 * x - 3, x] -in- Complements(1)
[-4 * x - 3, x] -in- Complements(2)

defines the mixed complementarity problem where the following holds:

Expand All @@ -844,17 +845,27 @@ The function `F` can also be defined in terms of single variables. For example,
the problem:

[x_3, x_4] -in- Nonnegatives(2)
[x_1, x_2, x_3, x_4] -in- Complements(2)
[x_1, x_2, x_3, x_4] -in- Complements(4)

defines the complementarity problem where `0 <= x_1 ⟂ x_3 >= 0` and
`0 <= x_2 ⟂ x_4 >= 0`.
"""
struct Complements <: AbstractVectorSet
dimension::Int
# Need an explicit Int64 here, because JSON parses Int as Int64, even on
# 32-bit machines.
function Complements(dimension::Union{Int,Int64})
if !iseven(dimension)
throw(
ArgumentError(
"The dimension of a Complements set must be even.",
),
)
end
return new(convert(Int, dimension))
end
end

dimension(set::Complements) = 2 * set.dimension

# isbits types, nothing to copy
function Base.copy(
set::Union{
Expand Down
2 changes: 1 addition & 1 deletion test/FileFormats/MOF/MOF.jl
Original file line number Diff line number Diff line change
Expand Up @@ -390,7 +390,7 @@ end
end
@testset "Complements" begin
test_model_equality(
"variables: x, y\nc1: [x, y] in Complements(1)",
"variables: x, y\nc1: [x, y] in Complements(2)",
["x", "y"],
["c1"],
)
Expand Down
6 changes: 4 additions & 2 deletions test/sets.jl
Original file line number Diff line number Diff line change
Expand Up @@ -104,9 +104,11 @@ Base.copy(mlt::MutLessThan) = MutLessThan(Base.copy(mlt.upper))
@test MOI.dimension(
MOI.IndicatorSet{MOI.ACTIVATE_ON_ONE}(MOI.LessThan(1.0)),
) == 2
@test MOI.dimension(MOI.Complements(5)) == 10
@test MOI.dimension(MOI.Complements(10)) == 10
end
@testset "Complements" begin
@test_throws ArgumentError MOI.Complements(3)
end

@testset "Dual Set" begin
function dual_set_test(set1, set2)
@test MOI.dual_set(set1) == set2
Expand Down