Skip to content

Commit

Permalink
Fix error message if legacy nonlinear is mixed with new NL API (#3741)
Browse files Browse the repository at this point in the history
  • Loading branch information
odow authored May 2, 2024
1 parent 498141b commit 18c01c4
Show file tree
Hide file tree
Showing 3 changed files with 102 additions and 32 deletions.
49 changes: 49 additions & 0 deletions src/nlp.jl
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at https://mozilla.org/MPL/2.0/.

_throw_if_legacy_error(::Any) = nothing

"""
nonlinear_model(
model::GenericModel;
Expand Down Expand Up @@ -209,6 +211,33 @@ struct NonlinearParameter <: AbstractJuMPScalar
index::Int
end

function check_belongs_to_model(arg::NonlinearParameter, model::AbstractModel)
return arg.model === model
end

variable_ref_type(arg::NonlinearParameter) = variable_ref_type(arg.model)

function _throw_if_legacy_error(p::NonlinearParameter)
return error(
"""
Cannot mix a legacy NonlinearParameter with the new nonlinear API.
Got: $p
To update, replace calls to:
```julia
@NLparameter(model, p == 1)
```
with
```julia
@variable(model, p in Parameter(1))
```
""",
)
end

moi_function(p::NonlinearParameter) = _throw_if_legacy_error(p)

function MOI.Nonlinear.parse_expression(
model::MOI.Nonlinear.Model,
expr::MOI.Nonlinear.Expression,
Expand Down Expand Up @@ -313,6 +342,26 @@ struct NonlinearExpression <: AbstractJuMPScalar
index::Int
end

function check_belongs_to_model(arg::NonlinearExpression, model::AbstractModel)
return arg.model === model
end

variable_ref_type(arg::NonlinearExpression) = variable_ref_type(arg.model)

function _throw_if_legacy_error(arg::NonlinearExpression)
return error(
"""
Cannot mix a legacy NonlinearExpression with the new nonlinear API.
Got: $arg
To update, replace all calls to `@NLexpression` with `@expression`.
""",
)
end

moi_function(arg::NonlinearExpression) = _throw_if_legacy_error(arg)

function MOI.Nonlinear.parse_expression(
model::MOI.Nonlinear.Model,
expr::MOI.Nonlinear.Expression,
Expand Down
2 changes: 2 additions & 0 deletions src/nlp_expr.jl
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ struct GenericNonlinearExpr{V<:AbstractVariableRef} <: AbstractJuMPScalar
) where {V<:AbstractVariableRef}
for arg in args
_throw_if_not_real(arg)
_throw_if_legacy_error(arg)
end
return new{V}(head, Any[a for a in args])
end
Expand All @@ -97,6 +98,7 @@ struct GenericNonlinearExpr{V<:AbstractVariableRef} <: AbstractJuMPScalar
) where {V<:AbstractVariableRef}
for arg in args
_throw_if_not_real(arg)
_throw_if_legacy_error(arg)
end
return new{V}(head, args)
end
Expand Down
83 changes: 51 additions & 32 deletions test/test_nlp_expr.jl
Original file line number Diff line number Diff line change
Expand Up @@ -371,26 +371,6 @@ 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)
Expand All @@ -414,18 +394,6 @@ 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)
Expand Down Expand Up @@ -1092,4 +1060,55 @@ function test_error_nonlinear_expr_complex_constructor()
return
end

function test_error_legacy_expression_constructor()
model = Model()
@variable(model, x)
@NLexpression(model, arg, x^3)
err = ErrorException(
"""
Cannot mix a legacy NonlinearExpression with the new nonlinear API.
Got: $arg
To update, replace all calls to `@NLexpression` with `@expression`.
""",
)
@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))
@test_throws err moi_function(arg)
@test_throws err x * arg
@test_throws err arg * x
return
end

function test_error_legacy_parameter_constructor()
model = Model()
@variable(model, x)
@NLparameter(model, p == 1)
err = ErrorException(
"""
Cannot mix a legacy NonlinearParameter with the new nonlinear API.
Got: $p
To update, replace calls to:
```julia
@NLparameter(model, p == 1)
```
with
```julia
@variable(model, p in Parameter(1))
```
""",
)
@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))
@test_throws err moi_function(p)
@test_throws err x * p
@test_throws err p * x
return
end

end # module

0 comments on commit 18c01c4

Please sign in to comment.