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

Add tests, extend docstring for ScalarQuadraticFunction. #697

Merged
merged 8 commits into from
Apr 9, 2019
106 changes: 105 additions & 1 deletion src/Test/contquadratic.jl
Original file line number Diff line number Diff line change
Expand Up @@ -385,9 +385,113 @@ function qcp3test(model::MOI.ModelLike, config::TestConfig)
end
end

function qcp4test(model::MOI.ModelLike, config::TestConfig)
atol = config.atol
rtol = config.rtol
# Max 2x + y
# s.t. x*y <= 4 (c)
rschwarz marked this conversation as resolved.
Show resolved Hide resolved
# x, y >= 1

@test MOIU.supports_default_copy_to(model, #=copy_names=# false)
@test MOI.supports(model, MOI.ObjectiveFunction{MOI.ScalarAffineFunction{Float64}}())
@test MOI.supports_constraint(model, MOI.ScalarQuadraticFunction{Float64}, MOI.LessThan{Float64})

MOI.empty!(model)
@test MOI.is_empty(model)

x = MOI.add_variable(model)
y = MOI.add_variable(model)
@test MOI.get(model, MOI.NumberOfVariables()) == 2

MOI.add_constraint(model, MOI.SingleVariable(x), MOI.GreaterThan(1.0))
MOI.add_constraint(model, MOI.SingleVariable(y), MOI.GreaterThan(1.0))

cf = MOI.ScalarQuadraticFunction([MOI.ScalarAffineTerm(0.0, x)], [MOI.ScalarQuadraticTerm(1.0, x, y)], 0.0)
c = MOI.add_constraint(model, cf, MOI.LessThan(4.0))
@test MOI.get(model, MOI.NumberOfConstraints{MOI.ScalarQuadraticFunction{Float64}, MOI.LessThan{Float64}}()) == 1

MOI.set(model, MOI.ObjectiveFunction{MOI.ScalarAffineFunction{Float64}}(), MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.([2.0, 1.0], [x, y]), 0.0))
MOI.set(model, MOI.ObjectiveSense(), MOI.MAX_SENSE)
@test MOI.get(model, MOI.ObjectiveSense()) == MOI.MAX_SENSE

if config.query
@test cf ≈ MOI.get(model, MOI.ConstraintFunction(), c)
end

if config.solve
@test MOI.get(model, MOI.TerminationStatus()) == MOI.OPTIMIZE_NOT_CALLED

MOI.optimize!(model)

@test MOI.get(model, MOI.TerminationStatus()) == config.optimal_status

@test MOI.get(model, MOI.PrimalStatus()) == MOI.FEASIBLE_POINT

@test MOI.get(model, MOI.ObjectiveValue()) ≈ 9.0 atol=atol rtol=rtol

@test MOI.get(model, MOI.VariablePrimal(), x) ≈ 4.0 atol=atol rtol=rtol
@test MOI.get(model, MOI.VariablePrimal(), y) ≈ 1.0 atol=atol rtol=rtol

@test MOI.get(model, MOI.ConstraintPrimal(), c) ≈ 4.0 atol=atol rtol=rtol
end
end

function qcp5test(model::MOI.ModelLike, config::TestConfig)
atol = config.atol
rtol = config.rtol
# Find x,y
# s.t. x*y == 4 (c)
# x*x == 4 (c2)
rschwarz marked this conversation as resolved.
Show resolved Hide resolved
# x, y >= 0

@test MOIU.supports_default_copy_to(model, #=copy_names=# false)
@test MOI.supports_constraint(model, MOI.ScalarQuadraticFunction{Float64}, MOI.EqualTo{Float64})

MOI.empty!(model)
@test MOI.is_empty(model)

x = MOI.add_variable(model)
y = MOI.add_variable(model)
@test MOI.get(model, MOI.NumberOfVariables()) == 2

MOI.add_constraint(model, MOI.SingleVariable(x), MOI.GreaterThan(0.0))
MOI.add_constraint(model, MOI.SingleVariable(y), MOI.GreaterThan(0.0))

cf = MOI.ScalarQuadraticFunction([MOI.ScalarAffineTerm(0.0, x)], [MOI.ScalarQuadraticTerm(1.0, x, y)], 0.0)
c = MOI.add_constraint(model, cf, MOI.EqualTo(4.0))

cf2 = MOI.ScalarQuadraticFunction([MOI.ScalarAffineTerm(0.0, x)], [MOI.ScalarQuadraticTerm(2.0, x, x)], 0.0)
c2 = MOI.add_constraint(model, cf2, MOI.EqualTo(4.0))

@test MOI.get(model, MOI.NumberOfConstraints{MOI.ScalarQuadraticFunction{Float64}, MOI.EqualTo{Float64}}()) == 2

if config.query
@test cf ≈ MOI.get(model, MOI.ConstraintFunction(), c)
@test cf2 ≈ MOI.get(model, MOI.ConstraintFunction(), c2)
end

if config.solve
@test MOI.get(model, MOI.TerminationStatus()) == MOI.OPTIMIZE_NOT_CALLED

MOI.optimize!(model)

@test MOI.get(model, MOI.TerminationStatus()) == config.optimal_status

@test MOI.get(model, MOI.PrimalStatus()) == MOI.FEASIBLE_POINT

@test MOI.get(model, MOI.VariablePrimal(), x) ≈ 2.0 atol=atol rtol=rtol
@test MOI.get(model, MOI.VariablePrimal(), y) ≈ 2.0 atol=atol rtol=rtol

@test MOI.get(model, MOI.ConstraintPrimal(), c) ≈ 4.0 atol=atol rtol=rtol
@test MOI.get(model, MOI.ConstraintPrimal(), c2) ≈ 4.0 atol=atol rtol=rtol
end
end

const qcptests = Dict("qcp1" => qcp1test,
"qcp2" => qcp2test,
"qcp3" => qcp3test)
"qcp3" => qcp3test,
"qcp4" => qcp4test,
"qcp5" => qcp5test)

@moitestset qcp

Expand Down
4 changes: 4 additions & 0 deletions src/functions.jl
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,10 @@ Duplicate indices in ``a`` or ``Q`` are accepted, and the corresponding
coefficients are summed together. "Mirrored" indices `(q,r)` and `(r,q)` (where
`r` and `q` are `VariableIndex`es) are considered duplicates; only one need be
specified.

For example, for two scalar variables ``y, z``, the quadratic expression
``yz + y^2`` is represented by the terms
`ScalarQuadraticTerm.([1.0, 2.0], [y, y], [z, y])`.
"""
mutable struct ScalarQuadraticFunction{T} <: AbstractScalarFunction
affine_terms::Vector{ScalarAffineTerm{T}}
Expand Down
6 changes: 6 additions & 0 deletions test/Test/contquadratic.jl
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,12 @@
MOIU.set_mock_optimize!(mock,
(mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [√2], MOI.FEASIBLE_POINT))
MOIT.qcp3test(mock, config)
MOIU.set_mock_optimize!(mock,
(mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [4.0, 1.0], MOI.FEASIBLE_POINT))
MOIT.qcp4test(mock, config)
MOIU.set_mock_optimize!(mock,
(mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [2.0, 2.0], MOI.FEASIBLE_POINT))
MOIT.qcp5test(mock, config)
end
@testset "SOCP" begin
MOIU.set_mock_optimize!(mock,
Expand Down