From 10b58c08da50b56c0c1028da0fda0011def33fb2 Mon Sep 17 00:00:00 2001 From: odow Date: Thu, 13 May 2021 12:27:04 +1200 Subject: [PATCH 1/2] Refactor tests into functional form --- test/attributes.jl | 91 +++++--- test/constraints.jl | 25 +- test/deprecate.jl | 22 +- test/errors.jl | 557 +++++++++++++++++++++++++++----------------- test/functions.jl | 292 +++++++++++++++++------ test/instantiate.jl | 42 +++- test/interval.jl | 19 -- test/isapprox.jl | 104 --------- test/isbits.jl | 14 -- test/runtests.jl | 34 +-- test/sets.jl | 451 ++++++++++++++++++++--------------- 11 files changed, 967 insertions(+), 684 deletions(-) delete mode 100644 test/interval.jl delete mode 100644 test/isapprox.jl delete mode 100644 test/isbits.jl diff --git a/test/attributes.jl b/test/attributes.jl index 9ac6ec6926..00db9f8ca1 100644 --- a/test/attributes.jl +++ b/test/attributes.jl @@ -1,40 +1,49 @@ -@testset "Attributes" begin - @testset "is_set_by_optimize" begin - @test MOI.is_set_by_optimize(MOI.TerminationStatus()) - @test !MOI.is_set_by_optimize(MOI.ConstraintSet()) - @test !MOI.is_set_by_optimize(MOI.ObjectiveSense()) - @test MOI.is_set_by_optimize(MOI.CallbackNodeStatus(1)) - end - @testset "is_copyable" begin - @test !MOI.is_copyable(MOI.TerminationStatus()) - @test !MOI.is_copyable(MOI.ConstraintSet()) - @test MOI.is_copyable(MOI.ObjectiveSense()) - end - @testset "supports" begin - model = DummyModel() - @test_throws ArgumentError MOI.supports(model, MOI.TerminationStatus()) - @test_throws ArgumentError begin - MOI.supports( - model, - MOI.ConstraintSet(), - MOI.ConstraintIndex{MOI.SingleVariable,MOI.EqualTo{Float64}}, - ) - end - @test MOI.supports(model, MOI.ObjectiveSense()) - end - @testset "set vector" begin - attr = MOI.VariablePrimalStart() - err = DimensionMismatch( - "Number of indices (1) does not match the " * - "number of values (2) set to `$attr`.", +module TestAttributes + +using Test +using MathOptInterface +const MOI = MathOptInterface + +include("dummy.jl") + +function test_attributes_is_set_by_optimize() + @test MOI.is_set_by_optimize(MOI.TerminationStatus()) + @test !MOI.is_set_by_optimize(MOI.ConstraintSet()) + @test !MOI.is_set_by_optimize(MOI.ObjectiveSense()) + @test MOI.is_set_by_optimize(MOI.CallbackNodeStatus(1)) +end + +function test_attributes_is_copyable() + @test !MOI.is_copyable(MOI.TerminationStatus()) + @test !MOI.is_copyable(MOI.ConstraintSet()) + @test MOI.is_copyable(MOI.ObjectiveSense()) +end + +function test_attributes_supports() + model = DummyModel() + @test_throws ArgumentError MOI.supports(model, MOI.TerminationStatus()) + @test_throws ArgumentError begin + MOI.supports( + model, + MOI.ConstraintSet(), + MOI.ConstraintIndex{MOI.SingleVariable,MOI.EqualTo{Float64}}, ) - model = DummyModel() - x = MOI.VariableIndex(1) - @test_throws err MOI.set(model, MOI.VariablePrimalStart(), [x], ones(2)) end + @test MOI.supports(model, MOI.ObjectiveSense()) end -@testset "test_integration_compute_conflict" begin +function test_attributes_set_vector() + attr = MOI.VariablePrimalStart() + err = DimensionMismatch( + "Number of indices (1) does not match the " * + "number of values (2) set to `$attr`.", + ) + model = DummyModel() + x = MOI.VariableIndex(1) + @test_throws err MOI.set(model, MOI.VariablePrimalStart(), [x], ones(2)) +end + +function test_attributes_integration_compute_conflict_1() optimizer = MOI.Utilities.MockOptimizer(MOI.Utilities.Model{Float64}()) model = MOI.Utilities.CachingOptimizer( MOI.Utilities.Model{Float64}(), @@ -90,7 +99,7 @@ MOI.Utilities.@model( () ) -@testset "test_integration_compute_conflict" begin +function test_attributes_integration_compute_conflict_2() optimizer = MOI.Utilities.MockOptimizer(OnlyScalarConstraints{Float64}()) model = MOI.Bridges.full_bridge_optimizer(optimizer, Float64) x = MOI.add_variable(model) @@ -107,3 +116,17 @@ MOI.Utilities.@model( @test MOI.get(model, MOI.ConflictStatus()) == MOI.CONFLICT_FOUND @test_throws ArgumentError MOI.get(model, MOI.ConstraintConflictStatus(), c) end + +function runtests() + for name in names(@__MODULE__; all = true) + if startswith("$name", "test_") + @testset "$(name)" begin + getfield(@__MODULE__, name)() + end + end + end +end + +end + +TestAttributes.runtests() diff --git a/test/constraints.jl b/test/constraints.jl index 0cd16f4c66..a06718f028 100644 --- a/test/constraints.jl +++ b/test/constraints.jl @@ -1,8 +1,10 @@ +module TestConstraints + using Test using MathOptInterface const MOI = MathOptInterface -function constant_not_zero_test(::Type{T}) where {T} +function _constant_not_zero_test(::Type{T}) where {T} S = MOI.EqualTo{T} x = MOI.VariableIndex(1) fx = MOI.SingleVariable(x) @@ -17,7 +19,22 @@ function constant_not_zero_test(::Type{T}) where {T} @test nothing === MOI.throw_if_scalar_and_constant_not_zero(func, MOI.Zeros) end -@testset "Constant not zero" begin - constant_not_zero_test(Int) - constant_not_zero_test(Float64) +function test_constraints_ConstantNotZero() + _constant_not_zero_test(Int) + _constant_not_zero_test(Float64) + return +end + +function runtests() + for name in names(@__MODULE__; all = true) + if startswith("$name", "test_") + @testset "$(name)" begin + getfield(@__MODULE__, name)() + end + end + end end + +end + +TestConstraints.runtests() diff --git a/test/deprecate.jl b/test/deprecate.jl index c3c847b071..3bb5305885 100644 --- a/test/deprecate.jl +++ b/test/deprecate.jl @@ -1,8 +1,10 @@ +module TestDeprecate + using Test using MathOptInterface const MOI = MathOptInterface -@testset "deprecations" begin +function test_deprecations_N() attr = MOI.VariablePrimal() @test_deprecated begin @test MOI._result_index_field(attr) == 1 @@ -26,16 +28,30 @@ const MOI = MathOptInterface end end -@testset "ScalarAffineTerm" begin +function test_deprecations_ScalarAffineTerm() x = MOI.VariableIndex(1) t = MOI.ScalarAffineTerm(1.0, x) @test_logs (:warn,) t.variable_index == x end -@testset "ScalarQuadraticTerm" begin +function test_deprecations_ScalarQuadraticTerm() x = MOI.VariableIndex(1) y = MOI.VariableIndex(2) t = MOI.ScalarQuadraticTerm(1.0, x, y) @test_logs (:warn,) t.variable_index_1 == x @test_logs (:warn,) t.variable_index_2 == y end + +function runtests() + for name in names(@__MODULE__; all = true) + if startswith("$name", "test_") + @testset "$(name)" begin + getfield(@__MODULE__, name)() + end + end + end +end + +end + +TestDeprecate.runtests() diff --git a/test/errors.jl b/test/errors.jl index 34195c590a..2b31133dc3 100644 --- a/test/errors.jl +++ b/test/errors.jl @@ -1,255 +1,361 @@ +module TestErrors + using Test using MathOptInterface const MOI = MathOptInterface include("dummy.jl") -@testset "Fallbacks for `set` methods" begin +function test_errors_fallback_AddVariableNotAllowed() model = DummyModel() - - @testset "AddVariableNotAllowed" begin - @test_throws MOI.AddVariableNotAllowed MOI.add_variable(model) - try - MOI.add_variable(model) - catch err - @test sprint(showerror, err) == - "MathOptInterface.AddVariableNotAllowed:" * - " Adding variables cannot be performed. You may want to use a" * - " `CachingOptimizer` in `AUTOMATIC` mode or you may need to call" * - " `reset_optimizer` before doing this operation if the" * - " `CachingOptimizer` is in `MANUAL` mode." - end - @test_throws MOI.AddVariableNotAllowed MOI.add_variables(model, 2) + @test_throws MOI.AddVariableNotAllowed MOI.add_variable(model) + try + MOI.add_variable(model) + catch err + @test sprint(showerror, err) == + "MathOptInterface.AddVariableNotAllowed:" * + " Adding variables cannot be performed. You may want to use a" * + " `CachingOptimizer` in `AUTOMATIC` mode or you may need to call" * + " `reset_optimizer` before doing this operation if the" * + " `CachingOptimizer` is in `MANUAL` mode." end + @test_throws MOI.AddVariableNotAllowed MOI.add_variables(model, 2) + return +end +function test_errors_inconsistent_vectorscalar() + model = DummyModel() vi = MOI.VariableIndex(1) func = MOI.SingleVariable(vi) + @test_throws( + MOI.ErrorException, + MOI.add_constraint( + model, + MOI.VectorOfVariables([vi, vi]), + MOI.EqualTo(0), + ) + ) + @test_throws( + MOI.ErrorException, + MOI.add_constraint(model, func, MOI.Nonnegatives(2)) + ) + return +end - @testset "Inconsistent Vector/Scalar errors" begin - @test_throws MOI.ErrorException begin - MOI.add_constraint( - model, - MOI.VectorOfVariables([vi, vi]), - MOI.EqualTo(0), - ) - end - @test_throws MOI.ErrorException begin - MOI.add_constraint(model, func, MOI.Nonnegatives(2)) - end +function _test_errors_UnsupportedConstraint(f) + model = DummyModel() + vi = MOI.VariableIndex(1) + func = MOI.SingleVariable(vi) + @test_throws( + MOI.UnsupportedConstraint, + f(model, func, MOI.EqualTo(0)), + ) + try + f(model, func, MOI.EqualTo(0)) + catch err + @test sprint(showerror, err) == + "$(MOI.UnsupportedConstraint{MOI.SingleVariable,MOI.EqualTo{Int}}):" * + " `$MOI.SingleVariable`-in-`$MOI.EqualTo{$Int}` constraint is" * + " not supported by the model." end - @testset "Unsupported constraint with $f" for f in ( - MOI.add_constraint, - MOIU.allocate_constraint, - (model, func, set) -> MOIU.load_constraint( + return +end + +function test_errors_UnsupportedConstraint() + _test_errors_UnsupportedConstraint(MOI.add_constraint) + _test_errors_UnsupportedConstraint(MOI.Utilities.allocate_constraint) + _test_errors_UnsupportedConstraint() do model, func, set + return MOI.Utilities.load_constraint( model, MOI.ConstraintIndex{typeof(func),typeof(set)}(1), func, set, - ), - ) - @test_throws MOI.UnsupportedConstraint begin - f(model, func, MOI.EqualTo(0)) - end - try - f(model, func, MOI.EqualTo(0)) - catch err - @test sprint(showerror, err) == - "$(MOI.UnsupportedConstraint{MOI.SingleVariable,MOI.EqualTo{Int}}):" * - " `$MOI.SingleVariable`-in-`$MOI.EqualTo{$Int}` constraint is" * - " not supported by the model." - end - end - @testset "Unsupported constraint for shortcuts" begin - @test_throws MOI.UnsupportedConstraint begin - MOI.add_constraint(model, vi, MOI.EqualTo(0)) - end - @test_throws MOI.UnsupportedConstraint begin - MOI.add_constraint(model, [vi, vi], MOI.Nonnegatives(2)) - end - @test_throws MOI.UnsupportedConstraint begin - MOI.add_constraints( - model, - [vi, vi], - [MOI.EqualTo(0), MOI.EqualTo(0)], - ) - end - end - @testset "add_constraint errors" begin - @test_throws MOI.AddConstraintNotAllowed begin - MOI.add_constraint(model, func, MOI.EqualTo(0.0)) - end - try - MOI.add_constraint(model, func, MOI.EqualTo(0.0)) - catch err - @test sprint(showerror, err) == - "$(MOI.AddConstraintNotAllowed{MOI.SingleVariable,MOI.EqualTo{Float64}}):" * - " Adding `$MOI.SingleVariable`-in-`$MOI.EqualTo{Float64}`" * - " constraints cannot be performed. You may want to use a" * - " `CachingOptimizer` in `AUTOMATIC` mode or you may need to call" * - " `reset_optimizer` before doing this operation if the" * - " `CachingOptimizer` is in `MANUAL` mode." - end - @test_throws MOI.AddConstraintNotAllowed begin - MOI.add_constraint(model, vi, MOI.EqualTo(0.0)) - end - @test_throws MOI.AddConstraintNotAllowed begin - MOI.add_constraint(model, [vi, vi], MOI.Zeros(2)) - end - @test_throws MOI.AddConstraintNotAllowed begin - MOI.add_constraints( - model, - [vi, vi], - [MOI.EqualTo(0.0), MOI.EqualTo(0.0)], - ) - end + ) end + return +end - @testset "allocate_constraint errors" begin - @test_throws MOI.ErrorException begin - MOIU.allocate_constraint(model, func, MOI.EqualTo(0.0)) - end - try - MOIU.allocate_constraint(model, func, MOI.EqualTo(0.0)) - catch err - @test err === MOIU.ALLOCATE_LOAD_NOT_IMPLEMENTED - end +function test_errors_UnsupportedConstraint_shortcut() + model = DummyModel() + vi = MOI.VariableIndex(1) + @test_throws MOI.UnsupportedConstraint begin + MOI.add_constraint(model, vi, MOI.EqualTo(0)) end - @testset "load_constraint errors" begin - ci = MOI.ConstraintIndex{typeof(func),MOI.EqualTo{Float64}}(1) - @test_throws MOI.ErrorException begin - MOIU.load_constraint(model, ci, func, MOI.EqualTo(0.0)) - end - try - MOIU.load_constraint(model, ci, func, MOI.EqualTo(0.0)) - catch err - @test err === MOIU.ALLOCATE_LOAD_NOT_IMPLEMENTED - end + @test_throws MOI.UnsupportedConstraint begin + MOI.add_constraint(model, [vi, vi], MOI.Nonnegatives(2)) end - - ci = MOI.ConstraintIndex{MOI.SingleVariable,MOI.EqualTo{Float64}}(1) - - @testset "DeleteNotAllowed" begin - @test_throws MOI.DeleteNotAllowed{typeof(vi)} MOI.delete(model, vi) - try - MOI.delete(model, vi) - catch err - @test sprint(showerror, err) == - "MathOptInterface.DeleteNotAllowed{MathOptInterface.VariableIndex}:" * - " Deleting the index MathOptInterface.VariableIndex(1) cannot be" * - " performed. You may want to use a `CachingOptimizer` in" * - " `AUTOMATIC` mode or you may need to call `reset_optimizer`" * - " before doing this operation if the `CachingOptimizer` is in" * - " `MANUAL` mode." - end - @test_throws MOI.DeleteNotAllowed{typeof(ci)} MOI.delete(model, ci) - try - MOI.delete(model, ci) - catch err - @test sprint(showerror, err) == - "$(MathOptInterface.DeleteNotAllowed{MathOptInterface.ConstraintIndex{MathOptInterface.SingleVariable,MathOptInterface.EqualTo{Float64}}}):" * - " Deleting the index $(MathOptInterface.ConstraintIndex{MathOptInterface.SingleVariable,MathOptInterface.EqualTo{Float64}}(1))" * - " cannot be performed. You may want to use a `CachingOptimizer`" * - " in `AUTOMATIC` mode or you may need to call `reset_optimizer`" * - " before doing this operation if the `CachingOptimizer` is in" * - " `MANUAL` mode." - end + @test_throws MOI.UnsupportedConstraint begin + MOI.add_constraints( + model, + [vi, vi], + [MOI.EqualTo(0), MOI.EqualTo(0)], + ) end +end - @testset "Unsupported attribute with $f" for f in ( - MOI.set, - MOIU.load, - MOIU.allocate, +function test_errors_add_constraint() + model = DummyModel() + vi = MOI.VariableIndex(1) + func = MOI.SingleVariable(vi) + @test_throws( + MOI.AddConstraintNotAllowed, + MOI.add_constraint(model, func, MOI.EqualTo(0.0)), ) - @test_throws MOI.UnsupportedAttribute begin - f( - model, - MOI.ObjectiveFunction{MOI.SingleVariable}(), - MOI.SingleVariable(vi), - ) - end - @test_throws MOI.UnsupportedAttribute begin - f(model, MOI.ConstraintDualStart(), ci, 0.0) - end + try + MOI.add_constraint(model, func, MOI.EqualTo(0.0)) + catch err + @test sprint(showerror, err) == + "$(MOI.AddConstraintNotAllowed{MOI.SingleVariable,MOI.EqualTo{Float64}}):" * + " Adding `$MOI.SingleVariable`-in-`$MOI.EqualTo{Float64}`" * + " constraints cannot be performed. You may want to use a" * + " `CachingOptimizer` in `AUTOMATIC` mode or you may need to call" * + " `reset_optimizer` before doing this operation if the" * + " `CachingOptimizer` is in `MANUAL` mode." end + @test_throws( + MOI.AddConstraintNotAllowed, + MOI.add_constraint(model, vi, MOI.EqualTo(0.0)), + ) + @test_throws( + MOI.AddConstraintNotAllowed, + MOI.add_constraint(model, [vi, vi], MOI.Zeros(2)), + ) + @test_throws( + MOI.AddConstraintNotAllowed, + MOI.add_constraints( + model, + [vi, vi], + [MOI.EqualTo(0.0), MOI.EqualTo(0.0)], + ), + ) + return +end - @testset "SetAttributeNotAllowed" begin - @test_throws MOI.SetAttributeNotAllowed begin - MOI.set(model, MOI.ObjectiveSense(), MOI.MAX_SENSE) - end - @test_throws MOI.SetAttributeNotAllowed begin - MOI.set(model, MOI.ConstraintPrimalStart(), ci, 0.0) - end +function test_errors_allocate_constraint() + model = DummyModel() + vi = MOI.VariableIndex(1) + func = MOI.SingleVariable(vi) + @test_throws( + MOI.ErrorException, + MOIU.allocate_constraint(model, func, MOI.EqualTo(0.0)), + ) + try + MOIU.allocate_constraint(model, func, MOI.EqualTo(0.0)) + catch err + @test err === MOIU.ALLOCATE_LOAD_NOT_IMPLEMENTED end + return +end - @testset "$f errors" for f in (MOIU.load, MOIU.allocate) - @test_throws MOI.ErrorException begin - f(model, MOI.ObjectiveSense(), MOI.MAX_SENSE) - end - try - f(model, MOI.ObjectiveSense(), MOI.MAX_SENSE) - catch err - @test err === MOIU.ALLOCATE_LOAD_NOT_IMPLEMENTED - end - @test_throws MOI.ErrorException begin - f(model, MOI.ConstraintPrimalStart(), ci, 0.0) - end +function test_errors_load_constraint() + model = DummyModel() + vi = MOI.VariableIndex(1) + func = MOI.SingleVariable(vi) + ci = MOI.ConstraintIndex{typeof(func),MOI.EqualTo{Float64}}(1) + @test_throws( + MOI.ErrorException, + MOIU.load_constraint(model, ci, func, MOI.EqualTo(0.0)), + ) + try + MOIU.load_constraint(model, ci, func, MOI.EqualTo(0.0)) + catch err + @test err === MOIU.ALLOCATE_LOAD_NOT_IMPLEMENTED end + return +end - @testset "ConstraintFunction" begin - @test_throws MOI.SetAttributeNotAllowed begin - MOI.set(model, MOI.ConstraintFunction(), ci, func) - end - @test_throws ArgumentError begin - MOI.set( - model, - MOI.ConstraintFunction(), - ci, - MOI.ScalarAffineFunction([MOI.ScalarAffineTerm(1.0, vi)], 0.0), - ) - end +function test_errors_DeleteNotAllowed() + model = DummyModel() + vi = MOI.VariableIndex(1) + func = MOI.SingleVariable(vi) + ci = MOI.ConstraintIndex{MOI.SingleVariable,MOI.EqualTo{Float64}}(1) + @test_throws MOI.DeleteNotAllowed{typeof(vi)} MOI.delete(model, vi) + try + MOI.delete(model, vi) + catch err + @test sprint(showerror, err) == + "MathOptInterface.DeleteNotAllowed{MathOptInterface.VariableIndex}:" * + " Deleting the index MathOptInterface.VariableIndex(1) cannot be" * + " performed. You may want to use a `CachingOptimizer` in" * + " `AUTOMATIC` mode or you may need to call `reset_optimizer`" * + " before doing this operation if the `CachingOptimizer` is in" * + " `MANUAL` mode." end - @testset "ConstraintSet" begin - @test_throws MOI.SetAttributeNotAllowed begin - MOI.set(model, MOI.ConstraintSet(), ci, MOI.EqualTo(1.0)) - end - @test_throws ArgumentError begin - MOI.set(model, MOI.ConstraintSet(), ci, MOI.EqualTo(1)) - end - @test_throws ArgumentError begin - MOI.set(model, MOI.ConstraintSet(), ci, MOI.GreaterThan(1.0)) - end + @test_throws MOI.DeleteNotAllowed{typeof(ci)} MOI.delete(model, ci) + try + MOI.delete(model, ci) + catch err + @test sprint(showerror, err) == + "$(MathOptInterface.DeleteNotAllowed{MathOptInterface.ConstraintIndex{MathOptInterface.SingleVariable,MathOptInterface.EqualTo{Float64}}}):" * + " Deleting the index $(MathOptInterface.ConstraintIndex{MathOptInterface.SingleVariable,MathOptInterface.EqualTo{Float64}}(1))" * + " cannot be performed. You may want to use a `CachingOptimizer`" * + " in `AUTOMATIC` mode or you may need to call `reset_optimizer`" * + " before doing this operation if the `CachingOptimizer` is in" * + " `MANUAL` mode." end + return +end - @testset "ModifyNotAllowed" begin - change = MOI.ScalarConstantChange(1.0) - @testset "Constraint" begin - err = MOI.ModifyConstraintNotAllowed(ci, change) - @test_throws err MOI.modify(model, ci, change) - @test sprint(showerror, err) == - "$(MathOptInterface.ModifyConstraintNotAllowed{MathOptInterface.SingleVariable,MathOptInterface.EqualTo{Float64},MathOptInterface.ScalarConstantChange{Float64}}):" * - " Modifying the constraints $(MathOptInterface.ConstraintIndex{MathOptInterface.SingleVariable,MathOptInterface.EqualTo{Float64}}(1))" * - " with MathOptInterface.ScalarConstantChange{Float64}(1.0) cannot" * - " be performed. You may want to use a `CachingOptimizer` in" * - " `AUTOMATIC` mode or you may need to call `reset_optimizer`" * - " before doing this operation if the `CachingOptimizer` is in" * - " `MANUAL` mode." - end - @testset "Objective" begin - attr = MOI.ObjectiveFunction{MOI.SingleVariable}() - err = MOI.ModifyObjectiveNotAllowed(change) - @test_throws err MOI.modify(model, attr, change) - @test sprint(showerror, err) == - "$(MathOptInterface.ModifyObjectiveNotAllowed{MathOptInterface.ScalarConstantChange{Float64}}):" * - " Modifying the objective function with $(MathOptInterface.ScalarConstantChange{Float64}(1.0))" * - " cannot be performed. You may want to use a `CachingOptimizer`" * - " in `AUTOMATIC` mode or you may need to call `reset_optimizer`" * - " before doing this operation if the `CachingOptimizer` is in" * - " `MANUAL` mode." - end +function _test_unsupported_attribute(f) + model = DummyModel() + vi = MOI.VariableIndex(1) + func = MOI.SingleVariable(vi) + ci = MOI.ConstraintIndex{typeof(func),MOI.EqualTo{Float64}}(1) + @test_throws( + MOI.UnsupportedAttribute, + f( + model, + MOI.ObjectiveFunction{MOI.SingleVariable}(), + MOI.SingleVariable(vi), + ), + ) + @test_throws( + MOI.UnsupportedAttribute, + f(model, MOI.ConstraintDualStart(), ci, 0.0), + ) + return +end + +function test_errors_unsupported_attribute() + _test_unsupported_attribute(MOI.set) + _test_unsupported_attribute(MOI.Utilities.load) + _test_unsupported_attribute(MOI.Utilities.allocate) + return +end + +function test_errors_SetAttributeNotAllowed() + model = DummyModel() + vi = MOI.VariableIndex(1) + func = MOI.SingleVariable(vi) + ci = MOI.ConstraintIndex{typeof(func),MOI.EqualTo{Float64}}(1) + model = DummyModel() + @test_throws( + MOI.SetAttributeNotAllowed, + MOI.set(model, MOI.ObjectiveSense(), MOI.MAX_SENSE), + ) + @test_throws( + MOI.SetAttributeNotAllowed, + MOI.set(model, MOI.ConstraintPrimalStart(), ci, 0.0), + ) + return +end + +function test_errors_allocate() + model = DummyModel() + vi = MOI.VariableIndex(1) + func = MOI.SingleVariable(vi) + ci = MOI.ConstraintIndex{typeof(func),MOI.EqualTo{Float64}}(1) + @test_throws( + MOI.ErrorException, + MOI.Utilities.allocate(model, MOI.ObjectiveSense(), MOI.MAX_SENSE), + ) + try + MOI.Utilities.allocate(model, MOI.ObjectiveSense(), MOI.MAX_SENSE) + catch err + @test err === MOIU.ALLOCATE_LOAD_NOT_IMPLEMENTED + end + @test_throws( + MOI.ErrorException, + MOI.Utilities.allocate(model, MOI.ConstraintPrimalStart(), ci, 0.0), + ) + return +end + +function test_errors_load() + model = DummyModel() + vi = MOI.VariableIndex(1) + func = MOI.SingleVariable(vi) + ci = MOI.ConstraintIndex{typeof(func),MOI.EqualTo{Float64}}(1) + @test_throws( + MOI.ErrorException, + MOI.Utilities.load(model, MOI.ObjectiveSense(), MOI.MAX_SENSE) + ) + try + MOI.Utilities.load(model, MOI.ObjectiveSense(), MOI.MAX_SENSE) + catch err + @test err === MOIU.ALLOCATE_LOAD_NOT_IMPLEMENTED end + @test_throws( + MOI.ErrorException, + MOI.Utilities.load(model, MOI.ConstraintPrimalStart(), ci, 0.0), + ) + return end -@testset "Error messages" begin +function test_errors_ConstraintFunction_NotAllowed() + model = DummyModel() + vi = MOI.VariableIndex(1) + func = MOI.SingleVariable(vi) + ci = MOI.ConstraintIndex{typeof(func),MOI.EqualTo{Float64}}(1) + @test_throws( + MOI.SetAttributeNotAllowed, + MOI.set(model, MOI.ConstraintFunction(), ci, func) + ) + @test_throws( + ArgumentError, + MOI.set( + model, + MOI.ConstraintFunction(), + ci, + MOI.ScalarAffineFunction([MOI.ScalarAffineTerm(1.0, vi)], 0.0), + ), + ) + return +end + +function test_errors_ConstraintSet_NotAllowed() + model = DummyModel() + vi = MOI.VariableIndex(1) + func = MOI.SingleVariable(vi) + ci = MOI.ConstraintIndex{typeof(func),MOI.EqualTo{Float64}}(1) + @test_throws( + MOI.SetAttributeNotAllowed, + MOI.set(model, MOI.ConstraintSet(), ci, MOI.EqualTo(1.0)) + ) + @test_throws( + ArgumentError, + MOI.set(model, MOI.ConstraintSet(), ci, MOI.EqualTo(1)) + ) + @test_throws( + ArgumentError, + MOI.set(model, MOI.ConstraintSet(), ci, MOI.GreaterThan(1.0)) + ) +end + +function test_errors_ModifyNotAllowed_constraint() + model = DummyModel() + vi = MOI.VariableIndex(1) + func = MOI.SingleVariable(vi) + ci = MOI.ConstraintIndex{typeof(func),MOI.EqualTo{Float64}}(1) + change = MOI.ScalarConstantChange(1.0) + err = MOI.ModifyConstraintNotAllowed(ci, change) + @test_throws err MOI.modify(model, ci, change) + @test sprint(showerror, err) == + "$(MathOptInterface.ModifyConstraintNotAllowed{MathOptInterface.SingleVariable,MathOptInterface.EqualTo{Float64},MathOptInterface.ScalarConstantChange{Float64}}):" * + " Modifying the constraints $(MathOptInterface.ConstraintIndex{MathOptInterface.SingleVariable,MathOptInterface.EqualTo{Float64}}(1))" * + " with MathOptInterface.ScalarConstantChange{Float64}(1.0) cannot" * + " be performed. You may want to use a `CachingOptimizer` in" * + " `AUTOMATIC` mode or you may need to call `reset_optimizer`" * + " before doing this operation if the `CachingOptimizer` is in" * + " `MANUAL` mode." +end + +function test_errors_ModifyNotAllowed_objective() + model = DummyModel() + change = MOI.ScalarConstantChange(1.0) + attr = MOI.ObjectiveFunction{MOI.SingleVariable}() + err = MOI.ModifyObjectiveNotAllowed(change) + @test_throws err MOI.modify(model, attr, change) + @test sprint(showerror, err) == + "$(MathOptInterface.ModifyObjectiveNotAllowed{MathOptInterface.ScalarConstantChange{Float64}}):" * + " Modifying the objective function with $(MathOptInterface.ScalarConstantChange{Float64}(1.0))" * + " cannot be performed. You may want to use a `CachingOptimizer`" * + " in `AUTOMATIC` mode or you may need to call `reset_optimizer`" * + " before doing this operation if the `CachingOptimizer` is in" * + " `MANUAL` mode." +end + +function test_errors_show_SetAttributeNotAllowed() @test sprint(showerror, MOI.UnsupportedAttribute(MOI.Name())) == "$MOI.UnsupportedAttribute{$MOI.Name}:" * " Attribute $MOI.Name() is not supported by the model." @@ -276,17 +382,36 @@ end " to use a `CachingOptimizer` in `AUTOMATIC` mode or you may need to call" * " `reset_optimizer` before doing this operation if the `CachingOptimizer`" * " is in `MANUAL` mode." + return +end +function test_errors_ResultIndexBoundsError() @test sprint( showerror, MOI.ResultIndexBoundsError(MOI.VariablePrimal(1), 0), ) == "Result index of attribute MathOptInterface.VariablePrimal(1) out of" * " bounds. There are currently 0 solution(s) in the model." +end +function test_errors_InvalidCalbackUsage() @test sprint( showerror, MOI.InvalidCallbackUsage(MOI.LazyConstraintCallback(), MOI.UserCut(1)), ) == "InvalidCallbackUsage: Cannot submit $(MOI.UserCut(1)) inside a MathOptInterface.LazyConstraintCallback()." end + +function runtests() + for name in names(@__MODULE__; all = true) + if startswith("$name", "test_") + @testset "$(name)" begin + getfield(@__MODULE__, name)() + end + end + end +end + +end + +TestErrors.runtests() diff --git a/test/functions.jl b/test/functions.jl index 0aa7a61197..239f830897 100644 --- a/test/functions.jl +++ b/test/functions.jl @@ -1,84 +1,234 @@ +module TestFunctions + using Test using MathOptInterface const MOI = MathOptInterface -@testset "Functions" begin +""" + test_isbits() + +Test isbit-ness of VariableIndex and terms. + +It is important that these struct remain isbits as otherwise, the performance of +the corresponding function will be deteriored. These tests explicit this design +choice and makes sure that it remains the case. +""" +function test_isbits() + x = @inferred MOI.VariableIndex(1) + @test isbits(x) + at = @inferred MOI.ScalarAffineTerm(1.0, x) + @test isbits(at) + @test isbits(@inferred MOI.VectorAffineTerm(1, at)) + qt = @inferred MOI.ScalarQuadraticTerm(1.0, x, x) + @test isbits(qt) + @test isbits(@inferred MOI.VectorQuadraticTerm(1, qt)) +end + +function test_functions_broadcast() x = MOI.VariableIndex(1) y = MOI.VariableIndex(2) z = MOI.VariableIndex(3) - @testset "Broadcast" begin - xf = MOI.SingleVariable(x) - yf = MOI.SingleVariable(y) - zf = MOI.SingleVariable(z) - function sum_indices(sv1::MOI.SingleVariable, sv2::MOI.SingleVariable) - return sv1.variable.value + sv2.variable.value - end - @test sum_indices.(xf, [yf, zf]) == [3, 4] + xf = MOI.SingleVariable(x) + yf = MOI.SingleVariable(y) + zf = MOI.SingleVariable(z) + function sum_indices(sv1::MOI.SingleVariable, sv2::MOI.SingleVariable) + return sv1.variable.value + sv2.variable.value end - @testset "Copy" begin - @testset "VectorOfVariables" begin - f = MOI.VectorOfVariables([x, y]) - f_copy = copy(f) - f_copy.variables[2] = z - @test f.variables[2] == y + @test sum_indices.(xf, [yf, zf]) == [3, 4] +end + +function test_functions_copy_VectorOfVariables() + x = MOI.VariableIndex(1) + y = MOI.VariableIndex(2) + z = MOI.VariableIndex(3) + f = MOI.VectorOfVariables([x, y]) + f_copy = copy(f) + f_copy.variables[2] = z + @test f.variables[2] == y +end + +function test_functions_convert_SingleVariable() + model = MOI.Utilities.Model{Float64}() + x = MOI.add_variable(model) + f = MOI.SingleVariable(x) + f_vov = convert(MOI.VectorOfVariables, f) + @test f_vov ≈ MOI.VectorOfVariables([x]) + f_vaf = convert(MOI.VectorAffineFunction{Float64}, f) + @test f_vaf ≈ MOI.VectorAffineFunction( + [MOI.VectorAffineTerm(1, MOI.ScalarAffineTerm(1.0, x))], + [0.0], + ) + f_vqf = convert(MOI.VectorQuadraticFunction{Float64}, f) + @test f_vqf ≈ MOI.VectorQuadraticFunction( + [MOI.VectorAffineTerm(1, MOI.ScalarAffineTerm(1.0, x))], + MOI.VectorQuadraticTerm{Float64}[], + [0.0], + ) +end + +function test_functions_convert_ScalarAffineFunction() + model = MOI.Utilities.Model{Float64}() + x = MOI.add_variable(model) + f = MOI.ScalarAffineFunction([MOI.ScalarAffineTerm(2.0, x)], 1.0) + @test_throws(MethodError, convert(MOI.VectorOfVariables, f)) + f_vaf = convert(MOI.VectorAffineFunction{Float64}, f) + @test f_vaf ≈ MOI.VectorAffineFunction( + [MOI.VectorAffineTerm(1, MOI.ScalarAffineTerm(2.0, x))], + [1.0], + ) + f_vqf = convert(MOI.VectorQuadraticFunction{Float64}, f) + @test f_vqf ≈ MOI.VectorQuadraticFunction( + [MOI.VectorAffineTerm(1, MOI.ScalarAffineTerm(2.0, x))], + MOI.VectorQuadraticTerm{Float64}[], + [1.0], + ) +end + +function test_functions_convert_ScalarQuadraticFunction() + model = MOI.Utilities.Model{Float64}() + x = MOI.add_variable(model) + f = MOI.ScalarQuadraticFunction( + [MOI.ScalarAffineTerm(2.0, x)], + [MOI.ScalarQuadraticTerm(3.0, x, x)], + 1.0, + ) + @test_throws(MethodError, convert(MOI.VectorOfVariables, f)) + @test_throws(MethodError, convert(MOI.VectorAffineFunction{Float64}, f)) + f_vqf = convert(MOI.VectorQuadraticFunction{Float64}, f) + @test f_vqf ≈ MOI.VectorQuadraticFunction( + [MOI.VectorAffineTerm(1, MOI.ScalarAffineTerm(2.0, x))], + MOI.VectorQuadraticTerm{Float64}[MOI.VectorQuadraticTerm( + 1, + MOI.ScalarQuadraticTerm(3.0, x, x), + )], + [1.0], + ) +end + +function test_isapprox_SingleVariable() + x = MOI.VariableIndex(1) + y = MOI.VariableIndex(2) + @test MOI.SingleVariable(x) == MOI.SingleVariable(x) + @test MOI.SingleVariable(x) != MOI.SingleVariable(y) +end + +function test_isapprox_VectorOfVariables() + x = MOI.VariableIndex(1) + y = MOI.VariableIndex(2) + @test MOI.VectorOfVariables([x, y]) == MOI.VectorOfVariables([x, y]) + @test MOI.VectorOfVariables([y, x]) != MOI.VectorOfVariables([x, y]) + @test MOI.VectorOfVariables([x, x]) != MOI.VectorOfVariables([x]) + @test MOI.VectorOfVariables([x]) != MOI.VectorOfVariables([y]) +end + +function test_isapprox_ScalarAffineFunction() + x = MOI.VariableIndex(1) + y = MOI.VariableIndex(2) + z = MOI.VariableIndex(3) + @test MOI.ScalarAffineFunction( + MOI.ScalarAffineTerm.([1, 1], [x, z]), + 1, + ) ≈ MOI.ScalarAffineFunction( + MOI.ScalarAffineTerm.([1.0, 1e-7, 1.0], [x, y, z]), + 1.0, + ) atol = 1e-6 + @test MOI.ScalarAffineFunction( + MOI.ScalarAffineTerm.([1.0, 1e-7], [x, y]), + 1.0, + ) ≈ MOI.ScalarAffineFunction([MOI.ScalarAffineTerm(1, x)], 1) atol = + 1e-6 + f = MOI.ScalarAffineFunction( + MOI.ScalarAffineTerm.([2, 4], [x, y]), + 6, + ) + g = deepcopy(f) + @test g ≈ f + f.terms[2] = MOI.ScalarAffineTerm(3, y) + @test !(g ≈ f) +end + +function test_isapprox_VectorAffineFunction() + x = MOI.VariableIndex(1) + y = MOI.VariableIndex(2) + f = MOI.VectorAffineFunction( + MOI.VectorAffineTerm.( + [1, 1, 2], + MOI.ScalarAffineTerm.([2, 4, 3], [x, y, y]), + ), + [6, 8], + ) + g = deepcopy(f) + @test f ≈ g + f.terms[3] = MOI.VectorAffineTerm(2, MOI.ScalarAffineTerm(9, y)) + @test !(f ≈ g) + push!(f.terms, MOI.VectorAffineTerm(2, MOI.ScalarAffineTerm(-6, y))) + @test f ≈ g +end + +function test_isapprox_ScalarQuadraticFunction() + x = MOI.VariableIndex(1) + y = MOI.VariableIndex(2) + z = MOI.VariableIndex(3) + f = MOI.ScalarQuadraticFunction( + [MOI.ScalarAffineTerm(3, x)], + MOI.ScalarQuadraticTerm.([1, 2, 3], [x, y, x], [x, y, y]), + 8, + ) + g = deepcopy(f) + @test f ≈ g + push!(f.affine_terms, MOI.ScalarAffineTerm(2, y)) + @test !(f ≈ g) + g = deepcopy(f) + push!(f.quadratic_terms, MOI.ScalarQuadraticTerm(2, y, x)) + @test !(f ≈ g) + push!(f.quadratic_terms, MOI.ScalarQuadraticTerm(-2, y, x)) + @test f ≈ g +end + +function test_isapprox_VectorQuadraticFunction() + x = MOI.VariableIndex(1) + y = MOI.VariableIndex(2) + z = MOI.VariableIndex(3) + f = MOI.VectorQuadraticFunction( + MOI.VectorAffineTerm.( + [1, 2, 1], + MOI.ScalarAffineTerm.([3, 1, 1], [x, x, y]), + ), + MOI.VectorQuadraticTerm.( + [1, 1, 2], + MOI.ScalarQuadraticTerm.([1, 2, 3], [x, y, x], [x, y, y]), + ), + [10, 11, 12], + ) + g = deepcopy(f) + @test f ≈ g + f.affine_terms[1] = + MOI.VectorAffineTerm(3, MOI.ScalarAffineTerm(4, x)) + @test !(f ≈ g) + push!( + g.affine_terms, + MOI.VectorAffineTerm(1, MOI.ScalarAffineTerm(-3, x)), + ) + push!( + g.affine_terms, + MOI.VectorAffineTerm(3, MOI.ScalarAffineTerm(4, x)), + ) + @test f ≈ g + f.quadratic_terms[1] = + MOI.VectorQuadraticTerm(3, MOI.ScalarQuadraticTerm(1, x, x)) + @test !(f ≈ g) +end + +function runtests() + for name in names(@__MODULE__; all = true) + if startswith("$name", "test_") + @testset "$(name)" begin + getfield(@__MODULE__, name)() + end end end end -@testset "Base.convert" begin - @testset "SingleVariable" begin - model = MOI.Utilities.Model{Float64}() - x = MOI.add_variable(model) - f = MOI.SingleVariable(x) - f_vov = convert(MOI.VectorOfVariables, f) - @test f_vov ≈ MOI.VectorOfVariables([x]) - f_vaf = convert(MOI.VectorAffineFunction{Float64}, f) - @test f_vaf ≈ MOI.VectorAffineFunction( - [MOI.VectorAffineTerm(1, MOI.ScalarAffineTerm(1.0, x))], - [0.0], - ) - f_vqf = convert(MOI.VectorQuadraticFunction{Float64}, f) - @test f_vqf ≈ MOI.VectorQuadraticFunction( - [MOI.VectorAffineTerm(1, MOI.ScalarAffineTerm(1.0, x))], - MOI.VectorQuadraticTerm{Float64}[], - [0.0], - ) - end - @testset "ScalarAffineFunction" begin - model = MOI.Utilities.Model{Float64}() - x = MOI.add_variable(model) - f = MOI.ScalarAffineFunction([MOI.ScalarAffineTerm(2.0, x)], 1.0) - @test_throws(MethodError, convert(MOI.VectorOfVariables, f)) - f_vaf = convert(MOI.VectorAffineFunction{Float64}, f) - @test f_vaf ≈ MOI.VectorAffineFunction( - [MOI.VectorAffineTerm(1, MOI.ScalarAffineTerm(2.0, x))], - [1.0], - ) - f_vqf = convert(MOI.VectorQuadraticFunction{Float64}, f) - @test f_vqf ≈ MOI.VectorQuadraticFunction( - [MOI.VectorAffineTerm(1, MOI.ScalarAffineTerm(2.0, x))], - MOI.VectorQuadraticTerm{Float64}[], - [1.0], - ) - end - @testset "ScalarQuadraticFunction" begin - model = MOI.Utilities.Model{Float64}() - x = MOI.add_variable(model) - f = MOI.ScalarQuadraticFunction( - [MOI.ScalarAffineTerm(2.0, x)], - [MOI.ScalarQuadraticTerm(3.0, x, x)], - 1.0, - ) - @test_throws(MethodError, convert(MOI.VectorOfVariables, f)) - @test_throws(MethodError, convert(MOI.VectorAffineFunction{Float64}, f)) - f_vqf = convert(MOI.VectorQuadraticFunction{Float64}, f) - @test f_vqf ≈ MOI.VectorQuadraticFunction( - [MOI.VectorAffineTerm(1, MOI.ScalarAffineTerm(2.0, x))], - MOI.VectorQuadraticTerm{Float64}[MOI.VectorQuadraticTerm( - 1, - MOI.ScalarQuadraticTerm(3.0, x, x), - )], - [1.0], - ) - end end + +TestFunctions.runtests() diff --git a/test/instantiate.jl b/test/instantiate.jl index 1d3c0d0cbb..11a5131787 100644 --- a/test/instantiate.jl +++ b/test/instantiate.jl @@ -1,19 +1,21 @@ -using Test +module TestInstantiate +using Test using MathOptInterface const MOI = MathOptInterface -const MOIU = MathOptInterface.Utilities struct DummyOptimizer <: MOI.AbstractOptimizer end MOI.is_empty(::DummyOptimizer) = true -@testset "Instantiate with $T" for T in [Float64, Int] - f() = MOIU.MockOptimizer(MOIU.UniversalFallback(MOIU.Model{T}())) +function _test_instantiate(T) + f() = MOI.Utilities.MockOptimizer( + MOI.Utilities.UniversalFallback(MOI.Utilities.Model{T}()), + ) optimizer_constructor = MOI.OptimizerWithAttributes(f, MOI.Silent() => true, "a" => 1, "b" => 2) optimizer = MOI.instantiate(optimizer_constructor) @test optimizer isa - MOIU.MockOptimizer{MOIU.UniversalFallback{MOIU.Model{T}}} + MOI.Utilities.MockOptimizer{MOI.Utilities.UniversalFallback{MOI.Utilities.Model{T}}} @test MOI.get(optimizer, MOI.Silent()) for with_names in [true, false] optimizer = MOI.instantiate( @@ -22,7 +24,7 @@ MOI.is_empty(::DummyOptimizer) = true with_names = with_names, ) @test optimizer isa MOI.Bridges.LazyBridgeOptimizer{ - MOIU.MockOptimizer{MOIU.UniversalFallback{MOIU.Model{T}}}, + MOI.Utilities.MockOptimizer{MOI.Utilities.UniversalFallback{MOI.Utilities.Model{T}}}, } @test MOI.get(optimizer, MOI.Silent()) @test MOI.get(optimizer, MOI.RawParameter("a")) == 1 @@ -39,9 +41,9 @@ MOI.is_empty(::DummyOptimizer) = true with_names = with_names, ) @test optimizer isa MOI.Bridges.LazyBridgeOptimizer{ - MOIU.CachingOptimizer{ + MOI.Utilities.CachingOptimizer{ DummyOptimizer, - MOIU.UniversalFallback{MOIU.Model{T}}, + MOI.Utilities.UniversalFallback{MOI.Utilities.Model{T}}, }, } end @@ -83,3 +85,27 @@ MOI.is_empty(::DummyOptimizer) = true with_bridge_type = T, ) end + +function test_instantiate_Float64() + _test_instantiate(Float64) + return +end + +function test_instantiate_Int() + _test_instantiate(Int) + return +end + +function runtests() + for name in names(@__MODULE__; all = true) + if startswith("$name", "test_") + @testset "$(name)" begin + getfield(@__MODULE__, name)() + end + end + end +end + +end + +TestInstantiate.runtests() diff --git a/test/interval.jl b/test/interval.jl deleted file mode 100644 index 3f65203b3b..0000000000 --- a/test/interval.jl +++ /dev/null @@ -1,19 +0,0 @@ -@testset "Interval" begin - @test MOI.Interval(MOI.GreaterThan(1.0)) === MOI.Interval(1.0, Inf) - @test MOI.Interval(MOI.LessThan(2.0)) === MOI.Interval(-Inf, 2.0) - @test MOI.Interval(MOI.EqualTo(3.0)) === MOI.Interval(3.0, 3.0) - - @test MOI.Interval(MOI.GreaterThan(1.0f0)) === MOI.Interval(1.0f0, Inf32) - @test MOI.Interval(MOI.LessThan(2.0f0)) === MOI.Interval(-Inf32, 2.0f0) - @test MOI.Interval(MOI.EqualTo(3.0f0)) === MOI.Interval(3.0f0, 3.0f0) - - @test_throws MethodError MOI.Interval(MOI.GreaterThan(false)) - @test_throws MethodError MOI.Interval(MOI.LessThan(true)) - @test MOI.Interval(MOI.EqualTo(true)) === MOI.Interval(true, true) - - @test_throws MethodError MOI.Interval(MOI.GreaterThan(1)) - @test_throws MethodError MOI.Interval(MOI.LessThan(2)) - @test MOI.Interval(MOI.EqualTo(3)) === MOI.Interval(3, 3) - - @test MOI.Interval(MOI.Interval(1, 2)) == MOI.Interval(1, 2) -end diff --git a/test/isapprox.jl b/test/isapprox.jl deleted file mode 100644 index b1e5e17f3f..0000000000 --- a/test/isapprox.jl +++ /dev/null @@ -1,104 +0,0 @@ -@testset "Functions isapprox" begin - x = MOI.VariableIndex(1) - y = MOI.VariableIndex(2) - z = MOI.VariableIndex(3) - @testset "Variable" begin - @testset "Single" begin - @test MOI.SingleVariable(x) == MOI.SingleVariable(x) - @test MOI.SingleVariable(x) != MOI.SingleVariable(y) - end - @testset "Vector" begin - @test MOI.VectorOfVariables([x, y]) == MOI.VectorOfVariables([x, y]) - @test MOI.VectorOfVariables([y, x]) != MOI.VectorOfVariables([x, y]) - @test MOI.VectorOfVariables([x, x]) != MOI.VectorOfVariables([x]) - @test MOI.VectorOfVariables([x]) != MOI.VectorOfVariables([y]) - end - end - @testset "Affine" begin - @testset "Scalar" begin - @test MOI.ScalarAffineFunction( - MOI.ScalarAffineTerm.([1, 1], [x, z]), - 1, - ) ≈ MOI.ScalarAffineFunction( - MOI.ScalarAffineTerm.([1.0, 1e-7, 1.0], [x, y, z]), - 1.0, - ) atol = 1e-6 - @test MOI.ScalarAffineFunction( - MOI.ScalarAffineTerm.([1.0, 1e-7], [x, y]), - 1.0, - ) ≈ MOI.ScalarAffineFunction([MOI.ScalarAffineTerm(1, x)], 1) atol = - 1e-6 - f = MOI.ScalarAffineFunction( - MOI.ScalarAffineTerm.([2, 4], [x, y]), - 6, - ) - g = deepcopy(f) - @test g ≈ f - f.terms[2] = MOI.ScalarAffineTerm(3, y) - @test !(g ≈ f) - end - @testset "Vector" begin - f = MOI.VectorAffineFunction( - MOI.VectorAffineTerm.( - [1, 1, 2], - MOI.ScalarAffineTerm.([2, 4, 3], [x, y, y]), - ), - [6, 8], - ) - g = deepcopy(f) - @test f ≈ g - f.terms[3] = MOI.VectorAffineTerm(2, MOI.ScalarAffineTerm(9, y)) - @test !(f ≈ g) - push!(f.terms, MOI.VectorAffineTerm(2, MOI.ScalarAffineTerm(-6, y))) - @test f ≈ g - end - end - @testset "Quadratic" begin - @testset "Affine" begin - f = MOI.ScalarQuadraticFunction( - [MOI.ScalarAffineTerm(3, x)], - MOI.ScalarQuadraticTerm.([1, 2, 3], [x, y, x], [x, y, y]), - 8, - ) - g = deepcopy(f) - @test f ≈ g - push!(f.affine_terms, MOI.ScalarAffineTerm(2, y)) - @test !(f ≈ g) - g = deepcopy(f) - push!(f.quadratic_terms, MOI.ScalarQuadraticTerm(2, y, x)) - @test !(f ≈ g) - push!(f.quadratic_terms, MOI.ScalarQuadraticTerm(-2, y, x)) - @test f ≈ g - end - @testset "Vector" begin - f = MOI.VectorQuadraticFunction( - MOI.VectorAffineTerm.( - [1, 2, 1], - MOI.ScalarAffineTerm.([3, 1, 1], [x, x, y]), - ), - MOI.VectorQuadraticTerm.( - [1, 1, 2], - MOI.ScalarQuadraticTerm.([1, 2, 3], [x, y, x], [x, y, y]), - ), - [10, 11, 12], - ) - g = deepcopy(f) - @test f ≈ g - f.affine_terms[1] = - MOI.VectorAffineTerm(3, MOI.ScalarAffineTerm(4, x)) - @test !(f ≈ g) - push!( - g.affine_terms, - MOI.VectorAffineTerm(1, MOI.ScalarAffineTerm(-3, x)), - ) - push!( - g.affine_terms, - MOI.VectorAffineTerm(3, MOI.ScalarAffineTerm(4, x)), - ) - @test f ≈ g - f.quadratic_terms[1] = - MOI.VectorQuadraticTerm(3, MOI.ScalarQuadraticTerm(1, x, x)) - @test !(f ≈ g) - end - end -end diff --git a/test/isbits.jl b/test/isbits.jl deleted file mode 100644 index 7da19ac34b..0000000000 --- a/test/isbits.jl +++ /dev/null @@ -1,14 +0,0 @@ -# Test isbit-ness of VariableIndex and terms. -# It is important that these struct remain isbits as otherwise, -# the performance of function will be deteriored. -# These tests explicit this design choice and makes sure that it remains the case. -@testset "isbits" begin - x = @inferred MOI.VariableIndex(1) - @test isbits(x) - at = @inferred MOI.ScalarAffineTerm(1.0, x) - @test isbits(at) - @test isbits(@inferred MOI.VectorAffineTerm(1, at)) - qt = @inferred MOI.ScalarQuadraticTerm(1.0, x, x) - @test isbits(qt) - @test isbits(@inferred MOI.VectorQuadraticTerm(1, qt)) -end diff --git a/test/runtests.jl b/test/runtests.jl index 0eb42c20b1..d0aba68a0b 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -1,33 +1,19 @@ -using MathOptInterface -const MOI = MathOptInterface -const MOIT = MathOptInterface.Test -const MOIU = MathOptInterface.Utilities -const MOIB = MathOptInterface.Bridges - using Test -# It needs to be called first to trigger the crash. +# This file gets called first. It it doesn't crash, all is well. include("issue980.jl") -# Tests for solvers are located in MOI.Test. - -include("dummy.jl") - -# MOI tests not relying on any submodule -@testset "MOI" begin - include("isbits.jl") - include("isapprox.jl") - include("interval.jl") - include("errors.jl") - include("functions.jl") - include("sets.jl") - include("attributes.jl") - include("constraints.jl") - include("instantiate.jl") - include("deprecate.jl") +for file in readdir(@__DIR__) + if file in ["issue980.jl", "dummy.jl", "hygiene.jl", "runtests.jl"] + continue + elseif !endswith(file, ".jl") + continue + end + @testset "$(file)" begin + include(file) + end end -# Utilities submodule tests @testset "MOI.$(submodule)" for submodule in [ "Bridges", "FileFormats", diff --git a/test/sets.jl b/test/sets.jl index 796efef3ea..36a54e04e1 100644 --- a/test/sets.jl +++ b/test/sets.jl @@ -1,5 +1,6 @@ -using Test +module TestSets +using Test using MathOptInterface const MOI = MathOptInterface @@ -17,195 +18,271 @@ end Base.copy(mlt::MutLessThan) = MutLessThan(Base.copy(mlt.upper)) -@testset "Sets" begin - @testset "==" begin - # By default, `==` redirects to `===`, it works for bits type - # but not for `BigInt`s. We define functions creating different - # instances so that `a() !== a()`. - a() = big(1) - b() = big(2) - @test a() !== a() - @test b() !== b() - for S in [ - MOI.LessThan, - MOI.GreaterThan, - MOI.EqualTo, - MOI.PowerCone, - MOI.DualPowerCone, - ] - @test S(a()) == S(a()) - @test S(a()) != S(b()) - @test S(b()) == S(b()) - @test S(b()) != S(a()) - end - for S in [MOI.Interval, MOI.Semicontinuous, MOI.Semiinteger] - @test S(a(), b()) == S(a(), b()) - @test S(a(), b()) != S(b(), a()) - @test S(a(), b()) != S(b(), b()) - @test S(a(), b()) != S(a(), a()) - @test S(a(), a()) != S(b(), b()) - @test S(a(), a()) == S(a(), a()) - end - S = MOI.IndicatorSet - A() = MOI.LessThan(a()) - B() = MOI.LessThan(b()) - @test S{MOI.ACTIVATE_ON_ZERO}(A()) == S{MOI.ACTIVATE_ON_ZERO}(A()) - @test S{MOI.ACTIVATE_ON_ZERO}(A()) != S{MOI.ACTIVATE_ON_ONE}(A()) - @test S{MOI.ACTIVATE_ON_ZERO}(A()) != S{MOI.ACTIVATE_ON_ZERO}(B()) - @test S{MOI.ACTIVATE_ON_ONE}(A()) != S{MOI.ACTIVATE_ON_ONE}(B()) +function test_sets_equals() + # By default, `==` redirects to `===`, it works for bits type + # but not for `BigInt`s. We define functions creating different + # instances so that `a() !== a()`. + a() = big(1) + b() = big(2) + @test a() !== a() + @test b() !== b() + for S in [ + MOI.LessThan, + MOI.GreaterThan, + MOI.EqualTo, + MOI.PowerCone, + MOI.DualPowerCone, + ] + @test S(a()) == S(a()) + @test S(a()) != S(b()) + @test S(b()) == S(b()) + @test S(b()) != S(a()) end - @testset "Copy" begin - @testset "for $S" for S in [MOI.SOS1, MOI.SOS2] - s = S([1.0]) - s_copy = copy(s) - s_copy.weights[1] = 2.0 - @test s.weights[1] == 1.0 - end - @testset "IndicatorSet" begin - s1 = MOI.IndicatorSet{MOI.ACTIVATE_ON_ONE}(MOI.LessThan(4.0)) - s2 = MOI.IndicatorSet{MOI.ACTIVATE_ON_ZERO}(MOI.GreaterThan(4.0)) - s1_copy = copy(s1) - s2_copy = copy(s2) - @test s1_copy isa MOI.IndicatorSet{MOI.ACTIVATE_ON_ONE} - @test s1 == s1_copy - @test s2_copy isa MOI.IndicatorSet{MOI.ACTIVATE_ON_ZERO} - @test s2 == s2_copy - s3 = MOI.IndicatorSet{MOI.ACTIVATE_ON_ZERO}(MutLessThan(4.0)) - s3_copy = copy(s3) - @test s3.set.upper ≈ 4.0 - s3_copy.set.upper = 5.0 - @test s3.set.upper ≈ 4.0 - @test s3_copy.set.upper ≈ 5.0 - end - end - @testset "Broadcast" begin - model = DummyModelWithAdd() - x = MOI.add_variables(model, 3) - cis = MOI.add_constraint.(model, x, MOI.EqualTo(0.0)) - @test cis isa Vector{ - MOI.ConstraintIndex{MOI.SingleVariable,MOI.EqualTo{Float64}}, - } - @test length(cis) == 3 + for S in [MOI.Interval, MOI.Semicontinuous, MOI.Semiinteger] + @test S(a(), b()) == S(a(), b()) + @test S(a(), b()) != S(b(), a()) + @test S(a(), b()) != S(b(), b()) + @test S(a(), b()) != S(a(), a()) + @test S(a(), a()) != S(b(), b()) + @test S(a(), a()) == S(a(), a()) end + S = MOI.IndicatorSet + A() = MOI.LessThan(a()) + B() = MOI.LessThan(b()) + @test S{MOI.ACTIVATE_ON_ZERO}(A()) == S{MOI.ACTIVATE_ON_ZERO}(A()) + @test S{MOI.ACTIVATE_ON_ZERO}(A()) != S{MOI.ACTIVATE_ON_ONE}(A()) + @test S{MOI.ACTIVATE_ON_ZERO}(A()) != S{MOI.ACTIVATE_ON_ZERO}(B()) + @test S{MOI.ACTIVATE_ON_ONE}(A()) != S{MOI.ACTIVATE_ON_ONE}(B()) +end - @testset "dimension" begin - @test MOI.dimension(MOI.ExponentialCone()) == 3 - @test MOI.dimension(MOI.DualExponentialCone()) == 3 - @test MOI.dimension(MOI.PowerCone(1 / 2)) == 3 - @test MOI.dimension(MOI.DualPowerCone(1 / 2)) == 3 - @test MOI.dimension(MOI.PositiveSemidefiniteConeTriangle(5)) == 15 - @test MOI.dimension(MOI.PositiveSemidefiniteConeSquare(5)) == 25 - @test MOI.dimension(MOI.LogDetConeTriangle(5)) == 17 - @test MOI.dimension(MOI.LogDetConeSquare(5)) == 27 - @test MOI.dimension(MOI.RootDetConeTriangle(5)) == 16 - @test MOI.dimension(MOI.RootDetConeSquare(5)) == 26 - @test MOI.dimension(MOI.SOS1([1.0, 2.0])) == 2 - @test MOI.dimension(MOI.SOS2([1.0, 2.0])) == 2 - @test MOI.dimension( - MOI.IndicatorSet{MOI.ACTIVATE_ON_ONE}(MOI.LessThan(1.0)), - ) == 2 - @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 - @test MOI.dual_set_type(typeof(set1)) == typeof(set2) - @test MOI.dual_set(set2) == set1 - @test MOI.dual_set_type(typeof(set2)) == typeof(set1) - end - function self_dual_set_test(set) - @test MOI.dual_set(set) == set - @test MOI.dual_set_type(typeof(set)) == typeof(set) +function test_sets_sos1_copy() + s = MOI.SOS1([1.0]) + s_copy = copy(s) + s_copy.weights[1] = 2.0 + @test s.weights[1] == 1.0 +end + +function test_sets_sos2_copy() + s = MOI.SOS2([1.0]) + s_copy = copy(s) + s_copy.weights[1] = 2.0 + @test s.weights[1] == 1.0 +end + +function test_sets_indicator_copy() + s1 = MOI.IndicatorSet{MOI.ACTIVATE_ON_ONE}(MOI.LessThan(4.0)) + s2 = MOI.IndicatorSet{MOI.ACTIVATE_ON_ZERO}(MOI.GreaterThan(4.0)) + s1_copy = copy(s1) + s2_copy = copy(s2) + @test s1_copy isa MOI.IndicatorSet{MOI.ACTIVATE_ON_ONE} + @test s1 == s1_copy + @test s2_copy isa MOI.IndicatorSet{MOI.ACTIVATE_ON_ZERO} + @test s2 == s2_copy + s3 = MOI.IndicatorSet{MOI.ACTIVATE_ON_ZERO}(MutLessThan(4.0)) + s3_copy = copy(s3) + @test s3.set.upper ≈ 4.0 + s3_copy.set.upper = 5.0 + @test s3.set.upper ≈ 4.0 + @test s3_copy.set.upper ≈ 5.0 +end + +function test_sets_broadcast() + model = DummyModelWithAdd() + x = MOI.add_variables(model, 3) + cis = MOI.add_constraint.(model, x, MOI.EqualTo(0.0)) + @test cis isa Vector{ + MOI.ConstraintIndex{MOI.SingleVariable,MOI.EqualTo{Float64}}, + } + @test length(cis) == 3 +end + +function test_sets_dimension() + @test MOI.dimension(MOI.ExponentialCone()) == 3 + @test MOI.dimension(MOI.DualExponentialCone()) == 3 + @test MOI.dimension(MOI.PowerCone(1 / 2)) == 3 + @test MOI.dimension(MOI.DualPowerCone(1 / 2)) == 3 + @test MOI.dimension(MOI.PositiveSemidefiniteConeTriangle(5)) == 15 + @test MOI.dimension(MOI.PositiveSemidefiniteConeSquare(5)) == 25 + @test MOI.dimension(MOI.LogDetConeTriangle(5)) == 17 + @test MOI.dimension(MOI.LogDetConeSquare(5)) == 27 + @test MOI.dimension(MOI.RootDetConeTriangle(5)) == 16 + @test MOI.dimension(MOI.RootDetConeSquare(5)) == 26 + @test MOI.dimension(MOI.SOS1([1.0, 2.0])) == 2 + @test MOI.dimension(MOI.SOS2([1.0, 2.0])) == 2 + @test MOI.dimension( + MOI.IndicatorSet{MOI.ACTIVATE_ON_ONE}(MOI.LessThan(1.0)), + ) == 2 + @test MOI.dimension(MOI.Complements(10)) == 10 +end + +function test_sets_complement() + @test_throws ArgumentError MOI.Complements(3) +end + + +function _dual_set_test(set1, set2) + @test MOI.dual_set(set1) == set2 + @test MOI.dual_set_type(typeof(set1)) == typeof(set2) + @test MOI.dual_set(set2) == set1 + @test MOI.dual_set_type(typeof(set2)) == typeof(set1) +end + +function _self_dual_set_test(set) + @test MOI.dual_set(set) == set + @test MOI.dual_set_type(typeof(set)) == typeof(set) +end + +function test_sets_dual_nonpositives() + nonpositives3 = MOI.Nonpositives(3) + nonpositives4 = MOI.Nonpositives(4) + _self_dual_set_test(nonpositives3) + @test MOI.dual_set(nonpositives3) != nonpositives4 + _self_dual_set_test(nonpositives4) + return +end + +function test_sets_dual_nonnegatives() + nonnegatives3 = MOI.Nonnegatives(3) + nonnegatives4 = MOI.Nonnegatives(4) + _self_dual_set_test(nonnegatives3) + @test MOI.dual_set(nonnegatives3) != nonnegatives4 + _self_dual_set_test(nonnegatives4) + return +end + +function test_sets_dual_zeroreal() + zeros3 = MOI.Zeros(3) + zeros4 = MOI.Zeros(4) + reals3 = MOI.Reals(3) + reals4 = MOI.Reals(4) + _dual_set_test(zeros3, reals3) + @test MOI.dual_set(reals3) != zeros4 + _dual_set_test(zeros4, reals4) + @test MOI.dual_set(zeros4) != reals3 + return +end + +function test_sets_dual_norm() + norminf2 = MOI.NormInfinityCone(2) + norminf3 = MOI.NormInfinityCone(3) + normone2 = MOI.NormOneCone(2) + normone3 = MOI.NormOneCone(3) + _dual_set_test(norminf2, normone2) + _dual_set_test(norminf3, normone3) + @test MOI.dual_set(norminf2) != normone3 + @test MOI.dual_set(normone2) != norminf3 + return +end + +function test_sets_dual_soc() + soc2 = MOI.SecondOrderCone(2) + soc3 = MOI.SecondOrderCone(3) + _self_dual_set_test(soc2) + @test MOI.dual_set(soc2) != soc3 + _self_dual_set_test(soc3) + return +end + +function test_sets_dual_rsoc() + rsoc2 = MOI.RotatedSecondOrderCone(2) + rsoc3 = MOI.RotatedSecondOrderCone(3) + _self_dual_set_test(rsoc2) + @test MOI.dual_set(rsoc2) != rsoc3 + _self_dual_set_test(rsoc3) + return +end + +function test_sets_dual_normspectral() + normspec22 = MOI.NormSpectralCone(2, 2) + normspec23 = MOI.NormSpectralCone(2, 3) + normnuc22 = MOI.NormNuclearCone(2, 2) + normnuc23 = MOI.NormNuclearCone(2, 3) + _dual_set_test(normspec23, normnuc23) + _dual_set_test(normspec22, normnuc22) + @test MOI.dual_set(normspec22) != normnuc23 + @test MOI.dual_set(normnuc22) != normspec23 + return +end + +function test_sets_dual_psdtriangle() + psd2 = MOI.PositiveSemidefiniteConeTriangle(2) + psd3 = MOI.PositiveSemidefiniteConeTriangle(3) + _self_dual_set_test(psd2) + @test MOI.dual_set(psd2) != psd3 + _self_dual_set_test(psd3) + return +end + +function test_sets_dual_exponential() + exp = MOI.ExponentialCone() + dual_exp = MOI.DualExponentialCone() + _dual_set_test(exp, dual_exp) + @test MOI.dual_set(exp) != exp + _dual_set_test(dual_exp, exp) + @test MOI.dual_set(dual_exp) != dual_exp + return +end + +function test_sets_dual_power() + pow03 = MOI.PowerCone(0.3) + pow04 = MOI.PowerCone(0.4) + dual_pow03 = MOI.DualPowerCone(0.3) + _dual_set_test(pow03, dual_pow03) + @test MOI.dual_set(pow03) != pow03 + _dual_set_test(dual_pow03, pow03) + @test MOI.dual_set(dual_pow03) != pow04 + @test MOI.dual_set(dual_pow03) != dual_pow03 + return +end + +function test_sets_dual_psdsquare() + s = MOI.PositiveSemidefiniteConeSquare(4) + err = ErrorException( + """Dual of `PositiveSemidefiniteConeSquare` is not defined in MathOptInterface. + For more details see the comments in `src/Bridges/Constraint/square.jl`.""", + ) + @test_throws err MOI.dual_set(MOI.PositiveSemidefiniteConeSquare(4)) + @test_throws err MOI.dual_set_type(MOI.PositiveSemidefiniteConeSquare) +end + +function test_sets_dual_nonimplemented() + s = MOI.LogDetConeTriangle(4) + err = ErrorException("Dual of $s is not implemented.") + @test_throws err MOI.dual_set(MOI.LogDetConeTriangle(4)) + err = ErrorException("Dual type of $(typeof(s)) is not implemented.") + @test_throws err MOI.dual_set_type(MOI.LogDetConeTriangle) +end + +function test_sets_Interval() + @test MOI.Interval(MOI.GreaterThan(1.0)) === MOI.Interval(1.0, Inf) + @test MOI.Interval(MOI.LessThan(2.0)) === MOI.Interval(-Inf, 2.0) + @test MOI.Interval(MOI.EqualTo(3.0)) === MOI.Interval(3.0, 3.0) + + @test MOI.Interval(MOI.GreaterThan(1.0f0)) === MOI.Interval(1.0f0, Inf32) + @test MOI.Interval(MOI.LessThan(2.0f0)) === MOI.Interval(-Inf32, 2.0f0) + @test MOI.Interval(MOI.EqualTo(3.0f0)) === MOI.Interval(3.0f0, 3.0f0) + + @test_throws MethodError MOI.Interval(MOI.GreaterThan(false)) + @test_throws MethodError MOI.Interval(MOI.LessThan(true)) + @test MOI.Interval(MOI.EqualTo(true)) === MOI.Interval(true, true) + + @test_throws MethodError MOI.Interval(MOI.GreaterThan(1)) + @test_throws MethodError MOI.Interval(MOI.LessThan(2)) + @test MOI.Interval(MOI.EqualTo(3)) === MOI.Interval(3, 3) + + @test MOI.Interval(MOI.Interval(1, 2)) == MOI.Interval(1, 2) +end + +function runtests() + for name in names(@__MODULE__; all = true) + if startswith("$name", "test_") + @testset "$(name)" begin + getfield(@__MODULE__, name)() + end end - # Nonpositives - nonpositives3 = MOI.Nonpositives(3) - nonpositives4 = MOI.Nonpositives(4) - self_dual_set_test(nonpositives3) - @test MOI.dual_set(nonpositives3) != nonpositives4 - self_dual_set_test(nonpositives4) - # Nonnegatives - nonnegatives3 = MOI.Nonnegatives(3) - nonnegatives4 = MOI.Nonnegatives(4) - self_dual_set_test(nonnegatives3) - @test MOI.dual_set(nonnegatives3) != nonnegatives4 - self_dual_set_test(nonnegatives4) - # Zeros and Reals - zeros3 = MOI.Zeros(3) - zeros4 = MOI.Zeros(4) - reals3 = MOI.Reals(3) - reals4 = MOI.Reals(4) - dual_set_test(zeros3, reals3) - @test MOI.dual_set(reals3) != zeros4 - dual_set_test(zeros4, reals4) - @test MOI.dual_set(zeros4) != reals3 - # Norm-1 and norm-∞ cones - norminf2 = MOI.NormInfinityCone(2) - norminf3 = MOI.NormInfinityCone(3) - normone2 = MOI.NormOneCone(2) - normone3 = MOI.NormOneCone(3) - dual_set_test(norminf2, normone2) - dual_set_test(norminf3, normone3) - @test MOI.dual_set(norminf2) != normone3 - @test MOI.dual_set(normone2) != norminf3 - # SOC - soc2 = MOI.SecondOrderCone(2) - soc3 = MOI.SecondOrderCone(3) - self_dual_set_test(soc2) - @test MOI.dual_set(soc2) != soc3 - self_dual_set_test(soc3) - # RSOC - rsoc2 = MOI.RotatedSecondOrderCone(2) - rsoc3 = MOI.RotatedSecondOrderCone(3) - self_dual_set_test(rsoc2) - @test MOI.dual_set(rsoc2) != rsoc3 - self_dual_set_test(rsoc3) - # Norm-spectral and norm-nuclear cones - normspec22 = MOI.NormSpectralCone(2, 2) - normspec23 = MOI.NormSpectralCone(2, 3) - normnuc22 = MOI.NormNuclearCone(2, 2) - normnuc23 = MOI.NormNuclearCone(2, 3) - dual_set_test(normspec23, normnuc23) - dual_set_test(normspec22, normnuc22) - @test MOI.dual_set(normspec22) != normnuc23 - @test MOI.dual_set(normnuc22) != normspec23 - # PSDtriangle - psd2 = MOI.PositiveSemidefiniteConeTriangle(2) - psd3 = MOI.PositiveSemidefiniteConeTriangle(3) - self_dual_set_test(psd2) - @test MOI.dual_set(psd2) != psd3 - self_dual_set_test(psd3) - # Exponential - exp = MOI.ExponentialCone() - dual_exp = MOI.DualExponentialCone() - dual_set_test(exp, dual_exp) - @test MOI.dual_set(exp) != exp - dual_set_test(dual_exp, exp) - @test MOI.dual_set(dual_exp) != dual_exp - # Power - pow03 = MOI.PowerCone(0.3) - pow04 = MOI.PowerCone(0.4) - dual_pow03 = MOI.DualPowerCone(0.3) - dual_set_test(pow03, dual_pow03) - @test MOI.dual_set(pow03) != pow03 - dual_set_test(dual_pow03, pow03) - @test MOI.dual_set(dual_pow03) != pow04 - @test MOI.dual_set(dual_pow03) != dual_pow03 - # PSDSquare error - s = MOI.PositiveSemidefiniteConeSquare(4) - err = ErrorException( - """Dual of `PositiveSemidefiniteConeSquare` is not defined in MathOptInterface. - For more details see the comments in `src/Bridges/Constraint/square.jl`.""", - ) - @test_throws err MOI.dual_set(MOI.PositiveSemidefiniteConeSquare(4)) - @test_throws err MOI.dual_set_type(MOI.PositiveSemidefiniteConeSquare) - # Not implemented - s = MOI.LogDetConeTriangle(4) - err = ErrorException("Dual of $s is not implemented.") - @test_throws err MOI.dual_set(MOI.LogDetConeTriangle(4)) - err = ErrorException("Dual type of $(typeof(s)) is not implemented.") - @test_throws err MOI.dual_set_type(MOI.LogDetConeTriangle) end end + +end + +TestSets.runtests() From c8e5fba38783ce54e6beb68ea1e1958691be65fa Mon Sep 17 00:00:00 2001 From: odow Date: Thu, 13 May 2021 12:37:36 +1200 Subject: [PATCH 2/2] Fix formatting --- test/errors.jl | 89 +++++++++++++++++++++------------------------ test/functions.jl | 27 ++++---------- test/instantiate.jl | 17 ++++++--- test/sets.jl | 6 +-- 4 files changed, 61 insertions(+), 78 deletions(-) diff --git a/test/errors.jl b/test/errors.jl index 2b31133dc3..eda32a23a9 100644 --- a/test/errors.jl +++ b/test/errors.jl @@ -13,11 +13,11 @@ function test_errors_fallback_AddVariableNotAllowed() MOI.add_variable(model) catch err @test sprint(showerror, err) == - "MathOptInterface.AddVariableNotAllowed:" * - " Adding variables cannot be performed. You may want to use a" * - " `CachingOptimizer` in `AUTOMATIC` mode or you may need to call" * - " `reset_optimizer` before doing this operation if the" * - " `CachingOptimizer` is in `MANUAL` mode." + "MathOptInterface.AddVariableNotAllowed:" * + " Adding variables cannot be performed. You may want to use a" * + " `CachingOptimizer` in `AUTOMATIC` mode or you may need to call" * + " `reset_optimizer` before doing this operation if the" * + " `CachingOptimizer` is in `MANUAL` mode." end @test_throws MOI.AddVariableNotAllowed MOI.add_variables(model, 2) return @@ -46,17 +46,14 @@ function _test_errors_UnsupportedConstraint(f) model = DummyModel() vi = MOI.VariableIndex(1) func = MOI.SingleVariable(vi) - @test_throws( - MOI.UnsupportedConstraint, - f(model, func, MOI.EqualTo(0)), - ) + @test_throws(MOI.UnsupportedConstraint, f(model, func, MOI.EqualTo(0)),) try f(model, func, MOI.EqualTo(0)) catch err @test sprint(showerror, err) == - "$(MOI.UnsupportedConstraint{MOI.SingleVariable,MOI.EqualTo{Int}}):" * - " `$MOI.SingleVariable`-in-`$MOI.EqualTo{$Int}` constraint is" * - " not supported by the model." + "$(MOI.UnsupportedConstraint{MOI.SingleVariable,MOI.EqualTo{Int}}):" * + " `$MOI.SingleVariable`-in-`$MOI.EqualTo{$Int}` constraint is" * + " not supported by the model." end return end @@ -85,11 +82,7 @@ function test_errors_UnsupportedConstraint_shortcut() MOI.add_constraint(model, [vi, vi], MOI.Nonnegatives(2)) end @test_throws MOI.UnsupportedConstraint begin - MOI.add_constraints( - model, - [vi, vi], - [MOI.EqualTo(0), MOI.EqualTo(0)], - ) + MOI.add_constraints(model, [vi, vi], [MOI.EqualTo(0), MOI.EqualTo(0)]) end end @@ -105,12 +98,12 @@ function test_errors_add_constraint() MOI.add_constraint(model, func, MOI.EqualTo(0.0)) catch err @test sprint(showerror, err) == - "$(MOI.AddConstraintNotAllowed{MOI.SingleVariable,MOI.EqualTo{Float64}}):" * - " Adding `$MOI.SingleVariable`-in-`$MOI.EqualTo{Float64}`" * - " constraints cannot be performed. You may want to use a" * - " `CachingOptimizer` in `AUTOMATIC` mode or you may need to call" * - " `reset_optimizer` before doing this operation if the" * - " `CachingOptimizer` is in `MANUAL` mode." + "$(MOI.AddConstraintNotAllowed{MOI.SingleVariable,MOI.EqualTo{Float64}}):" * + " Adding `$MOI.SingleVariable`-in-`$MOI.EqualTo{Float64}`" * + " constraints cannot be performed. You may want to use a" * + " `CachingOptimizer` in `AUTOMATIC` mode or you may need to call" * + " `reset_optimizer` before doing this operation if the" * + " `CachingOptimizer` is in `MANUAL` mode." end @test_throws( MOI.AddConstraintNotAllowed, @@ -174,24 +167,24 @@ function test_errors_DeleteNotAllowed() MOI.delete(model, vi) catch err @test sprint(showerror, err) == - "MathOptInterface.DeleteNotAllowed{MathOptInterface.VariableIndex}:" * - " Deleting the index MathOptInterface.VariableIndex(1) cannot be" * - " performed. You may want to use a `CachingOptimizer` in" * - " `AUTOMATIC` mode or you may need to call `reset_optimizer`" * - " before doing this operation if the `CachingOptimizer` is in" * - " `MANUAL` mode." + "MathOptInterface.DeleteNotAllowed{MathOptInterface.VariableIndex}:" * + " Deleting the index MathOptInterface.VariableIndex(1) cannot be" * + " performed. You may want to use a `CachingOptimizer` in" * + " `AUTOMATIC` mode or you may need to call `reset_optimizer`" * + " before doing this operation if the `CachingOptimizer` is in" * + " `MANUAL` mode." end @test_throws MOI.DeleteNotAllowed{typeof(ci)} MOI.delete(model, ci) try MOI.delete(model, ci) catch err @test sprint(showerror, err) == - "$(MathOptInterface.DeleteNotAllowed{MathOptInterface.ConstraintIndex{MathOptInterface.SingleVariable,MathOptInterface.EqualTo{Float64}}}):" * - " Deleting the index $(MathOptInterface.ConstraintIndex{MathOptInterface.SingleVariable,MathOptInterface.EqualTo{Float64}}(1))" * - " cannot be performed. You may want to use a `CachingOptimizer`" * - " in `AUTOMATIC` mode or you may need to call `reset_optimizer`" * - " before doing this operation if the `CachingOptimizer` is in" * - " `MANUAL` mode." + "$(MathOptInterface.DeleteNotAllowed{MathOptInterface.ConstraintIndex{MathOptInterface.SingleVariable,MathOptInterface.EqualTo{Float64}}}):" * + " Deleting the index $(MathOptInterface.ConstraintIndex{MathOptInterface.SingleVariable,MathOptInterface.EqualTo{Float64}}(1))" * + " cannot be performed. You may want to use a `CachingOptimizer`" * + " in `AUTOMATIC` mode or you may need to call `reset_optimizer`" * + " before doing this operation if the `CachingOptimizer` is in" * + " `MANUAL` mode." end return end @@ -331,13 +324,13 @@ function test_errors_ModifyNotAllowed_constraint() err = MOI.ModifyConstraintNotAllowed(ci, change) @test_throws err MOI.modify(model, ci, change) @test sprint(showerror, err) == - "$(MathOptInterface.ModifyConstraintNotAllowed{MathOptInterface.SingleVariable,MathOptInterface.EqualTo{Float64},MathOptInterface.ScalarConstantChange{Float64}}):" * - " Modifying the constraints $(MathOptInterface.ConstraintIndex{MathOptInterface.SingleVariable,MathOptInterface.EqualTo{Float64}}(1))" * - " with MathOptInterface.ScalarConstantChange{Float64}(1.0) cannot" * - " be performed. You may want to use a `CachingOptimizer` in" * - " `AUTOMATIC` mode or you may need to call `reset_optimizer`" * - " before doing this operation if the `CachingOptimizer` is in" * - " `MANUAL` mode." + "$(MathOptInterface.ModifyConstraintNotAllowed{MathOptInterface.SingleVariable,MathOptInterface.EqualTo{Float64},MathOptInterface.ScalarConstantChange{Float64}}):" * + " Modifying the constraints $(MathOptInterface.ConstraintIndex{MathOptInterface.SingleVariable,MathOptInterface.EqualTo{Float64}}(1))" * + " with MathOptInterface.ScalarConstantChange{Float64}(1.0) cannot" * + " be performed. You may want to use a `CachingOptimizer` in" * + " `AUTOMATIC` mode or you may need to call `reset_optimizer`" * + " before doing this operation if the `CachingOptimizer` is in" * + " `MANUAL` mode." end function test_errors_ModifyNotAllowed_objective() @@ -347,12 +340,12 @@ function test_errors_ModifyNotAllowed_objective() err = MOI.ModifyObjectiveNotAllowed(change) @test_throws err MOI.modify(model, attr, change) @test sprint(showerror, err) == - "$(MathOptInterface.ModifyObjectiveNotAllowed{MathOptInterface.ScalarConstantChange{Float64}}):" * - " Modifying the objective function with $(MathOptInterface.ScalarConstantChange{Float64}(1.0))" * - " cannot be performed. You may want to use a `CachingOptimizer`" * - " in `AUTOMATIC` mode or you may need to call `reset_optimizer`" * - " before doing this operation if the `CachingOptimizer` is in" * - " `MANUAL` mode." + "$(MathOptInterface.ModifyObjectiveNotAllowed{MathOptInterface.ScalarConstantChange{Float64}}):" * + " Modifying the objective function with $(MathOptInterface.ScalarConstantChange{Float64}(1.0))" * + " cannot be performed. You may want to use a `CachingOptimizer`" * + " in `AUTOMATIC` mode or you may need to call `reset_optimizer`" * + " before doing this operation if the `CachingOptimizer` is in" * + " `MANUAL` mode." end function test_errors_show_SetAttributeNotAllowed() diff --git a/test/functions.jl b/test/functions.jl index 239f830897..fbe5c46ccd 100644 --- a/test/functions.jl +++ b/test/functions.jl @@ -125,22 +125,16 @@ function test_isapprox_ScalarAffineFunction() x = MOI.VariableIndex(1) y = MOI.VariableIndex(2) z = MOI.VariableIndex(3) - @test MOI.ScalarAffineFunction( - MOI.ScalarAffineTerm.([1, 1], [x, z]), - 1, - ) ≈ MOI.ScalarAffineFunction( + @test MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.([1, 1], [x, z]), 1) ≈ + MOI.ScalarAffineFunction( MOI.ScalarAffineTerm.([1.0, 1e-7, 1.0], [x, y, z]), 1.0, ) atol = 1e-6 @test MOI.ScalarAffineFunction( MOI.ScalarAffineTerm.([1.0, 1e-7], [x, y]), 1.0, - ) ≈ MOI.ScalarAffineFunction([MOI.ScalarAffineTerm(1, x)], 1) atol = - 1e-6 - f = MOI.ScalarAffineFunction( - MOI.ScalarAffineTerm.([2, 4], [x, y]), - 6, - ) + ) ≈ MOI.ScalarAffineFunction([MOI.ScalarAffineTerm(1, x)], 1) atol = 1e-6 + f = MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.([2, 4], [x, y]), 6) g = deepcopy(f) @test g ≈ f f.terms[2] = MOI.ScalarAffineTerm(3, y) @@ -202,17 +196,10 @@ function test_isapprox_VectorQuadraticFunction() ) g = deepcopy(f) @test f ≈ g - f.affine_terms[1] = - MOI.VectorAffineTerm(3, MOI.ScalarAffineTerm(4, x)) + f.affine_terms[1] = MOI.VectorAffineTerm(3, MOI.ScalarAffineTerm(4, x)) @test !(f ≈ g) - push!( - g.affine_terms, - MOI.VectorAffineTerm(1, MOI.ScalarAffineTerm(-3, x)), - ) - push!( - g.affine_terms, - MOI.VectorAffineTerm(3, MOI.ScalarAffineTerm(4, x)), - ) + push!(g.affine_terms, MOI.VectorAffineTerm(1, MOI.ScalarAffineTerm(-3, x))) + push!(g.affine_terms, MOI.VectorAffineTerm(3, MOI.ScalarAffineTerm(4, x))) @test f ≈ g f.quadratic_terms[1] = MOI.VectorQuadraticTerm(3, MOI.ScalarQuadraticTerm(1, x, x)) diff --git a/test/instantiate.jl b/test/instantiate.jl index 11a5131787..6f4d4ccd42 100644 --- a/test/instantiate.jl +++ b/test/instantiate.jl @@ -8,14 +8,17 @@ struct DummyOptimizer <: MOI.AbstractOptimizer end MOI.is_empty(::DummyOptimizer) = true function _test_instantiate(T) - f() = MOI.Utilities.MockOptimizer( - MOI.Utilities.UniversalFallback(MOI.Utilities.Model{T}()), - ) + function f() + return MOI.Utilities.MockOptimizer( + MOI.Utilities.UniversalFallback(MOI.Utilities.Model{T}()), + ) + end optimizer_constructor = MOI.OptimizerWithAttributes(f, MOI.Silent() => true, "a" => 1, "b" => 2) optimizer = MOI.instantiate(optimizer_constructor) - @test optimizer isa - MOI.Utilities.MockOptimizer{MOI.Utilities.UniversalFallback{MOI.Utilities.Model{T}}} + @test optimizer isa MOI.Utilities.MockOptimizer{ + MOI.Utilities.UniversalFallback{MOI.Utilities.Model{T}}, + } @test MOI.get(optimizer, MOI.Silent()) for with_names in [true, false] optimizer = MOI.instantiate( @@ -24,7 +27,9 @@ function _test_instantiate(T) with_names = with_names, ) @test optimizer isa MOI.Bridges.LazyBridgeOptimizer{ - MOI.Utilities.MockOptimizer{MOI.Utilities.UniversalFallback{MOI.Utilities.Model{T}}}, + MOI.Utilities.MockOptimizer{ + MOI.Utilities.UniversalFallback{MOI.Utilities.Model{T}}, + }, } @test MOI.get(optimizer, MOI.Silent()) @test MOI.get(optimizer, MOI.RawParameter("a")) == 1 diff --git a/test/sets.jl b/test/sets.jl index 36a54e04e1..829ee99797 100644 --- a/test/sets.jl +++ b/test/sets.jl @@ -90,9 +90,8 @@ function test_sets_broadcast() model = DummyModelWithAdd() x = MOI.add_variables(model, 3) cis = MOI.add_constraint.(model, x, MOI.EqualTo(0.0)) - @test cis isa Vector{ - MOI.ConstraintIndex{MOI.SingleVariable,MOI.EqualTo{Float64}}, - } + @test cis isa + Vector{MOI.ConstraintIndex{MOI.SingleVariable,MOI.EqualTo{Float64}}} @test length(cis) == 3 end @@ -119,7 +118,6 @@ function test_sets_complement() @test_throws ArgumentError MOI.Complements(3) end - function _dual_set_test(set1, set2) @test MOI.dual_set(set1) == set2 @test MOI.dual_set_type(typeof(set1)) == typeof(set2)