From 1138c47f0d23269a7e0278693f52a82e09d83093 Mon Sep 17 00:00:00 2001 From: odow Date: Wed, 24 Apr 2024 16:41:43 +1200 Subject: [PATCH 1/5] Add tests for issue #3736 --- test/test_expr.jl | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/test/test_expr.jl b/test/test_expr.jl index 1a446493496..d5b11771dce 100644 --- a/test/test_expr.jl +++ b/test/test_expr.jl @@ -519,4 +519,37 @@ function test_aff_expr_complex_HermitianPSDCone() return end +function test_multiply_expr_MA_Zero() + model = Model() + @variable(model, x) + for f in (x, x^2, sin(x)) + @test @expression(model, f * sum(x for i in 1:0)) == 0.0 + @test @expression(model, sum(x for i in 1:0) * f) == 0.0 + @test @expression(model, -f * sum(x for i in 1:0)) == 0.0 + @test @expression(model, sum(x for i in 1:0) * -f) == 0.0 + @test @expression(model, (f + f) * sum(x for i in 1:0)) == 0.0 + @test @expression(model, sum(x for i in 1:0) * (f + f)) == 0.0 + + @test isequal_canonical(@expression(model, f + sum(x for i in 1:0)), f) + @test isequal_canonical(@expression(model, sum(x for i in 1:0) + f), f) + @test isequal_canonical( + @expression(model, -f + sum(x for i in 1:0)), + -1.0 * f, # Needed for f = sin(x) + ) + @test isequal_canonical( + @expression(model, sum(x for i in 1:0) + -f), + -1.0 * f, # Needed for f = sin(x) + ) + @test isequal_canonical( + @expression(model, (f + f) + sum(x for i in 1:0)), + f + f, + ) + @test isequal_canonical( + @expression(model, sum(x for i in 1:0) + (f + f)), + f + f, + ) + end + return +end + end # TestExpr From a2bedfdb0b873343881d5e44e4676d13596b6966 Mon Sep 17 00:00:00 2001 From: odow Date: Wed, 24 Apr 2024 20:19:37 +1200 Subject: [PATCH 2/5] Add methods --- src/operators.jl | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/operators.jl b/src/operators.jl index 9e18da55c64..01e1be6aad4 100644 --- a/src/operators.jl +++ b/src/operators.jl @@ -568,3 +568,9 @@ function Base.complex( ) return r + im * i end + +# These methods are used to provide an efficient implementation for a common +# case like `x^2 * sum(f for i in 1:0)`, which lowers to +# `_MA.operate!!(*, x^2, _MA.Zero())` +_MA.operate!!(::typeof(*), ::AbstractJuMPScalar, ::_MA.Zero) = _MA.Zero() +_MA.operate!!(::typeof(*), ::_MA.Zero, ::AbstractJuMPScalar) = _MA.Zero() From e03e3f8f1ac7de7fd1d629cdefa5a0f9bce4a72a Mon Sep 17 00:00:00 2001 From: odow Date: Thu, 25 Apr 2024 08:51:53 +1200 Subject: [PATCH 3/5] Update --- src/operators.jl | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/src/operators.jl b/src/operators.jl index 01e1be6aad4..268d55b33a5 100644 --- a/src/operators.jl +++ b/src/operators.jl @@ -572,5 +572,18 @@ end # These methods are used to provide an efficient implementation for a common # case like `x^2 * sum(f for i in 1:0)`, which lowers to # `_MA.operate!!(*, x^2, _MA.Zero())` -_MA.operate!!(::typeof(*), ::AbstractJuMPScalar, ::_MA.Zero) = _MA.Zero() -_MA.operate!!(::typeof(*), ::_MA.Zero, ::AbstractJuMPScalar) = _MA.Zero() +function _MA.promote_operation( + ::typeof(*), + ::Type{<:AbstractJuMPScalar}, + ::Type{_MA.Zero}, +) + return _MA.Zero +end + +function _MA.promote_operation( + ::typeof(*), + ::Type{_MA.Zero}, + ::Type{<:AbstractJuMPScalar}, +) + return _MA.Zero +end From 3cdd27b9c47b5b5bbd25e37d6fc17d4bee310efb Mon Sep 17 00:00:00 2001 From: Oscar Dowson Date: Thu, 25 Apr 2024 09:30:19 +1200 Subject: [PATCH 4/5] Update operators.jl --- src/operators.jl | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/src/operators.jl b/src/operators.jl index 268d55b33a5..be5cb0d4fe8 100644 --- a/src/operators.jl +++ b/src/operators.jl @@ -569,9 +569,11 @@ function Base.complex( return r + im * i end -# These methods are used to provide an efficient implementation for a common +# This method is used to provide an efficient implementation for the common # case like `x^2 * sum(f for i in 1:0)`, which lowers to -# `_MA.operate!!(*, x^2, _MA.Zero())` +# `_MA.operate!!(*, x^2, _MA.Zero())`. We don't need the method with reversed +# arguments because MA.Zero is not mutable, and MA never queries the mutablility +# of arguments if the first is not mutable. function _MA.promote_operation( ::typeof(*), ::Type{<:AbstractJuMPScalar}, @@ -579,11 +581,3 @@ function _MA.promote_operation( ) return _MA.Zero end - -function _MA.promote_operation( - ::typeof(*), - ::Type{_MA.Zero}, - ::Type{<:AbstractJuMPScalar}, -) - return _MA.Zero -end From 04f0fc94f7631c04072e3c5dbf92d535866a7361 Mon Sep 17 00:00:00 2001 From: Oscar Dowson Date: Thu, 25 Apr 2024 11:19:28 +1200 Subject: [PATCH 5/5] Update operators.jl --- src/operators.jl | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/src/operators.jl b/src/operators.jl index be5cb0d4fe8..9e18da55c64 100644 --- a/src/operators.jl +++ b/src/operators.jl @@ -568,16 +568,3 @@ function Base.complex( ) return r + im * i end - -# This method is used to provide an efficient implementation for the common -# case like `x^2 * sum(f for i in 1:0)`, which lowers to -# `_MA.operate!!(*, x^2, _MA.Zero())`. We don't need the method with reversed -# arguments because MA.Zero is not mutable, and MA never queries the mutablility -# of arguments if the first is not mutable. -function _MA.promote_operation( - ::typeof(*), - ::Type{<:AbstractJuMPScalar}, - ::Type{_MA.Zero}, -) - return _MA.Zero -end