diff --git a/src/nlp.jl b/src/nlp.jl index 53e72f23438..0d82ff476ef 100644 --- a/src/nlp.jl +++ b/src/nlp.jl @@ -209,6 +209,10 @@ struct NonlinearParameter <: AbstractJuMPScalar index::Int end +function check_belongs_to_model(arg::NonlinearParameter, model::AbstractModel) + return arg.model === model +end + function MOI.Nonlinear.parse_expression( model::MOI.Nonlinear.Model, expr::MOI.Nonlinear.Expression, @@ -313,6 +317,10 @@ struct NonlinearExpression <: AbstractJuMPScalar index::Int end +function check_belongs_to_model(arg::NonlinearExpression, model::AbstractModel) + return arg.model === model +end + function MOI.Nonlinear.parse_expression( model::MOI.Nonlinear.Model, expr::MOI.Nonlinear.Expression, diff --git a/src/nlp_expr.jl b/src/nlp_expr.jl index 342916a7f35..57a1634c207 100644 --- a/src/nlp_expr.jl +++ b/src/nlp_expr.jl @@ -87,7 +87,6 @@ struct GenericNonlinearExpr{V<:AbstractVariableRef} <: AbstractJuMPScalar ) where {V<:AbstractVariableRef} for arg in args _throw_if_not_real(arg) - _throw_if_legacy(arg) end return new{V}(head, Any[a for a in args]) end @@ -98,20 +97,16 @@ struct GenericNonlinearExpr{V<:AbstractVariableRef} <: AbstractJuMPScalar ) where {V<:AbstractVariableRef} for arg in args _throw_if_not_real(arg) - _throw_if_legacy(arg) end return new{V}(head, args) end end -_throw_if_legacy(::Any) = nothing - -function _throw_if_legacy(arg::Union{NonlinearExpression,NonlinearParameter}) +function moi_function(arg::Union{NonlinearExpression,NonlinearParameter}) return error( - "Cannot create a nonlinear expression that mixes features from " * - "both the legacy (macros beginning with `@NL`) and new " * - "(`NonlinearExpr`) nonlinear interfaces. You must use one or " * - "the other. Got: $arg", + "You cannot mix legacy nonlinear object of type $(typeof(arg)) with " * + "the new nonlinear API. To use the legacy nonlinear API, all " * + "nonlinear objects must be in a `@NL` macro.", ) end diff --git a/test/test_nlp_expr.jl b/test/test_nlp_expr.jl index 58266ae659f..3d6e2b3b748 100644 --- a/test/test_nlp_expr.jl +++ b/test/test_nlp_expr.jl @@ -371,6 +371,26 @@ function test_extension_recursion_stackoverflow( return end +function test_nlparameter_interaction() + model = Model() + @variable(model, x) + @NLparameter(model, p == 1) + e = x + p + @test e isa GenericNonlinearExpr + @test string(e) == "x + ($p)" + return +end + +function test_nlexpression_interaction() + model = Model() + @variable(model, x) + @NLexpression(model, expr, sin(x)) + e = x + expr + @test e isa GenericNonlinearExpr + @test string(e) == "x + ($expr)" + return +end + function test_nlobjective_with_nlexpr() model = Model() @variable(model, x) @@ -394,6 +414,18 @@ function test_nlconstraint_with_nlexpr() return end +function test_jump_function_nonlinearexpr() + model = Model() + @variable(model, x) + @NLparameter(model, p == 1) + @NLexpression(model, expr1, sin(p + x)) + @NLexpression(model, expr2, sin(expr1)) + nlp = nonlinear_model(model) + @test string(jump_function(model, nlp[index(expr1)])) == "sin(($p) + $x)" + @test string(jump_function(model, nlp[index(expr2)])) == "sin($expr1)" + return +end + function test_constraint_object() model = Model() @variable(model, x) @@ -1065,15 +1097,13 @@ function test_error_legacy_expression_constructor() @variable(model, x) @NLexpression(model, arg, x^3) err = ErrorException( - "Cannot create a nonlinear expression that mixes features from " * - "both the legacy (macros beginning with `@NL`) and new " * - "(`NonlinearExpr`) nonlinear interfaces. You must use one or " * - "the other. Got: $arg", + "You cannot mix legacy nonlinear object of type $(typeof(arg)) with " * + "the new nonlinear API. To use the legacy nonlinear API, all " * + "nonlinear objects must be in a `@NL` macro.", ) - @test_throws err GenericNonlinearExpr(:*, Any[x, arg]) - @test_throws err GenericNonlinearExpr(:*, x, arg) - @test_throws err (x * arg) - @test_throws err (arg * x) + @test_throws err @objective(model, Min, arg) + @test_throws err @constraint(model, arg <= 0) + @test_throws err @constraint(model, arg in MOI.LessThan(0.0)) return end @@ -1082,17 +1112,13 @@ function test_error_legacy_parameter_constructor() @variable(model, x) @NLparameter(model, p == 1) err = ErrorException( - "Cannot create a nonlinear expression that mixes features from " * - "both the legacy (macros beginning with `@NL`) and new " * - "(`NonlinearExpr`) nonlinear interfaces. You must use one or " * - "the other. Got: $p", + "You cannot mix legacy nonlinear object of type $(typeof(p)) with " * + "the new nonlinear API. To use the legacy nonlinear API, all " * + "nonlinear objects must be in a `@NL` macro.", ) - @test_throws err GenericNonlinearExpr(:*, Any[x, p]) - @test_throws err GenericNonlinearExpr(:*, Any[p, x]) - @test_throws err GenericNonlinearExpr(:*, x, p) - @test_throws err GenericNonlinearExpr(:*, p, x) - @test_throws err (x * p) - @test_throws err (p * x) + @test_throws err @objective(model, Min, p) + @test_throws err @constraint(model, p <= 0) + @test_throws err @constraint(model, p in MOI.LessThan(0.0)) return end