diff --git a/src/constraints.jl b/src/constraints.jl index 240b295ecf5..6356dec6cce 100644 --- a/src/constraints.jl +++ b/src/constraints.jl @@ -465,11 +465,10 @@ function constraint_by_name end function constraint_by_name(model::GenericModel, name::String) index = MOI.get(backend(model), MOI.ConstraintIndex, name) - if index isa Nothing + if index === nothing return nothing - else - return constraint_ref_with_index(model, index) end + return constraint_ref_with_index(model, index) end function constraint_by_name( @@ -479,7 +478,7 @@ function constraint_by_name( ::Type{S}, ) where {F<:MOI.AbstractFunction,S<:MOI.AbstractSet} index = MOI.get(backend(model), MOI.ConstraintIndex{F,S}, name) - if index isa Nothing + if index === nothing return nothing end return constraint_ref_with_index(model, index) diff --git a/src/nlp_expr.jl b/src/nlp_expr.jl index 5233165629d..1436c417f11 100644 --- a/src/nlp_expr.jl +++ b/src/nlp_expr.jl @@ -632,15 +632,13 @@ function jump_function(model::GenericModel, expr::MOI.Nonlinear.Expression) ) elseif node.type == MOI.Nonlinear.NODE_MOI_VARIABLE V(model, MOI.VariableIndex(node.index)) - elseif node.type == MOI.Nonlinear.NODE_PARAMETER - NonlinearParameter(model, node.index) - elseif node.type == MOI.Nonlinear.NODE_SUBEXPRESSION - NonlinearExpression(model, node.index) elseif node.type == MOI.Nonlinear.NODE_VALUE expr.values[node.index] else # node.type == MOI.Nonlinear.NODE_COMPARISON # node.type == MOI.Nonlinear.NODE_LOGIC + # node.type == MOI.Nonlinear.NODE_PARAMETER + # node.type == MOI.Nonlinear.NODE_SUBEXPRESSION error("Unsupported node") end end diff --git a/src/operators.jl b/src/operators.jl index 11671393eb8..18a6600ede4 100644 --- a/src/operators.jl +++ b/src/operators.jl @@ -445,10 +445,15 @@ Base.transpose(x::AbstractJuMPScalar) = x Base.conj(x::GenericVariableRef) = x # Can remove the following code once == overloading is removed -function LinearAlgebra.issymmetric(x::Matrix{T}) where {T<:_JuMPTypes} - (n = size(x, 1)) == size(x, 2) || return false +function LinearAlgebra.issymmetric(x::Matrix{<:_JuMPTypes}) + n = size(x, 1) + if n != size(x, 2) + return false + end for i in 1:n, j in (i+1):n - isequal(x[i, j], x[j, i]) || return false + if !isequal(x[i, j], x[j, i]) + return false + end end return true end diff --git a/test/test_constraint.jl b/test/test_constraint.jl index 19c73209575..04214015ac4 100644 --- a/test/test_constraint.jl +++ b/test/test_constraint.jl @@ -621,7 +621,7 @@ function _test_constraint_name_util(ModelType, VariableRefType) MOI.EqualTo{Float64}, ) set_name(con, "kon") - @test constraint_by_name(model, "con") isa Nothing + @test constraint_by_name(model, "con") === nothing _test_constraint_name_util( con, "kon", @@ -646,7 +646,7 @@ function _test_constraint_name_util(ModelType, VariableRefType) ) set_name(con, "con") @test_throws err("con") constraint_by_name(model, "con") - @test constraint_by_name(model, "kon") isa Nothing + @test constraint_by_name(model, "kon") === nothing set_name(kon, "kon") _test_constraint_name_util( con, @@ -2157,4 +2157,18 @@ function test_hermitian_shape() return end +function test_constraint_by_name() + model = Model() + @variable(model, x) + @constraint(model, c, 2x <= 1) + @test constraint_by_name(model, "c") === c + @test constraint_by_name(model, "d") === nothing + F, S1, S2 = AffExpr, MOI.LessThan{Float64}, MOI.GreaterThan{Float64} + @test constraint_by_name(model, "c", F, S1) === c + @test constraint_by_name(model, "c", F, S2) === nothing + @test constraint_by_name(model, "d", F, S1) === nothing + @test constraint_by_name(model, "d", F, S2) === nothing + return +end + end # module diff --git a/test/test_model.jl b/test/test_model.jl index 1d3fd1f92be..ee4c193e383 100644 --- a/test/test_model.jl +++ b/test/test_model.jl @@ -984,6 +984,7 @@ function test_optimize_not_called_warning() end @variable(model, x >= 0) @constraint(model, c, 2x <= 1) + @test_throws OptimizeNotCalled value(x) optimize!(model) set_start_value(x, 0.0) @test_logs (:warn,) (@test_throws OptimizeNotCalled objective_value(model)) @@ -1348,4 +1349,19 @@ function test_iterate_scalar() return end +function test_optimizer_index() + model = Model() do + inner = MOI.Utilities.UniversalFallback(MOI.Utilities.Model{Float64}()) + return MOI.Utilities.MockOptimizer(inner) + end + @variable(model, x) + @test_throws( + ErrorException( + "There is no `optimizer_index` as the optimizer is not synchronized with the cached model. Call `MOIU.attach_optimizer(model)` to synchronize it.", + ), + optimizer_index(x), + ) + return +end + end # module TestModels diff --git a/test/test_nlp_expr.jl b/test/test_nlp_expr.jl index 1bd9e0d2668..a9401175868 100644 --- a/test/test_nlp_expr.jl +++ b/test/test_nlp_expr.jl @@ -1122,4 +1122,16 @@ function test_error_legacy_parameter_constructor() return end +function test_promote_type() + F = GenericNonlinearExpr{GenericVariableRef{Int}} + G = GenericNonlinearExpr{GenericVariableRef{Float64}} + @test_throws( + ErrorException( + "Unable to promote two different types of nonlinear expression", + ), + MA.promote_operation(+, F, G), + ) + return +end + end # module diff --git a/test/test_operator.jl b/test/test_operator.jl index b29d2b357e0..718558aed27 100644 --- a/test/test_operator.jl +++ b/test/test_operator.jl @@ -264,11 +264,21 @@ function test_extension_operator_warn( if ModelType <: Model @test model.operator_counter == 0 end - # Triggers the increment of operator_counter since sum(x) has more than 50 terms - @test_expression(sum(x) + 2x[1]) - if ModelType <: Model - # The following check verifies that this test covers the code incrementing `operator_counter` - @test model.operator_counter == 1 + lhs = sum(x) + rhs = 2 * x[1] + for i in 1:20_001 + # Triggers the increment of operator_counter since lhs has more than + # 50 terms + if i == 20_001 && ModelType <: Model + @test_logs (:warn,) lhs + rhs + else + lhs + rhs + end + if ModelType <: Model + # The following check verifies that this test covers the code + # incrementing `operator_counter` + @test model.operator_counter == i + end end return end @@ -723,4 +733,13 @@ function test_hermitian_and_symmetric() return end +function test_is_symmetric() + model = Model() + @variable(model, x[1:3]) + @test !LinearAlgebra.issymmetric([x[1] x[2]; x[3] x[3]]) + @test !LinearAlgebra.issymmetric([x[1] x[2]]) + @test LinearAlgebra.issymmetric([x[1] x[2]; x[2] x[3]]) + return +end + end diff --git a/test/test_variable.jl b/test/test_variable.jl index 1ac9440c0a7..d61675dd484 100644 --- a/test/test_variable.jl +++ b/test/test_variable.jl @@ -376,7 +376,7 @@ function test_extension_variable_name( @variable(model, x) _test_variable_name_util(x, "x") set_name(x, "y") - @test variable_by_name(model, "x") isa Nothing + @test variable_by_name(model, "x") === nothing _test_variable_name_util(x, "y") y = @variable(model, base_name = "y") err(name) = ErrorException("Multiple variables have the name $name.") @@ -386,7 +386,7 @@ function test_extension_variable_name( _test_variable_name_util(y, "x") set_name(x, "x") @test_throws err("x") variable_by_name(model, "x") - @test variable_by_name(model, "y") isa Nothing + @test variable_by_name(model, "y") === nothing set_name(y, "y") _test_variable_name_util(x, "x") _test_variable_name_util(y, "y")