-
-
Notifications
You must be signed in to change notification settings - Fork 401
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
Should we define zero(AffExpr) and one(AffExpr)? #1151
Comments
If Base is doing this, they may be implicitly assuming that only immutable objects should define zero and one. Maybe we could have two version of |
Not true, we also expose |
seems reasonable. |
We could have a warning |
Having both a mutable and immutable AffExpr is worth considering, but I'd put it off until after 0.19. |
What is the advantage of having the immutable version? |
This example by @jdlara-berkeley suggests a similar issue with m = Model()
x = @variable(m, x >= 0)
NetInjectionVar = Array{AffExpr,2}(undef, 5, 24)
NetInjectionVar[:] .= 0.0
JuMP.add_to_expression!(NetInjectionVar[1,1],x)
NetInjectionVar
5×24 Array{JuMP.GenericAffExpr{Float64,JuMP.VariableRef},2}:
x x x x x x x x x x x x x x x x x x x x x x x x
x x x x x x x x x x x x x x x x x x x x x x x x
x x x x x x x x x x x x x x x x x x x x x x x x
x x x x x x x x x x x x x x x x x x x x x x x x
x x x x x x x x x x x x x x x x x x x x x x x x I claim that this would be less of a gotcha if you had to write NetInjectionVar[:] .= AffExpr(0.0) instead of NetInjectionVar[:] .= 0.0 |
Now that we've changed to m = Model()
x = @variable(m, x >= 0)
NetInjectionVar = Array{JuMP.AffExpr,2}(undef, 5, 24)
NetInjectionVar[:] .= zero(AffExpr)
NetInjectionVar[1,1] += x
julia> NetInjectionVar
5×24 Array{JuMP.GenericAffExpr{Float64,VariableRef},2}:
x 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 |
I just updated my example. The issue still exists on Julia 1.0 and JuMP/MOI. |
We should come back to this, since removing it is going to be breaking for JuMP 1.0. Another option is mutable struct GenericAffExpr{V,K}
mutable::Bool
terms::OrderedDict{K,V}
constant::V
end
function GenericAffExpr{K,V}(terms::OrderedDict{K,V}, constant::V) where {K,V}
return GenericAffExpr(true, terms, constant)
end
function Base.zero(::Type{GenericAffExpr{K,V}}) where {K,V}
return GenericAffExpr(false, OrderedDict{K,V}(), 0.0)
end
function Base.one(::Type{GenericAffExpr{K,V}}) where {K,V}
return GenericAffExpr(false, OrderedDict{K,V}(), 1.0)
end
function add_to_expression!(aff::GenericAffExpr)
if aff.mutable
# ...
else
# ...
end
end In almost all cases the object is mutable (and Julia is probably smart enough to optimize away the This is also breaking because would be people would have to write the following if they were unsure if NetInjectionVar[1,1] = JuMP.add_to_expression!(NetInjectionVar[1,1],x) Having a separate type seems problematic for type stability reasons. (Users will say |
Given that the issue only happens if the user calls |
+1 for the original suggestion to remove
this is pretty clear
...but I didn't think about how I think leaving things as is is also understandable, but defining an immutable |
See issue #1151 for background. The problem is that calls like zero(AffExpr) lead to hard-to-diagnose bugs. However, much of Julia's LinearAlgebra routines assume that zero and one are defined for the element types of arrays. Thus, if we do remove these methods, we're likely to break a lot of user-code.
To summarize, we can either:
My conclusion from #2711 is the second option. The first one is going to cause problems for new users and we will have the forum flooded with questions. The second is going to cause problems for more advanced users, who should, by then, have an understanding of why it happens with sufficient documentation. |
@odow FWIW removing the zeros of AffnExpr makes it harder to compose expressions before they get used in building the constraint. We use Zeros of AffnExpr a lot in Edit: Lol, I just realized that I had added an example back in 2018 when PowerSimulations.jl started. |
You fall into the second category. If needed, you should use |
I agree with the second option. |
The implementation of
zeros(AffExpr, n)
looks likefill!(Array{AffExpr}(n), zero(AffExpr))
, which is problematic because the result isn
entries that refer to the sameAffExpr
(#1113). Same forones
.This leads me to question if we should define
zero(AffExpr)
orone(AffExpr)
at all given that code may be written assuming that these return immutable objects. The replacement isAffExpr(0.0)
andAffExpr(1.0)
.@daschw
The text was updated successfully, but these errors were encountered: