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
8 changes: 7 additions & 1 deletion src/Test/Test.jl
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ mutable struct Config{T<:Real}
atol::T
rtol::T
optimal_status::MOI.TerminationStatusCode
infeasible_status::MOI.TerminationStatusCode
exclude::Vector{Any}
end

Expand All @@ -21,6 +22,7 @@ end
atol::Real = Base.rtoldefault(T),
rtol::Real = Base.rtoldefault(T),
optimal_status::MOI.TerminationStatusCode = MOI.OPTIMAL,
infeasible_status::MOI.TerminationStatusCode = MOI.INFEASIBLE,
exclude::Vector{Any} = Any[],
) where {T}

Expand All @@ -34,6 +36,8 @@ Return an object that is used to configure various tests.
when comparing solutions.
* `optimal_status = MOI.OPTIMAL`: Set to `MOI.LOCALLY_SOLVED` if the solver
cannot prove global optimality.
* `infeasible_status = MOI.INFEASIBLE`: Set to `MOI.LOCALLY_INFEASIBLE` if the
solver cannot prove global infeasibility.
* `exclude = Vector{Any}`: Pass attributes or functions to `exclude` to skip
parts of tests that require certain functionality. Common arguments include:
- `MOI.delete` to skip deletion-related tests
Expand Down Expand Up @@ -64,16 +68,18 @@ function Config(
atol::Real = Base.rtoldefault(T),
rtol::Real = Base.rtoldefault(T),
optimal_status::MOI.TerminationStatusCode = MOI.OPTIMAL,
infeasible_status::MOI.TerminationStatusCode = MOI.INFEASIBLE,
exclude::Vector{Any} = Any[],
) where {T<:Real}
return Config{T}(atol, rtol, optimal_status, exclude)
return Config{T}(atol, rtol, optimal_status, infeasible_status, exclude)
end

function Base.copy(config::Config{T}) where {T}
return Config{T}(
config.atol,
config.rtol,
config.optimal_status,
config.infeasible_status,
copy(config.exclude),
)
end
Expand Down
15 changes: 9 additions & 6 deletions src/Test/test_conic.jl
Original file line number Diff line number Diff line change
Expand Up @@ -521,7 +521,7 @@ function test_conic_linear_INFEASIBLE(model::MOI.ModelLike, config::Config)
@test MOI.get(model, MOI.TerminationStatus()) == MOI.OPTIMIZE_NOT_CALLED
MOI.optimize!(model)
@test MOI.get(model, MOI.TerminationStatus()) in
[MOI.INFEASIBLE, MOI.INFEASIBLE_OR_UNBOUNDED]
[config.infeasible_status, MOI.INFEASIBLE_OR_UNBOUNDED]
# TODO test dual feasibility and objective sign
end
return
Expand Down Expand Up @@ -597,7 +597,7 @@ function test_conic_linear_INFEASIBLE_2(model::MOI.ModelLike, config::Config)
@test MOI.get(model, MOI.TerminationStatus()) == MOI.OPTIMIZE_NOT_CALLED
MOI.optimize!(model)
@test MOI.get(model, MOI.TerminationStatus()) in
[MOI.INFEASIBLE, MOI.INFEASIBLE_OR_UNBOUNDED]
[config.infeasible_status, MOI.INFEASIBLE_OR_UNBOUNDED]
# TODO test dual feasibility and objective sign
end
return
Expand Down Expand Up @@ -928,7 +928,8 @@ function test_conic_NormInfinityCone_INFEASIBLE(
if _supports(config, MOI.optimize!)
@test MOI.get(model, MOI.TerminationStatus()) == MOI.OPTIMIZE_NOT_CALLED
MOI.optimize!(model)
@test MOI.get(model, MOI.TerminationStatus()) == MOI.INFEASIBLE
@test MOI.get(model, MOI.TerminationStatus()) ==
config.infeasible_status
@test MOI.get(model, MOI.PrimalStatus()) in
(MOI.NO_SOLUTION, MOI.INFEASIBLE_POINT)
# TODO test dual feasibility and objective sign
Expand Down Expand Up @@ -1351,7 +1352,8 @@ function test_conic_NormOneCone_INFEASIBLE(model::MOI.ModelLike, config::Config)
if _supports(config, MOI.optimize!)
@test MOI.get(model, MOI.TerminationStatus()) == MOI.OPTIMIZE_NOT_CALLED
MOI.optimize!(model)
@test MOI.get(model, MOI.TerminationStatus()) == MOI.INFEASIBLE
@test MOI.get(model, MOI.TerminationStatus()) ==
config.infeasible_status
@test MOI.get(model, MOI.PrimalStatus()) in
(MOI.NO_SOLUTION, MOI.INFEASIBLE_POINT)
# TODO test dual feasibility and objective sign
Expand Down Expand Up @@ -2005,7 +2007,8 @@ function test_conic_SecondOrderCone_INFEASIBLE(
if _supports(config, MOI.optimize!)
@test MOI.get(model, MOI.TerminationStatus()) == MOI.OPTIMIZE_NOT_CALLED
MOI.optimize!(model)
@test MOI.get(model, MOI.TerminationStatus()) == MOI.INFEASIBLE
@test MOI.get(model, MOI.TerminationStatus()) ==
config.infeasible_status
@test MOI.get(model, MOI.PrimalStatus()) in
(MOI.NO_SOLUTION, MOI.INFEASIBLE_POINT)
# TODO test dual feasibility and objective sign
Expand Down Expand Up @@ -2445,7 +2448,7 @@ function test_conic_RotatedSecondOrderCone_INFEASIBLE(
@test MOI.get(model, MOI.TerminationStatus()) == MOI.OPTIMIZE_NOT_CALLED
MOI.optimize!(model)
@test MOI.get(model, MOI.TerminationStatus()) in
[MOI.INFEASIBLE, MOI.INFEASIBLE_OR_UNBOUNDED]
[config.infeasible_status, MOI.INFEASIBLE_OR_UNBOUNDED]
has_certificate = MOI.get(model, MOI.DualStatus()) in [
MOI.INFEASIBILITY_CERTIFICATE,
MOI.NEARLY_INFEASIBILITY_CERTIFICATE,
Expand Down
2 changes: 1 addition & 1 deletion src/Test/test_constraint.jl
Original file line number Diff line number Diff line change
Expand Up @@ -609,7 +609,7 @@ function test_constraint_ZeroOne_bounds_3(model::MOI.ModelLike, config::Config)
)
x = MOI.get(model, MOI.VariableIndex, "x")
MOI.optimize!(model)
@test MOI.get(model, MOI.TerminationStatus()) == MOI.INFEASIBLE
@test MOI.get(model, MOI.TerminationStatus()) == config.infeasible_status
return
end

Expand Down
6 changes: 4 additions & 2 deletions src/Test/test_infeasibility_certificates.jl
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,8 @@ for sense in (MOI.MIN_SENSE, MOI.MAX_SENSE), offset in (0.0, 1.2)
cu = MOI.add_constraint(model, 1.0 * x, MOI.LessThan(1.4))
MOI.optimize!(model)
@requires(
MOI.get(model, MOI.TerminationStatus()) == MOI.INFEASIBLE,
MOI.get(model, MOI.TerminationStatus()) ==
config.infeasible_status,
)
@requires(
MOI.get(model, MOI.DualStatus()) ==
Expand Down Expand Up @@ -137,7 +138,8 @@ for sense in (MOI.MIN_SENSE, MOI.MAX_SENSE), offset in (0.0, 1.2)
cu = MOI.add_constraint(model, x, MOI.LessThan(1.4))
MOI.optimize!(model)
@requires(
MOI.get(model, MOI.TerminationStatus()) == MOI.INFEASIBLE,
MOI.get(model, MOI.TerminationStatus()) ==
config.infeasible_status,
)
@requires(
MOI.get(model, MOI.DualStatus()) ==
Expand Down
15 changes: 6 additions & 9 deletions src/Test/test_linear.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1432,9 +1432,8 @@ function test_linear_INFEASIBLE(
if _supports(config, MOI.optimize!)
@test MOI.get(model, MOI.TerminationStatus()) == MOI.OPTIMIZE_NOT_CALLED
MOI.optimize!(model)
@test MOI.get(model, MOI.TerminationStatus()) == MOI.INFEASIBLE ||
MOI.get(model, MOI.TerminationStatus()) ==
MOI.INFEASIBLE_OR_UNBOUNDED
@test MOI.get(model, MOI.TerminationStatus()) in
(config.infeasible_status, MOI.INFEASIBLE_OR_UNBOUNDED)
has_certificate =
MOI.get(model, MOI.DualStatus()) == MOI.INFEASIBILITY_CERTIFICATE
if _supports(config, MOI.ConstraintDual) && has_certificate
Expand Down Expand Up @@ -2334,9 +2333,8 @@ function test_linear_INFEASIBLE_2(
if _supports(config, MOI.optimize!)
@test MOI.get(model, MOI.TerminationStatus()) == MOI.OPTIMIZE_NOT_CALLED
MOI.optimize!(model)
@test MOI.get(model, MOI.TerminationStatus()) == MOI.INFEASIBLE ||
MOI.get(model, MOI.TerminationStatus()) ==
MOI.INFEASIBLE_OR_UNBOUNDED
@test MOI.get(model, MOI.TerminationStatus()) in
(config.infeasible_status, MOI.INFEASIBLE_OR_UNBOUNDED)
has_certificate =
MOI.get(model, MOI.DualStatus()) == MOI.INFEASIBILITY_CERTIFICATE
if _supports(config, MOI.ConstraintDual) && has_certificate
Expand Down Expand Up @@ -3982,9 +3980,8 @@ function _test_linear_SemiXXX_integration(
MOI.set(model, MOI.ConstraintSet(), vc2, MOI.EqualTo(T(4)))
if _supports(config, MOI.optimize!)
MOI.optimize!(model)
@test MOI.get(model, MOI.TerminationStatus()) == MOI.INFEASIBLE ||
MOI.get(model, MOI.TerminationStatus()) ==
MOI.INFEASIBLE_OR_UNBOUNDED
@test MOI.get(model, MOI.TerminationStatus()) in
(config.infeasible_status, MOI.INFEASIBLE_OR_UNBOUNDED)
end
return
end
Expand Down
32 changes: 16 additions & 16 deletions src/Test/test_solve.jl
Original file line number Diff line number Diff line change
Expand Up @@ -426,7 +426,7 @@ function test_solve_DualStatus_INFEASIBILITY_CERTIFICATE_EqualTo_upper(
MOI.EqualTo(-1.0),
)
MOI.optimize!(model)
@test MOI.get(model, MOI.TerminationStatus()) == MOI.INFEASIBLE
@test MOI.get(model, MOI.TerminationStatus()) == config.infeasible_status
if MOI.get(model, MOI.DualStatus()) != MOI.INFEASIBILITY_CERTIFICATE
return
end
Expand Down Expand Up @@ -481,7 +481,7 @@ function test_solve_DualStatus_INFEASIBILITY_CERTIFICATE_EqualTo_lower(
MOI.EqualTo(1.0),
)
MOI.optimize!(model)
@test MOI.get(model, MOI.TerminationStatus()) == MOI.INFEASIBLE
@test MOI.get(model, MOI.TerminationStatus()) == config.infeasible_status
if MOI.get(model, MOI.DualStatus()) != MOI.INFEASIBILITY_CERTIFICATE
return
end
Expand Down Expand Up @@ -535,7 +535,7 @@ function test_solve_DualStatus_INFEASIBILITY_CERTIFICATE_LessThan(
MOI.LessThan(-1.0),
)
MOI.optimize!(model)
@test MOI.get(model, MOI.TerminationStatus()) == MOI.INFEASIBLE
@test MOI.get(model, MOI.TerminationStatus()) == config.infeasible_status
if MOI.get(model, MOI.DualStatus()) != MOI.INFEASIBILITY_CERTIFICATE
return
end
Expand Down Expand Up @@ -590,7 +590,7 @@ function test_solve_DualStatus_INFEASIBILITY_CERTIFICATE_GreaterThan(
MOI.GreaterThan(1.0),
)
MOI.optimize!(model)
@test MOI.get(model, MOI.TerminationStatus()) == MOI.INFEASIBLE
@test MOI.get(model, MOI.TerminationStatus()) == config.infeasible_status
if MOI.get(model, MOI.DualStatus()) != MOI.INFEASIBILITY_CERTIFICATE
return
end
Expand Down Expand Up @@ -645,7 +645,7 @@ function test_solve_DualStatus_INFEASIBILITY_CERTIFICATE_Interval_upper(
MOI.Interval(-2.0, -1.0),
)
MOI.optimize!(model)
@test MOI.get(model, MOI.TerminationStatus()) == MOI.INFEASIBLE
@test MOI.get(model, MOI.TerminationStatus()) == config.infeasible_status
if MOI.get(model, MOI.DualStatus()) != MOI.INFEASIBILITY_CERTIFICATE
return
end
Expand Down Expand Up @@ -700,7 +700,7 @@ function test_solve_DualStatus_INFEASIBILITY_CERTIFICATE_Interval_lower(
MOI.Interval(1.0, 2.0),
)
MOI.optimize!(model)
@test MOI.get(model, MOI.TerminationStatus()) == MOI.INFEASIBLE
@test MOI.get(model, MOI.TerminationStatus()) == config.infeasible_status
if MOI.get(model, MOI.DualStatus()) != MOI.INFEASIBILITY_CERTIFICATE
return
end
Expand Down Expand Up @@ -755,7 +755,7 @@ function test_solve_DualStatus_INFEASIBILITY_CERTIFICATE_VariableIndex_LessThan(
MOI.GreaterThan(1.0),
)
MOI.optimize!(model)
@test MOI.get(model, MOI.TerminationStatus()) == MOI.INFEASIBLE
@test MOI.get(model, MOI.TerminationStatus()) == config.infeasible_status
if MOI.get(model, MOI.DualStatus()) != MOI.INFEASIBILITY_CERTIFICATE
return
end
Expand Down Expand Up @@ -814,7 +814,7 @@ function test_solve_DualStatus_INFEASIBILITY_CERTIFICATE_VariableIndex_LessThan_
MOI.set(model, MOI.ObjectiveSense(), MOI.MAX_SENSE)
MOI.set(model, MOI.ObjectiveFunction{MOI.VariableIndex}(), x[1])
MOI.optimize!(model)
@test MOI.get(model, MOI.TerminationStatus()) == MOI.INFEASIBLE
@test MOI.get(model, MOI.TerminationStatus()) == config.infeasible_status
if MOI.get(model, MOI.DualStatus()) != MOI.INFEASIBILITY_CERTIFICATE
return
end
Expand Down Expand Up @@ -910,7 +910,7 @@ function test_solve_conflict_bound_bound(
@test MOI.get(model, MOI.ConflictStatus()) ==
MOI.COMPUTE_CONFLICT_NOT_CALLED
MOI.optimize!(model)
@test MOI.get(model, MOI.TerminationStatus()) == MOI.INFEASIBLE
@test MOI.get(model, MOI.TerminationStatus()) == config.infeasible_status
MOI.compute_conflict!(model)
@test MOI.get(model, MOI.ConflictStatus()) == MOI.CONFLICT_FOUND
@test MOI.get(model, MOI.ConstraintConflictStatus(), c1) == MOI.IN_CONFLICT
Expand Down Expand Up @@ -974,7 +974,7 @@ function test_solve_conflict_two_affine(
@test MOI.get(model, MOI.ConflictStatus()) ==
MOI.COMPUTE_CONFLICT_NOT_CALLED
MOI.optimize!(model)
@test MOI.get(model, MOI.TerminationStatus()) == MOI.INFEASIBLE
@test MOI.get(model, MOI.TerminationStatus()) == config.infeasible_status
MOI.compute_conflict!(model)
@test MOI.get(model, MOI.ConflictStatus()) == MOI.CONFLICT_FOUND
@test MOI.get(model, MOI.ConstraintConflictStatus(), c1) == MOI.IN_CONFLICT
Expand Down Expand Up @@ -1033,7 +1033,7 @@ function test_solve_conflict_invalid_interval(
@test MOI.get(model, MOI.ConflictStatus()) ==
MOI.COMPUTE_CONFLICT_NOT_CALLED
MOI.optimize!(model)
@test MOI.get(model, MOI.TerminationStatus()) == MOI.INFEASIBLE
@test MOI.get(model, MOI.TerminationStatus()) == config.infeasible_status
MOI.compute_conflict!(model)
@test MOI.get(model, MOI.ConflictStatus()) == MOI.CONFLICT_FOUND
@test MOI.get(model, MOI.ConstraintConflictStatus(), c1) == MOI.IN_CONFLICT
Expand Down Expand Up @@ -1095,7 +1095,7 @@ function test_solve_conflict_affine_affine(
@test MOI.get(model, MOI.ConflictStatus()) ==
MOI.COMPUTE_CONFLICT_NOT_CALLED
MOI.optimize!(model)
@test MOI.get(model, MOI.TerminationStatus()) == MOI.INFEASIBLE
@test MOI.get(model, MOI.TerminationStatus()) == config.infeasible_status
MOI.compute_conflict!(model)
@test MOI.get(model, MOI.ConflictStatus()) == MOI.CONFLICT_FOUND
@test MOI.get(model, MOI.ConstraintConflictStatus(), b1) == MOI.IN_CONFLICT
Expand Down Expand Up @@ -1169,7 +1169,7 @@ function test_solve_conflict_EqualTo(
@test MOI.get(model, MOI.ConflictStatus()) ==
MOI.COMPUTE_CONFLICT_NOT_CALLED
MOI.optimize!(model)
@test MOI.get(model, MOI.TerminationStatus()) == MOI.INFEASIBLE
@test MOI.get(model, MOI.TerminationStatus()) == config.infeasible_status
MOI.compute_conflict!(model)
@test MOI.get(model, MOI.ConflictStatus()) == MOI.CONFLICT_FOUND
@test MOI.get(model, MOI.ConstraintConflictStatus(), b1) == MOI.IN_CONFLICT
Expand Down Expand Up @@ -1243,7 +1243,7 @@ function test_solve_conflict_NOT_IN_CONFLICT(
@test MOI.get(model, MOI.ConflictStatus()) ==
MOI.COMPUTE_CONFLICT_NOT_CALLED
MOI.optimize!(model)
@test MOI.get(model, MOI.TerminationStatus()) == MOI.INFEASIBLE
@test MOI.get(model, MOI.TerminationStatus()) == config.infeasible_status
MOI.compute_conflict!(model)
@test MOI.get(model, MOI.ConflictStatus()) == MOI.CONFLICT_FOUND
@test MOI.get(model, MOI.ConstraintConflictStatus(), b1) == MOI.IN_CONFLICT
Expand Down Expand Up @@ -1363,7 +1363,7 @@ function test_solve_conflict_zeroone(
MOI.GreaterThan(T(2)),
)
MOI.optimize!(model)
@test MOI.get(model, MOI.TerminationStatus()) == MOI.INFEASIBLE
@test MOI.get(model, MOI.TerminationStatus()) == config.infeasible_status
MOI.compute_conflict!(model)
@test MOI.get(model, MOI.ConflictStatus()) == MOI.CONFLICT_FOUND
zeroone_conflict = MOI.get(model, MOI.ConstraintConflictStatus(), c1)
Expand Down Expand Up @@ -1426,7 +1426,7 @@ function test_solve_conflict_zeroone_2(
MOI.EqualTo(one(T) / T(2)),
)
MOI.optimize!(model)
@test MOI.get(model, MOI.TerminationStatus()) == MOI.INFEASIBLE
@test MOI.get(model, MOI.TerminationStatus()) == config.infeasible_status
MOI.compute_conflict!(model)
@test MOI.get(model, MOI.ConflictStatus()) == MOI.CONFLICT_FOUND
zeroone_conflict = MOI.get(model, MOI.ConstraintConflictStatus(), c1)
Expand Down