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
118 changes: 99 additions & 19 deletions src/Test/contconic.jl
Original file line number Diff line number Diff line change
Expand Up @@ -114,20 +114,27 @@ function _lin2test(model::MOI.ModelLike, config::TestConfig, vecofvars::Bool)
MOI.empty!(model)
@test MOI.is_empty(model)

x,y,z,s = MOI.add_variables(model, 4)
x = MOI.add_variable(model)
@test MOI.get(model, MOI.NumberOfVariables()) == 1

if vecofvars
ys, vc = MOI.add_constrained_variables(model, MOI.Nonpositives(1))
y = ys[1]
else
y = MOI.add_variable(model)
func = MOI.VectorAffineFunction{Float64}(MOI.VectorOfVariables([y]))
vc = MOI.add_constraint(model, func, MOI.Nonpositives(1))
end
@test MOI.get(model, MOI.NumberOfVariables()) == 2

z, s = MOI.add_variables(model, 2)
@test MOI.get(model, MOI.NumberOfVariables()) == 4

MOI.set(model, MOI.ObjectiveFunction{MOI.ScalarAffineFunction{Float64}}(), MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.([3.0, 2.0, -4.0], [x,y,z]), 0.0))
MOI.set(model, MOI.ObjectiveSense(), MOI.MIN_SENSE)

c = MOI.add_constraint(model, MOI.VectorAffineFunction(MOI.VectorAffineTerm.([1,1,2,3,3], MOI.ScalarAffineTerm.([1.0,-1.0,1.0,1.0,1.0], [x,s,y,x,z])), [4.0,3.0,-12.0]), MOI.Zeros(3))

vov = MOI.VectorOfVariables([y])
if vecofvars
vc = MOI.add_constraint(model, vov, MOI.Nonpositives(1))
else
vc = MOI.add_constraint(model, MOI.VectorAffineFunction{Float64}(vov), MOI.Nonpositives(1))
end
if vecofvars
# test fallback
vz = MOI.add_constraint(model, [z], MOI.Nonnegatives(1))
Expand Down Expand Up @@ -256,10 +263,10 @@ function lin4test(model::MOI.ModelLike, config::TestConfig)
MOI.empty!(model)
@test MOI.is_empty(model)

x = MOI.add_variable(model)
xs, cx = MOI.add_constrained_variables(model, MOI.Nonpositives(1))
x = xs[1]

MOI.add_constraint(model, MOI.VectorAffineFunction([MOI.VectorAffineTerm(1, MOI.ScalarAffineTerm(1.0, x))], [-1.0]), MOI.Nonnegatives(1))
MOI.add_constraint(model, MOI.VectorOfVariables([x]), MOI.Nonpositives(1))

@test MOI.get(model, MOI.NumberOfConstraints{MOI.VectorAffineFunction{Float64},MOI.Nonnegatives}()) == 1
@test MOI.get(model, MOI.NumberOfConstraints{MOI.VectorOfVariables,MOI.Nonpositives}()) == 1
Expand Down Expand Up @@ -603,18 +610,18 @@ function _rotatedsoc1test(model::MOI.ModelLike, config::TestConfig, abvars::Bool
MOI.empty!(model)
@test MOI.is_empty(model)

x = MOI.add_variables(model, 2)
if abvars
a = MOI.add_variable(model)
b = MOI.add_variable(model)
abx, rsoc = MOI.add_constrained_variables(model, MOI.RotatedSecondOrderCone(4))
a, b, x1, x2 = abx
x = [x1, x2]
vc1 = MOI.add_constraint(model, MOI.SingleVariable(a), MOI.EqualTo(0.5))
# We test this after the creation of every `SingleVariable` constraint
# to ensure a good coverage of corner cases.
@test vc1.value == a.value
vc2 = MOI.add_constraint(model, MOI.SingleVariable(b), MOI.EqualTo(1.0))
@test vc2.value == b.value
rsoc = MOI.add_constraint(model, MOI.VectorOfVariables([a; b; x]), MOI.RotatedSecondOrderCone(4))
else
x = MOI.add_variables(model, 2)
a = 0.5
b = 1.0
rsoc = MOI.add_constraint(model, MOI.VectorAffineFunction(MOI.VectorAffineTerm.([3, 4], MOI.ScalarAffineTerm.([1., 1.], x)), [a, b, 0., 0.]), MOI.RotatedSecondOrderCone(4))
Expand Down Expand Up @@ -702,7 +709,7 @@ function rotatedsoc2test(model::MOI.ModelLike, config::TestConfig)
MOI.empty!(model)
@test MOI.is_empty(model)

x = MOI.add_variables(model, 3)
x, rsoc = MOI.add_constrained_variables(model, MOI.RotatedSecondOrderCone(3))

vc1 = MOI.add_constraint(model, MOI.SingleVariable(x[1]), MOI.LessThan(1.0))
@test vc1.value == x[1].value
Expand All @@ -711,8 +718,6 @@ function rotatedsoc2test(model::MOI.ModelLike, config::TestConfig)
vc3 = MOI.add_constraint(model, MOI.SingleVariable(x[3]), MOI.GreaterThan(2.0))
@test vc3.value == x[3].value

rsoc = MOI.add_constraint(model, MOI.VectorOfVariables(x), MOI.RotatedSecondOrderCone(3))

@test MOI.get(model, MOI.NumberOfConstraints{MOI.SingleVariable,MOI.LessThan{Float64}}()) == 1
@test MOI.get(model, MOI.NumberOfConstraints{MOI.SingleVariable,MOI.EqualTo{Float64}}()) == 1
@test MOI.get(model, MOI.NumberOfConstraints{MOI.SingleVariable,MOI.GreaterThan{Float64}}()) == 1
Expand Down Expand Up @@ -775,7 +780,7 @@ function rotatedsoc3test(model::MOI.ModelLike, config::TestConfig; n=2, ub=3.0)
MOI.empty!(model)
@test MOI.is_empty(model)

x = MOI.add_variables(model, n)
x, cx = MOI.add_constrained_variables(model, MOI.Nonnegatives(n))
u = MOI.add_variable(model)
v = MOI.add_variable(model)
t = MOI.add_variables(model, 2)
Expand All @@ -784,7 +789,6 @@ function rotatedsoc3test(model::MOI.ModelLike, config::TestConfig; n=2, ub=3.0)
@test ct1.value == t[1].value
ct2 = MOI.add_constraint(model, MOI.SingleVariable(t[2]), MOI.EqualTo(1.0))
@test ct2.value == t[2].value
cx = MOI.add_constraint(model, MOI.VectorOfVariables(x), MOI.Nonnegatives(n))
cu1 = MOI.add_constraint(model, MOI.SingleVariable(u), MOI.GreaterThan(0.0))
@test cu1.value == u.value
cu2 = MOI.add_constraint(model, MOI.SingleVariable(u), MOI.LessThan(ub))
Expand Down Expand Up @@ -847,11 +851,87 @@ function rotatedsoc3test(model::MOI.ModelLike, config::TestConfig; n=2, ub=3.0)
end
end

function rotatedsoc4test(model::MOI.ModelLike, config::TestConfig; n=2, ub=3.0)
atol = config.atol
rtol = config.rtol
# Problem SOCRotated4
# max x + y
# s.t.
# t + u ≤ 2 (1)
# [t, u, x, y] in RSOC(4) (2)
# Solution:
# By AM-QM: (x+y)/2 ≤ √((x^2+y^2)/2) with equality iff x = y
# That is,
# (x + y)^2/2 ≤ x^2 + y^2 (3)
# By AM-GM: √tu ≤ (t+u)/2 with equality iff t = u
# That is,
# 2tu ≤ (t + u)^2/2 (4)
# Combining (2), (3) and (4), we have
# |x + y| ≤ t + u (5)
# with equality iff x = y and t = u.
# Combining (1) and (5), we have
# x + y ≤ 2
# with equality iff x = y.
# We conclude that the optimal solution is x = y = t = u = 1
# with objective value 2.

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

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

v, cv = MOI.add_constrained_variables(model, MOI.RotatedSecondOrderCone(4))
t, u, x, y = v
ft = MOI.SingleVariable(t)
fu = MOI.SingleVariable(u)
c = MOI.add_constraint(model, 1.0ft + 1.0fu, MOI.LessThan(2.0))
fx = MOI.SingleVariable(x)
fy = MOI.SingleVariable(y)
func = 1.0fx + 1.0fy
MOI.set(model, MOI.ObjectiveSense(), MOI.MAX_SENSE)
MOI.set(model, MOI.ObjectiveFunction{typeof(func)}(), func)

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
if config.duals
@test MOI.get(model, MOI.DualStatus()) == MOI.FEASIBLE_POINT
end

@test MOI.get(model, MOI.ObjectiveValue()) ≈ 2.0 atol=atol rtol=rtol
if config.duals
@test MOI.get(model, MOI.DualObjectiveValue()) ≈ 2.0 atol=atol rtol=rtol
end

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

@test MOI.get(model, MOI.ConstraintPrimal(), cv) ≈ ones(4) atol=atol rtol=rtol
@test MOI.get(model, MOI.ConstraintPrimal(), c) ≈ 2.0 atol=atol rtol=rtol

if config.duals
@test MOI.get(model, MOI.ConstraintDual(), cv) ≈ [1.0, 1.0, -1.0, -1.0] atol=atol rtol=rtol
@test MOI.get(model, MOI.ConstraintDual(), c) ≈ -1.0 atol=atol rtol=rtol
end
end
end

const rsoctests = Dict("rotatedsoc1v" => rotatedsoc1vtest,
"rotatedsoc1f" => rotatedsoc1ftest,
"rotatedsoc2" => rotatedsoc2test,
"rotatedsoc3" => rotatedsoc3test)
"rotatedsoc3" => rotatedsoc3test,
"rotatedsoc4" => rotatedsoc4test)

@moitestset rsoc

Expand Down
99 changes: 84 additions & 15 deletions src/Test/modellike.jl
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,21 @@ function nametest(model::MOI.ModelLike)
@test MOI.supports(model, MOI.VariableName(), MOI.VariableIndex)
v = MOI.add_variables(model, 2)
@test MOI.get(model, MOI.VariableName(), v[1]) == ""
x, cx = MOI.add_constrained_variable(model, MOI.GreaterThan(0.0))
@test MOI.get(model, MOI.VariableName(), x) == ""
@test MOI.get(model, MOI.ConstraintName(), cx) == ""
y, cy = MOI.add_constrained_variables(model, MOI.Nonpositives(4))
for yi in y
@test MOI.get(model, MOI.VariableName(), yi) == ""
end
@test MOI.get(model, MOI.ConstraintName(), cy) == ""

MOI.set(model, MOI.VariableName(), v[1], "")
MOI.set(model, MOI.VariableName(), v[2], "") # Shouldn't error with duplicate empty name
MOI.set(model, MOI.VariableName(), x, "")
for yi in y
MOI.set(model, MOI.VariableName(), yi, "")
end

MOI.set(model, MOI.VariableName(), v[1], "Var1")
MOI.set(model, MOI.VariableName(), v[2], "Var1")
Expand All @@ -52,30 +64,45 @@ function nametest(model::MOI.ModelLike)
@test MOI.get(model, MOI.VariableIndex, "Var2") == v[2]
@test MOI.get(model, MOI.VariableIndex, "Var3") === nothing

MOI.set(model, MOI.VariableName(), v, ["VarX","Var2"])
@test MOI.get(model, MOI.VariableName(), v) == ["VarX", "Var2"]
MOI.set(model, MOI.VariableName(), x, "Var1")
@test_throws Exception MOI.get(model, MOI.VariableIndex, "Var1")

MOI.set(model, MOI.VariableName(), x, "Varx")
@test MOI.get(model, MOI.VariableIndex, "Var1") == v[1]
@test MOI.get(model, MOI.VariableIndex, "Var2") == v[2]
@test MOI.get(model, MOI.VariableIndex, "Varx") == x
@test MOI.get(model, MOI.VariableIndex, "Var3") === nothing

vynames = ["VarX", "Var2", "Vary1", "Vary2", "Vary3", "Vary4"]
MOI.set(model, MOI.VariableName(), [v; y], vynames)
@test MOI.get(model, MOI.VariableName(), v) == vynames[1:2]
@test MOI.get(model, MOI.VariableName(), y) == vynames[3:6]
@test MOI.get(model, MOI.VariableName(), [v; y]) == vynames

@test MOI.supports_constraint(model, MOI.ScalarAffineFunction{Float64}, MOI.LessThan{Float64})
c = MOI.add_constraint(model, MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.([1.0,1.0], v), 0.0), MOI.LessThan(1.0))
@test MOI.supports_constraint(model, MOI.ScalarAffineFunction{Float64}, MOI.EqualTo{Float64})
c2 = MOI.add_constraint(model, MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.([-1.0,1.0], v), 0.0), MOI.EqualTo(0.0))
@test MOI.get(model, MOI.ConstraintName(), c) == ""
@test MOI.get(model, MOI.ConstraintName(), c2) == ""
@test MOI.get(model, MOI.ConstraintName(), cx) == ""
@test MOI.get(model, MOI.ConstraintName(), cy) == ""

@test MOI.supports(model, MOI.ConstraintName(), typeof(c))
MOI.set(model, MOI.ConstraintName(), c, "")
@test MOI.supports(model, MOI.ConstraintName(), typeof(c2))
MOI.set(model, MOI.ConstraintName(), c2, "") # Shouldn't error with duplicate empty name
@test MOI.supports(model, MOI.ConstraintName(), typeof(cx))
MOI.set(model, MOI.ConstraintName(), cx, "")
@test MOI.supports(model, MOI.ConstraintName(), typeof(cy))
MOI.set(model, MOI.ConstraintName(), cy, "")

MOI.set(model, MOI.ConstraintName(), c, "Con0")
@test MOI.get(model, MOI.ConstraintName(), c) == "Con0"
MOI.set(model, MOI.ConstraintName(), c2, "Con0")
# Lookup must fail when multiple constraints have the same name.
@test_throws Exception MOI.get(model, MOI.ConstraintIndex, "Con0")
@test_throws Exception MOI.get(model,
MOI.ConstraintIndex{
MOI.ScalarAffineFunction{Float64},
MOI.LessThan{Float64}},
"Con0")
@test_throws Exception MOI.get(model, typeof(c), "Con0")

MOI.set(model, MOI.ConstraintName(), [c], ["Con1"])
@test MOI.get(model, MOI.ConstraintName(), [c]) == ["Con1"]
Expand All @@ -87,21 +114,63 @@ function nametest(model::MOI.ModelLike)
@test MOI.get(model, MOI.ConstraintIndex, "Con1") == c
@test MOI.get(model, MOI.ConstraintIndex, "Con2") === nothing

MOI.set(model, MOI.ConstraintName(), c2, "Con0")
MOI.set(model, MOI.ConstraintName(), [c], ["Con1"])

@test MOI.get(model, MOI.ConstraintIndex{MOI.ScalarAffineFunction{Float64},MOI.LessThan{Float64}}, "Con0") === nothing
@test MOI.get(model, MOI.ConstraintIndex{MOI.ScalarAffineFunction{Float64},MOI.EqualTo{Float64}}, "Con1") === nothing
@test MOI.get(model, MOI.ConstraintIndex{MOI.ScalarAffineFunction{Float64},MOI.LessThan{Float64}}, "Con1") == c
@test MOI.get(model, MOI.ConstraintIndex{MOI.ScalarAffineFunction{Float64},MOI.EqualTo{Float64}}, "Con0") == c2
@test MOI.get(model, MOI.ConstraintIndex, "Con0") == c2
@test MOI.get(model, MOI.ConstraintIndex, "Con1") == c
MOI.set(model, MOI.ConstraintName(), [c2, cx], ["Con2", "Con2"])
@test_throws Exception MOI.get(model, MOI.ConstraintIndex, "Con2")
@test_throws Exception MOI.get(model, typeof(c2), "Con2")
@test_throws Exception MOI.get(model, typeof(cx), "Con2")

MOI.set(model, MOI.ConstraintName(), [cx, cy], ["Con3", "Con3"])
@test_throws Exception MOI.get(model, MOI.ConstraintIndex, "Con3")
@test_throws Exception MOI.get(model, typeof(cx), "Con3")
@test_throws Exception MOI.get(model, typeof(cy), "Con3")

MOI.set(model, MOI.ConstraintName(), cy, "Con4")

for (i, ca) in enumerate([c, c2, cx, cy])
namea = "Con$i"
@test MOI.get(model, MOI.ConstraintName(), ca) == namea
@test MOI.get(model, typeof(ca), namea) == ca
@test MOI.get(model, MOI.ConstraintIndex, namea) == ca
for cb in [c, c2, cx, cy]
if ca === cb
continue
end
nameb = MOI.get(model, MOI.ConstraintName(), cb)
@test MOI.get(model, typeof(cb), namea) == nothing
@test MOI.get(model, typeof(ca), nameb) == nothing
end
end

MOI.delete(model, v[2])
@test MOI.get(model, MOI.VariableIndex, "Var2") === nothing

MOI.delete(model, c)
@test MOI.get(model, MOI.ConstraintIndex{MOI.ScalarAffineFunction{Float64},MOI.LessThan{Float64}}, "Con1") === nothing
@test MOI.get(model, typeof(c), "Con1") === nothing
@test MOI.get(model, MOI.ConstraintIndex, "Con1") === nothing

MOI.set(model, MOI.ConstraintName(), cx, "Con2")
@test_throws Exception MOI.get(model, MOI.ConstraintIndex, "Con2")
@test_throws Exception MOI.get(model, typeof(c2), "Con2")
@test_throws Exception MOI.get(model, typeof(cx), "Con2")

MOI.delete(model, x)
@test MOI.get(model, MOI.VariableIndex, "Varx") === nothing
@test MOI.get(model, typeof(cx), "Con3") === nothing
@test MOI.get(model, MOI.ConstraintIndex, "Con3") === nothing
@test MOI.get(model, typeof(c2), "Con2") === c2
@test MOI.get(model, MOI.ConstraintIndex, "Con2") === c2

MOI.delete(model, y)
@test MOI.get(model, typeof(cy), "Con4") === nothing
@test MOI.get(model, MOI.ConstraintIndex, "Con4") === nothing
for i in 1:4
@test MOI.get(model, MOI.VariableIndex, "Vary$i") === nothing
end
MOI.set(model, MOI.ConstraintName(), c2, "Con4")
@test MOI.get(model, typeof(c2), "Con4") === c2
@test MOI.get(model, MOI.ConstraintIndex, "Con4") === c2
end
end

Expand Down
4 changes: 1 addition & 3 deletions test/Bridges/Constraint/flip_sign.jl
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,7 @@ const MOIB = MathOptInterface.Bridges

include("../utilities.jl")

include("../simple_model.jl")

mock = MOIU.MockOptimizer(SimpleModel{Float64}())
mock = MOIU.MockOptimizer(MOIU.Model{Float64}())
config = MOIT.TestConfig()

@testset "GreaterToLess" begin
Expand Down
4 changes: 1 addition & 3 deletions test/Bridges/Constraint/functionize.jl
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,7 @@ const MOIB = MathOptInterface.Bridges

include("../utilities.jl")

include("../simple_model.jl")

mock = MOIU.MockOptimizer(SimpleModel{Float64}())
mock = MOIU.MockOptimizer(MOIU.Model{Float64}())
config = MOIT.TestConfig()
config_with_basis = MOIT.TestConfig(basis = true)

Expand Down
12 changes: 8 additions & 4 deletions test/Bridges/Constraint/interval.jl
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,7 @@ const MOIB = MathOptInterface.Bridges

include("../utilities.jl")

include("../simple_model.jl")

mock = MOIU.MockOptimizer(SimpleModel{Float64}())
mock = MOIU.MockOptimizer(MOIU.Model{Float64}())
config = MOIT.TestConfig()
config_with_basis = MOIT.TestConfig(basis = true)

Expand Down Expand Up @@ -61,9 +59,15 @@ config_with_basis = MOIT.TestConfig(basis = true)
MOIT.linear10btest(bridged_mock, config_with_basis)

ci = first(MOI.get(bridged_mock, MOI.ListOfConstraintIndices{MOI.ScalarAffineFunction{Float64}, MOI.Interval{Float64}}()))
newf = MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.([1.0, -1.0], MOI.get(bridged_mock, MOI.ListOfVariableIndices())), 0.0)
vis = MOI.get(bridged_mock, MOI.ListOfVariableIndices())
newf = MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.([1.0, -1.0], vis), 0.0)
MOI.set(bridged_mock, MOI.ConstraintFunction(), ci, newf)
@test MOI.get(bridged_mock, MOI.ConstraintFunction(), ci) ≈ newf

MOI.modify(bridged_mock, ci, MOI.ScalarCoefficientChange(vis[2], 1.0))
modified_f = MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.(ones(2), vis), 0.0)
@test MOI.get(bridged_mock, MOI.ConstraintFunction(), ci) ≈ modified_f

test_delete_bridge(bridged_mock, ci, 2, ((MOI.ScalarAffineFunction{Float64}, MOI.GreaterThan{Float64}, 0),
(MOI.ScalarAffineFunction{Float64}, MOI.LessThan{Float64}, 0)))
end
Loading