From 88ccae420e0fbafbeb0e4900d8f57430ffc7bfd4 Mon Sep 17 00:00:00 2001 From: odow Date: Mon, 27 Nov 2023 09:42:47 +1300 Subject: [PATCH 1/3] Fix error message for invalid indicator connstraints --- src/indicator.jl | 39 ++++++++++++++++++++------------------- test/test_constraint.jl | 10 ++++++++++ 2 files changed, 30 insertions(+), 19 deletions(-) diff --git a/src/indicator.jl b/src/indicator.jl index 77bee822bca..1f76d3e67e1 100644 --- a/src/indicator.jl +++ b/src/indicator.jl @@ -16,6 +16,18 @@ function _build_indicator_constraint( return VectorConstraint([variable, jump_function(constraint)], set) end +function _build_indicator_constraint( + _error::Function, + lhs::F, + ::ScalarConstraint, + ::Type{<:MOI.Indicator}, +) where {F} + return _error( + "unable to build indicator constraint with the left-hand side term " * + "`($lhs)::$F`. The left-hand side must be a binary decision variable.", + ) +end + function _indicator_variable_set(::Function, variable::Symbol) return variable, MOI.Indicator{MOI.ACTIVATE_ON_ONE} end @@ -51,30 +63,19 @@ function parse_constraint_call( "Invalid right-hand side `$(rhs)` of indicator constraint. Expected constraint surrounded by `{` and `}`.", ) end - rhs_con = rhs.args[1] - rhs_vectorized, rhs_parsecode, rhs_buildcall = - parse_constraint(_error, rhs_con) + rhs_vectorized, rhs_parsecode, rhs_build_call = + parse_constraint(_error, rhs.args[1]) if vectorized != rhs_vectorized _error("Inconsistent use of `.` in symbols to indicate vectorization.") end - if vectorized - buildcall = :( - _build_indicator_constraint.( - $_error, - $(esc(variable)), - $rhs_buildcall, - $S, - ) - ) + f, lhs_parse_code = _rewrite_expression(variable) + push!(rhs_parsecode.args, lhs_parse_code) + build_call = if vectorized + :(_build_indicator_constraint.($_error, $f, $rhs_build_call, $S)) else - buildcall = :(_build_indicator_constraint( - $_error, - $(esc(variable)), - $rhs_buildcall, - $S, - )) + :(_build_indicator_constraint($_error, $f, $rhs_build_call, $S)) end - return rhs_parsecode, buildcall + return rhs_parsecode, build_call end function constraint_string( diff --git a/test/test_constraint.jl b/test/test_constraint.jl index 20b43dab372..8150c946df6 100644 --- a/test/test_constraint.jl +++ b/test/test_constraint.jl @@ -1783,4 +1783,14 @@ function test_SkipModelConvertScalarSetWrapper() return end +function test_indicator_error() + model = Model() + @variable(model, x[1:2]) + err = ErrorException( + "In `@constraint(model, x[1] >= 0 --> {x[2] == 0})`: unable to build indicator constraint with the left-hand side term `(x[1] >= 0)::NonlinearExpr`. The left-hand side must be a binary decision variable.", + ) + @test_macro_throws err @constraint(model, x[1] >= 0 --> {x[2] == 0}) + return +end + end # module From 8dc8d41dac71a7aa4e96d242e7c76bd0edf31e53 Mon Sep 17 00:00:00 2001 From: odow Date: Mon, 27 Nov 2023 09:52:35 +1300 Subject: [PATCH 2/3] Fix --- test/test_constraint.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test_constraint.jl b/test/test_constraint.jl index 8150c946df6..3d6ef60c77a 100644 --- a/test/test_constraint.jl +++ b/test/test_constraint.jl @@ -1789,7 +1789,7 @@ function test_indicator_error() err = ErrorException( "In `@constraint(model, x[1] >= 0 --> {x[2] == 0})`: unable to build indicator constraint with the left-hand side term `(x[1] >= 0)::NonlinearExpr`. The left-hand side must be a binary decision variable.", ) - @test_macro_throws err @constraint(model, x[1] >= 0 --> {x[2] == 0}) + @test_throws_strip err @constraint(model, x[1] >= 0 --> {x[2] == 0}) return end From 77559296db4402aff38c2c3afa5745895e9b5827 Mon Sep 17 00:00:00 2001 From: Oscar Dowson Date: Mon, 27 Nov 2023 10:42:53 +1300 Subject: [PATCH 3/3] Update test/test_constraint.jl --- test/test_constraint.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test_constraint.jl b/test/test_constraint.jl index 3d6ef60c77a..37585b61d4a 100644 --- a/test/test_constraint.jl +++ b/test/test_constraint.jl @@ -1787,7 +1787,7 @@ function test_indicator_error() model = Model() @variable(model, x[1:2]) err = ErrorException( - "In `@constraint(model, x[1] >= 0 --> {x[2] == 0})`: unable to build indicator constraint with the left-hand side term `(x[1] >= 0)::NonlinearExpr`. The left-hand side must be a binary decision variable.", + "In `@constraint(model, x[1] >= 0 --> {x[2] == 0})`: unable to build indicator constraint with the left-hand side term `(x[1] >= 0)::JuMP.NonlinearExpr`. The left-hand side must be a binary decision variable.", ) @test_throws_strip err @constraint(model, x[1] >= 0 --> {x[2] == 0}) return