Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix error message if NonlinearExpression is mixed with new NL API #3741

Merged
merged 6 commits into from
May 2, 2024
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
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
odow marked this conversation as resolved.
Show resolved Hide resolved
@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
odow marked this conversation as resolved.
Show resolved Hide resolved
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
Loading