Skip to content

Commit 98dd735

Browse files
authored
Improve the type stability of constant powers (#4016)
1 parent 6420fc2 commit 98dd735

File tree

2 files changed

+54
-0
lines changed

2 files changed

+54
-0
lines changed

src/operators.jl

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,17 @@ function Base.:/(lhs::GenericAffExpr, rhs::_Constant)
226226
return map_coefficients(c -> c / rhs, lhs)
227227
end
228228

229+
# We need an implementation for both Base.literal_pow and Base.:^ because of the
230+
# difference between `x^2` and `a = 2; x^a`.
231+
232+
function Base.literal_pow(::typeof(^), x::AbstractVariableRef, ::Val{0})
233+
return one(value_type(typeof(x)))
234+
end
235+
236+
Base.literal_pow(::typeof(^), x::AbstractVariableRef, ::Val{1}) = x
237+
238+
Base.literal_pow(::typeof(^), x::AbstractVariableRef, ::Val{2}) = x * x
239+
229240
function Base.:^(lhs::V, rhs::Integer) where {V<:AbstractVariableRef}
230241
if rhs == 0
231242
return one(value_type(V))
@@ -238,6 +249,12 @@ function Base.:^(lhs::V, rhs::Integer) where {V<:AbstractVariableRef}
238249
end
239250
end
240251

252+
Base.literal_pow(::typeof(^), x::GenericAffExpr{T}, ::Val{0}) where {T} = one(T)
253+
254+
Base.literal_pow(::typeof(^), x::GenericAffExpr, ::Val{1}) = x
255+
256+
Base.literal_pow(::typeof(^), x::GenericAffExpr, ::Val{2}) = x * x
257+
241258
function Base.:^(lhs::GenericAffExpr{T,V}, rhs::Integer) where {T,V}
242259
if rhs == 0
243260
return one(T)

test/test_operator.jl

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -758,4 +758,41 @@ function test_is_hermitian()
758758
return
759759
end
760760

761+
function test_literal_pow_AbstractVariableRef()
762+
model = Model()
763+
@variable(model, x)
764+
# We need a function barrier to allow Julia to optimize the constant power
765+
p0(x) = x^0
766+
p1(x) = x^1
767+
p2(x) = x^2
768+
@test (@inferred p0(x)) === 1.0
769+
@test isequal_canonical(@inferred(p1(x)), x)
770+
@test isequal_canonical(@inferred(p2(x)), 1.0 * x * x)
771+
# Test the Base.:^ fallback
772+
pa(x, a) = x^a
773+
@test pa(x, 0) === 1.0
774+
@test isequal_canonical(pa(x, 1), x)
775+
@test isequal_canonical(pa(x, 2), 1.0 * x * x)
776+
return
777+
end
778+
779+
function test_literal_pow_GenericAffExpr()
780+
model = Model()
781+
@variable(model, y)
782+
x = 2.0 * y + 1.0
783+
# We need a function barrier to allow Julia to optimize the constant power
784+
p0(x) = x^0
785+
p1(x) = x^1
786+
p2(x) = x^2
787+
@test (@inferred p0(x)) === 1.0
788+
@test isequal_canonical(@inferred(p1(x)), x)
789+
@test isequal_canonical(@inferred(p2(x)), 1.0 * x * x)
790+
# Test the Base.:^ fallback
791+
pa(x, a) = x^a
792+
@test pa(x, 0) === 1.0
793+
@test isequal_canonical(pa(x, 1), x)
794+
@test isequal_canonical(pa(x, 2), 1.0 * x * x)
795+
return
796+
end
797+
761798
end # module

0 commit comments

Comments
 (0)