diff --git a/src/affexpr.jl b/src/affexpr.jl index cfbe35e2c14..5fba6dfacfd 100644 --- a/src/affexpr.jl +++ b/src/affexpr.jl @@ -303,8 +303,6 @@ function Base.copy(a::GenericAffExpr, new_model::Model) return result end -# TODO GenericAffExprConstraint - struct AffExprConstraint{V <: AbstractVariableRef, S <: MOI.AbstractScalarSet} <: AbstractConstraint func::GenericAffExpr{Float64, V} set::S @@ -323,15 +321,18 @@ end moi_function_and_set(c::VectorAffExprConstraint) = (MOI.VectorAffineFunction(c.func), c.set) -function constraintobject(cr::ConstraintRef{Model}, ::Type{AffExpr}, ::Type{SetType}) where {SetType <: MOI.AbstractScalarSet} - f = MOI.get(cr.m, MOI.ConstraintFunction(), cr)::MOI.ScalarAffineFunction - s = MOI.get(cr.m, MOI.ConstraintSet(), cr)::SetType - return AffExprConstraint(AffExpr(cr.m, f), s) +function constraintobject(ref::ConstraintRef{Model, MOICON{FuncType, SetType}}) where + {FuncType <: MOI.ScalarAffineFunction, SetType <: MOI.AbstractScalarSet} + model = ref.m + f = MOI.get(model, MOI.ConstraintFunction(), ref)::FuncType + s = MOI.get(model, MOI.ConstraintSet(), ref)::SetType + return AffExprConstraint(AffExpr(model, f), s) end -function constraintobject(cr::ConstraintRef{Model}, ::Type{Vector{AffExpr}}, ::Type{SetType}) where {SetType <: MOI.AbstractVectorSet} - m = cr.m - f = MOI.get(m, MOI.ConstraintFunction(), cr)::MOI.VectorAffineFunction - s = MOI.get(m, MOI.ConstraintSet(), cr)::SetType - return VectorAffExprConstraint(map(f -> AffExpr(m, f), MOIU.eachscalar(f)), s) +function constraintobject(ref::ConstraintRef{Model, MOICON{FuncType, SetType}}) where + {FuncType <: MOI.VectorAffineFunction, SetType <: MOI.AbstractVectorSet} + model = ref.m + f = MOI.get(model, MOI.ConstraintFunction(), ref)::MOI.VectorAffineFunction + s = MOI.get(model, MOI.ConstraintSet(), ref)::SetType + return VectorAffExprConstraint(map(f -> AffExpr(model, f), MOIU.eachscalar(f)), s) end diff --git a/src/quadexpr.jl b/src/quadexpr.jl index b685a40f226..0370d268114 100644 --- a/src/quadexpr.jl +++ b/src/quadexpr.jl @@ -227,11 +227,12 @@ end moi_function_and_set(c::QuadExprConstraint) = (MOI.ScalarQuadraticFunction(c.func), c.set) -function constraintobject(cr::ConstraintRef{Model}, ::Type{QuadExpr}, ::Type{SetType}) where {SetType <: MOI.AbstractScalarSet} - m = cr.m - f = MOI.get(m.moibackend, MOI.ConstraintFunction(), index(cr))::MOI.ScalarQuadraticFunction - s = MOI.get(m.moibackend, MOI.ConstraintSet(), index(cr))::SetType - return QuadExprConstraint(QuadExpr(m, f), s) +function constraintobject(ref::ConstraintRef{Model, MOICON{FuncType, SetType}}) where + {FuncType <: MOI.ScalarQuadraticFunction, SetType <: MOI.AbstractScalarSet} + model = ref.m + f = MOI.get(model, MOI.ConstraintFunction(), ref)::FuncType + s = MOI.get(model, MOI.ConstraintSet(), ref)::SetType + return QuadExprConstraint(QuadExpr(model, f), s) end # TODO: VectorQuadExprConstraint diff --git a/src/variables.jl b/src/variables.jl index 683a420bb7d..f26b2a73aac 100644 --- a/src/variables.jl +++ b/src/variables.jl @@ -221,17 +221,20 @@ end moi_function_and_set(c::VectorOfVariablesConstraint) = (MOI.VectorOfVariables(c.func), c.set) -function constraintobject(cr::ConstraintRef{Model}, ::Type{VariableRef}, ::Type{SetType}) where {SetType <: MOI.AbstractScalarSet} - f = MOI.get(cr.m, MOI.ConstraintFunction(), cr)::MOI.SingleVariable - s = MOI.get(cr.m, MOI.ConstraintSet(), cr)::SetType - return SingleVariableConstraint(VariableRef(cr.m, f), s) -end - -function constraintobject(cr::ConstraintRef{Model}, ::Type{Vector{VariableRef}}, ::Type{SetType}) where {SetType <: MOI.AbstractVectorSet} - m = cr.m - f = MOI.get(m, MOI.ConstraintFunction(), cr)::MOI.VectorOfVariables - s = MOI.get(m, MOI.ConstraintSet(), cr)::SetType - return VectorOfVariablesConstraint(map(v -> VariableRef(m, v), f.variables), s) +function constraintobject(ref::ConstraintRef{Model, MOICON{FuncType, SetType}}) where + {FuncType <: MOI.SingleVariable, SetType <: MOI.AbstractScalarSet} + model = ref.m + f = MOI.get(model, MOI.ConstraintFunction(), ref)::FuncType + s = MOI.get(model, MOI.ConstraintSet(), ref)::SetType + return SingleVariableConstraint(VariableRef(model, f), s) +end + +function constraintobject(ref::ConstraintRef{Model, MOICON{FuncType, SetType}}) where + {FuncType <: MOI.VectorOfVariables, SetType <: MOI.AbstractVectorSet} + model = ref.m + f = MOI.get(model, MOI.ConstraintFunction(), ref)::FuncType + s = MOI.get(model, MOI.ConstraintSet(), ref)::SetType + return VectorOfVariablesConstraint(map(v -> VariableRef(model, v), f.variables), s) end diff --git a/test/JuMPExtension.jl b/test/JuMPExtension.jl index 27cba1654b8..690177d804e 100644 --- a/test/JuMPExtension.jl +++ b/test/JuMPExtension.jl @@ -114,13 +114,8 @@ function MOI.delete!(m::MyModel, cref::MyConstraintRef) delete!(m.connames, cref.idx) end MOI.isvalid(m::MyModel, cref::MyConstraintRef) = cref.idx in keys(m.constraints) -function JuMP.constraintobject(cref::MyConstraintRef, F::Type, S::Type) - c = cref.model.constraints[cref.idx] - # `TypeError` should be thrown is `F` and `S` are not correct - # This is needed for the tests in `constraints.jl` - c.func::F - c.set::S - c +function JuMP.constraintobject(cref::MyConstraintRef) + return cref.model.constraints[cref.idx] end # Objective diff --git a/test/constraint.jl b/test/constraint.jl index dc4bb367e76..582dc9756da 100644 --- a/test/constraint.jl +++ b/test/constraint.jl @@ -1,7 +1,4 @@ -function constraints_test(ModelType::Type{<:JuMP.AbstractModel}, VariableRefType::Type{<:JuMP.AbstractVariableRef}, ConstraintRefType::Type) - AffExprType = JuMP.GenericAffExpr{Float64, VariableRefType} - QuadExprType = JuMP.GenericQuadExpr{Float64, VariableRefType} - +function constraints_test(ModelType::Type{<:JuMP.AbstractModel}) @testset "SingleVariable constraints" begin m = ModelType() @variable(m, x) @@ -10,16 +7,14 @@ function constraints_test(ModelType::Type{<:JuMP.AbstractModel}, VariableRefType # the LHS is first subtracted to form x - 10.0 <= 0. @constraint(m, cref, x in MOI.LessThan(10.0)) @test JuMP.name(cref) == "cref" - c = JuMP.constraintobject(cref, VariableRefType, MOI.LessThan) + c = JuMP.constraintobject(cref) @test c.func == x @test c.set == MOI.LessThan(10.0) - @test_throws TypeError JuMP.constraintobject(cref, QuadExprType, MOI.LessThan) - @test_throws TypeError JuMP.constraintobject(cref, AffExprType, MOI.EqualTo) @variable(m, y[1:2]) @constraint(m, cref2[i=1:2], y[i] in MOI.LessThan(float(i))) @test JuMP.name(cref2[1]) == "cref2[1]" - c = JuMP.constraintobject(cref2[1], VariableRefType, MOI.LessThan) + c = JuMP.constraintobject(cref2[1]) @test c.func == y[1] @test c.set == MOI.LessThan(1.0) end @@ -29,19 +24,17 @@ function constraints_test(ModelType::Type{<:JuMP.AbstractModel}, VariableRefType @variable(m, x[1:2]) cref = @constraint(m, x in MOI.Zeros(2)) - c = JuMP.constraintobject(cref, Vector{VariableRefType}, MOI.Zeros) + c = JuMP.constraintobject(cref) @test c.func == x @test c.set == MOI.Zeros(2) - @test_throws TypeError JuMP.constraintobject(cref, Vector{AffExprType}, MOI.Nonnegatives) - @test_throws TypeError JuMP.constraintobject(cref, AffExprType, MOI.EqualTo) cref = @constraint(m, [x[2],x[1]] in MOI.Zeros(2)) - c = JuMP.constraintobject(cref, Vector{VariableRefType}, MOI.Zeros) + c = JuMP.constraintobject(cref) @test c.func == [x[2],x[1]] @test c.set == MOI.Zeros(2) end - @testset "AffExprType constraints" begin + @testset "AffExpr constraints" begin m = ModelType() @variable(m, x) @@ -50,26 +43,24 @@ function constraints_test(ModelType::Type{<:JuMP.AbstractModel}, VariableRefType JuMP.setname(cref, "c") @test JuMP.name(cref) == "c" - c = JuMP.constraintobject(cref, AffExprType, MOI.LessThan) + c = JuMP.constraintobject(cref) @test JuMP.isequal_canonical(c.func, 2x) @test c.set == MOI.LessThan(10.0) - @test_throws TypeError JuMP.constraintobject(cref, QuadExprType, MOI.LessThan) - @test_throws TypeError JuMP.constraintobject(cref, AffExprType, MOI.EqualTo) cref = @constraint(m, 3x + 1 ≥ 10) - c = JuMP.constraintobject(cref, AffExprType, MOI.GreaterThan) + c = JuMP.constraintobject(cref) @test JuMP.isequal_canonical(c.func, 3x) @test c.set == MOI.GreaterThan(9.0) cref = @constraint(m, 1 == -x) - c = JuMP.constraintobject(cref, AffExprType, MOI.EqualTo) + c = JuMP.constraintobject(cref) @test JuMP.isequal_canonical(c.func, 1.0x) @test c.set == MOI.EqualTo(-1.0) @test_throws ErrorException @constraint(m, [x, 2x] == [1-x, 3]) @test_macro_throws ErrorException @constraint(m, [x == 1-x, 2x == 3]) cref = @constraint(m, [x, 2x] .== [1-x, 3]) - c = JuMP.constraintobject.(cref, AffExprType, MOI.EqualTo) + c = JuMP.constraintobject.(cref) @test JuMP.isequal_canonical(c[1].func, 2.0x) @test c[1].set == MOI.EqualTo(1.0) @test JuMP.isequal_canonical(c[2].func, 2.0x) @@ -88,7 +79,7 @@ function constraints_test(ModelType::Type{<:JuMP.AbstractModel}, VariableRefType @constraint(m, cref, 1.0 <= x + y + 1.0 <= 2.0) @test JuMP.name(cref) == "cref" - c = JuMP.constraintobject(cref, AffExprType, MOI.Interval) + c = JuMP.constraintobject(cref) @test JuMP.isequal_canonical(c.func, x + y) @test c.set == MOI.Interval(0.0, 1.0) end @@ -103,10 +94,10 @@ function constraints_test(ModelType::Type{<:JuMP.AbstractModel}, VariableRefType cref = @constraint(m, A*x .== b) @test size(cref) == (2,) - c1 = JuMP.constraintobject(cref[1], AffExprType, MOI.EqualTo) + c1 = JuMP.constraintobject(cref[1]) @test JuMP.isequal_canonical(c1.func, x[1] + 2x[2]) @test c1.set == MOI.EqualTo(4.0) - c2 = JuMP.constraintobject(cref[2], AffExprType, MOI.EqualTo) + c2 = JuMP.constraintobject(cref[2]) @test JuMP.isequal_canonical(c2.func, 3x[1] + 4x[2]) @test c2.set == MOI.EqualTo(5.0) end @@ -121,8 +112,8 @@ function constraints_test(ModelType::Type{<:JuMP.AbstractModel}, VariableRefType @test size(cref) == (2,2) for i in 1:2 for j in 1:2 - c = JuMP.constraintobject(cref[i,j], AffExprType, MOI.LessThan) - @test JuMP.isequal_canonical(c.func, convert(AffExprType, x[i,j])) + c = JuMP.constraintobject(cref[i,j]) + @test JuMP.isequal_canonical(c.func, x[i,j] + 0) @test c.set == MOI.LessThan(UB[i,j] - 1) end end @@ -139,7 +130,7 @@ function constraints_test(ModelType::Type{<:JuMP.AbstractModel}, VariableRefType @test size(cref) == (2,) for i in 1:2 - c = JuMP.constraintobject(cref[i], AffExprType, MOI.Interval) + c = JuMP.constraintobject(cref[i]) @test JuMP.isequal_canonical(c.func, x[i] + y[i]) @test c.set == MOI.Interval(l[i]-1, u[i]-1) end @@ -149,6 +140,7 @@ function constraints_test(ModelType::Type{<:JuMP.AbstractModel}, VariableRefType m = ModelType() @variable m x[1:2] @constraint m cref1[i=2:4] x .== [i, i+1] + ConstraintRefType = eltype(cref1[2]) @test cref1 isa JuMP.JuMPArray{AbstractArray{ConstraintRefType}} @constraint m cref2[i=1:3, j=1:4] x .≤ [i+j, i-j] @test cref2 isa Matrix{AbstractArray{ConstraintRefType}} @@ -157,25 +149,24 @@ function constraints_test(ModelType::Type{<:JuMP.AbstractModel}, VariableRefType @test cref3 isa Vector{AbstractArray{ConstraintRefType}} end - @testset "QuadExprType constraints" begin + @testset "QuadExpr constraints" begin m = ModelType() @variable(m, x) @variable(m, y) cref = @constraint(m, x^2 + x <= 1) - c = JuMP.constraintobject(cref, QuadExprType, MOI.LessThan) + c = JuMP.constraintobject(cref) @test JuMP.isequal_canonical(c.func, x^2 + x) @test c.set == MOI.LessThan(1.0) cref = @constraint(m, y*x - 1.0 == 0.0) - c = JuMP.constraintobject(cref, QuadExprType, MOI.EqualTo) + c = JuMP.constraintobject(cref) @test JuMP.isequal_canonical(c.func, x*y) @test c.set == MOI.EqualTo(1.0) - @test_throws TypeError JuMP.constraintobject(cref, QuadExprType, MOI.LessThan) - @test_throws TypeError JuMP.constraintobject(cref, AffExprType, MOI.EqualTo) + # TODO: VectorQuadraticFunctions # cref = @constraint(m, [x^2 - 1] in MOI.SecondOrderCone(1)) - # c = JuMP.constraintobject(cref, QuadExprType, MOI.SecondOrderCone) + # c = JuMP.constraintobject(cref) # @test JuMP.isequal_canonical(c.func, -1 + x^2) # @test c.set == MOI.SecondOrderCone(1) end @@ -188,13 +179,13 @@ function constraints_test(ModelType::Type{<:JuMP.AbstractModel}, VariableRefType @variable(m, w) cref = @constraint(m, [x y; z w] in PSDCone()) - c = JuMP.constraintobject(cref, Vector{VariableRefType}, MOI.PositiveSemidefiniteConeSquare) + c = JuMP.constraintobject(cref) @test c.func == [x, z, y, w] @test c.set == MOI.PositiveSemidefiniteConeSquare(2) @SDconstraint(m, cref, [x 1; 1 -y] ⪰ [1 x; x -2]) @test JuMP.name(cref) == "cref" - c = JuMP.constraintobject(cref, Vector{AffExprType}, MOI.PositiveSemidefiniteConeTriangle) + c = JuMP.constraintobject(cref) @test JuMP.isequal_canonical(c.func[1], x-1) @test JuMP.isequal_canonical(c.func[2], 1-x) @test JuMP.isequal_canonical(c.func[3], 2-y) @@ -203,7 +194,7 @@ function constraints_test(ModelType::Type{<:JuMP.AbstractModel}, VariableRefType @SDconstraint(m, iref[i=1:2], 0 ⪯ [x+i x+y; x+y -y]) for i in 1:2 @test JuMP.name(iref[i]) == "iref[$i]" - c = JuMP.constraintobject(iref[i], Vector{AffExprType}, MOI.PositiveSemidefiniteConeTriangle) + c = JuMP.constraintobject(iref[i]) @test JuMP.isequal_canonical(c.func[1], x+i) @test JuMP.isequal_canonical(c.func[2], x+y) @test JuMP.isequal_canonical(c.func[3], -y) @@ -251,9 +242,9 @@ function constraints_test(ModelType::Type{<:JuMP.AbstractModel}, VariableRefType end @testset "Constraints for JuMP.Model" begin - constraints_test(Model, VariableRef, ConstraintRef{Model}) + constraints_test(Model) end @testset "Constraints for JuMPExtension.MyModel" begin - constraints_test(JuMPExtension.MyModel, JuMPExtension.MyVariableRef, JuMPExtension.MyConstraintRef) + constraints_test(JuMPExtension.MyModel) end diff --git a/test/macros.jl b/test/macros.jl index bf6f3f9b61c..d6be13e9b55 100644 --- a/test/macros.jl +++ b/test/macros.jl @@ -72,8 +72,6 @@ end end function macros_test(ModelType::Type{<:JuMP.AbstractModel}, VariableRefType::Type{<:JuMP.AbstractVariableRef}) - AffExprType = JuMP.GenericAffExpr{Float64, VariableRefType} - @testset "buildconstraint on variable" begin m = ModelType() @variable(m, x) @@ -91,42 +89,42 @@ function macros_test(ModelType::Type{<:JuMP.AbstractModel}, VariableRefType::Typ t = 10.0 cref = @constraint(m, 3x - y == 3.3(w + 2z) + 5) - c = JuMP.constraintobject(cref, AffExprType, MOI.EqualTo) + c = JuMP.constraintobject(cref) @test JuMP.isequal_canonical(c.func, 3*x - y - 3.3*w - 6.6*z) @test c.set == MOI.EqualTo(5.0) cref = @constraint(m, 3x - y == (w + 2z)*3.3 + 5) - c = JuMP.constraintobject(cref, AffExprType, MOI.EqualTo) + c = JuMP.constraintobject(cref) @test JuMP.isequal_canonical(c.func, 3*x - y - 3.3*w - 6.6*z) @test c.set == MOI.EqualTo(5.0) cref = @constraint(m, (x+y)/2 == 1) - c = JuMP.constraintobject(cref, AffExprType, MOI.EqualTo) + c = JuMP.constraintobject(cref) @test JuMP.isequal_canonical(c.func, 0.5*x + 0.5*y) @test c.set == MOI.EqualTo(1.0) cref = @constraint(m, -1 <= x-y <= t) - c = JuMP.constraintobject(cref, AffExprType, MOI.Interval) + c = JuMP.constraintobject(cref) @test JuMP.isequal_canonical(c.func, x - y) @test c.set == MOI.Interval(-1.0, t) cref = @constraint(m, -1 <= x+1 <= 1) - c = JuMP.constraintobject(cref, AffExprType, MOI.Interval) + c = JuMP.constraintobject(cref) @test JuMP.isequal_canonical(c.func, 1x) @test c.set == MOI.Interval(-2.0, 0.0) cref = @constraint(m, -1 <= x <= 1) - c = JuMP.constraintobject(cref, VariableRefType, MOI.Interval) + c = JuMP.constraintobject(cref) @test c.func == x @test c.set == MOI.Interval(-1.0, 1.0) cref = @constraint(m, -1 <= x <= sum(0.5 for i = 1:2)) - c = JuMP.constraintobject(cref, VariableRefType, MOI.Interval) + c = JuMP.constraintobject(cref) @test c.func == x @test c.set == MOI.Interval(-1.0, 1.0) cref = @constraint(m, 1 >= x >= 0) - c = JuMP.constraintobject(cref, VariableRefType, MOI.Interval) + c = JuMP.constraintobject(cref) @test c.func == x @test c.set == MOI.Interval(0.0, 1.0) @@ -138,7 +136,7 @@ function macros_test(ModelType::Type{<:JuMP.AbstractModel}, VariableRefType::Typ @test JuMP.isequal_canonical(@expression(m, quad, (w+3)*(2x+1)+10), 2*w*x + 6*x + w + 13) cref = @constraint(m, 3 + 5*7 <= 0) - c = JuMP.constraintobject(cref, AffExpr, MOI.LessThan) + c = JuMP.constraintobject(cref) @test JuMP.isequal_canonical(c.func, zero(AffExpr)) @test c.set == MOI.LessThan(-38.0) end diff --git a/test/operator.jl b/test/operator.jl index c599210e1e2..a555576c8bd 100644 --- a/test/operator.jl +++ b/test/operator.jl @@ -532,13 +532,13 @@ function operators_test(ModelType::Type{<:JuMP.AbstractModel}, VariableRefType:: B = sparse(A) # force vector output cref1 = @constraint(m, reshape(x,(1,3))*A*x .>= 1) - c1 = JuMP.constraintobject.(cref1, QuadExprType, MOI.GreaterThan) + c1 = JuMP.constraintobject.(cref1) f1 = map(c -> c.func, c1) @test JuMP.isequal_canonical(f1, [x[1]*x[1] + 2x[1]*x[2] + 4x[2]*x[2] + 9x[1]*x[3] + 5x[2]*x[3] + 7x[3]*x[3]]) @test all(c -> c.set.lower == 1, c1) cref2 = @constraint(m, x'*A*x >= 1) - c2 = JuMP.constraintobject.(cref2, QuadExprType, MOI.GreaterThan) + c2 = JuMP.constraintobject.(cref2) @test JuMP.isequal_canonical(f1[1], c2.func) mat = [ 3x[1] + 12x[3] + 4x[2] @@ -546,7 +546,7 @@ function operators_test(ModelType::Type{<:JuMP.AbstractModel}, VariableRefType:: 15x[1] + 5x[2] + 21x[3]] cref3 = @constraint(m, (x'A)' + 2A*x .<= 1) - c3 = JuMP.constraintobject.(cref3, AffExprType, MOI.LessThan) + c3 = JuMP.constraintobject.(cref3) f3 = map(c->c.func, c3) @test JuMP.isequal_canonical(f3, mat) @test all(c -> c.set.upper == 1, c3) @@ -559,28 +559,28 @@ function operators_test(ModelType::Type{<:JuMP.AbstractModel}, VariableRefType:: @test JuMP.isequal_canonical((x'A)' + 2A*x, @JuMP.Expression((x'B)' + 2B*x)) cref4 = @constraint(m, -1 .<= (x'A)' + 2A*x .<= 1) - c4 = JuMP.constraintobject.(cref4, AffExprType, MOI.Interval) + c4 = JuMP.constraintobject.(cref4) f4 = map(c->c.func, c4) @test JuMP.isequal_canonical(f4, mat) @test all(c -> c.set.lower == -1, c4) @test all(c -> c.set.upper == 1, c4) cref5 = @constraint(m, -[1:3;] .<= (x'A)' + 2A*x .<= 1) - c5 = JuMP.constraintobject.(cref5, AffExprType, MOI.Interval) + c5 = JuMP.constraintobject.(cref5) f5 = map(c->c.func, c5) @test JuMP.isequal_canonical(f5, mat) @test map(c -> c.set.lower, c5) == -[1:3;] @test all(c -> c.set.upper == 1, c4) cref6 = @constraint(m, -[1:3;] .<= (x'A)' + 2A*x .<= [3:-1:1;]) - c6 = JuMP.constraintobject.(cref6, AffExprType, MOI.Interval) + c6 = JuMP.constraintobject.(cref6) f6 = map(c->c.func, c6) @test JuMP.isequal_canonical(f6, mat) @test map(c -> c.set.lower, c6) == -[1:3;] @test map(c -> c.set.upper, c6) == [3:-1:1;] cref7 = @constraint(m, -[1:3;] .<= (x'A)' + 2A*x .<= 3) - c7 = JuMP.constraintobject.(cref7, AffExprType, MOI.Interval) + c7 = JuMP.constraintobject.(cref7) f7 = map(c->c.func, c7) @test JuMP.isequal_canonical(f7, mat) @test map(c -> c.set.lower, c7) == -[1:3;]