-
Notifications
You must be signed in to change notification settings - Fork 8
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
Ternary operator inside macros #324
Comments
Check against |
So I think we already do the clever thing here, because julia> dump(:(a ? b : c))
Expr
head: Symbol if
args: Array{Any}((3,))
1: Symbol a
2: Symbol b
3: Symbol c
julia> dump(:(if a; b else c end))
Expr
head: Symbol if
args: Array{Any}((3,))
1: Symbol a
2: Expr
head: Symbol block
args: Array{Any}((2,))
1: LineNumberNode
line: Int64 1
file: Symbol REPL[54]
2: Symbol b
3: Expr
head: Symbol block
args: Array{Any}((2,))
1: LineNumberNode
line: Int64 1
file: Symbol REPL[54]
2: Symbol c Check: julia> model = Model();
julia> @variable(model, x[1:2])
2-element Vector{VariableRef}:
x[1]
x[2]
julia> j = 2
2
julia> @allocated @expression(model, (iseven(j) ? 3x[j] : 0) + 2x[1])
640
julia> @allocated @expression(model, 2x[1] + (iseven(j) ? 3x[j] : 0))
1216
julia> @allocated @expression(model, 2x[1] + 3x[j])
640 The issue is that if the if block is on the right-hand side, we first do Trying to merge the outer expression with the inner part of the @expression(model, 2x[1] + (iseven(j) ? (a = 3; b = x[j]; a * b) : 0)) we'd need to track that the outer operator is |
I think we can just close this as won't fix. |
Since conditionals are already optimized, I would like to bring back the alternative of the macro kind of solution such as |
Strongly against. The macro is more characters: @zero_else(iseven(j), 3x[j])
(iseven(j) ? 3x[j] : 0) For the common case of out-of-bounds access, you can also do: julia> model = Model();
julia> @variable(model, x[1:2]);
julia> @expression(model, [i in 1:2], (i > 1 ? x[i-1] : 0) + x[i])
2-element Vector{AffExpr}:
x[1]
x[1] + x[2]
julia> @expression(model, [i in 1:2], get(x, i-1, 0) + x[i])
2-element Vector{AffExpr}:
x[1]
x[1] + x[2] |
The issue is that users might accidentally write the slow version. If we add another macro, since the users won't know about it, they will still be able to write the slow version. |
It's also the case that the most common use-case is something like a variable or |
If it's a variable or zero then you should do |
What's the point of all this? It's up to the user to write nice code. This is, at best, a small edge case that does not have performance implications. I don't want a special case. The @expression(EP, eTotalCap[y in 1:G],
if y in intersect(NEW_CAP, RET_CAP, RETROFIT_CAP) # Resources eligible for new capacity, retirements and being retrofitted
if y in COMMIT
eExistingCap[y] +
cap_size(gen[y]) * (EP[:vCAP][y] - EP[:vRETCAP][y] - EP[:vRETROFITCAP][y])
else
eExistingCap[y] + EP[:vCAP][y] - EP[:vRETCAP][y] - EP[:vRETROFITCAP][y]
end
elseif y in intersect(setdiff(RET_CAP, NEW_CAP), setdiff(RET_CAP, RETROFIT_CAP)) # Resources eligible for only capacity retirements
if y in COMMIT
eExistingCap[y] - cap_size(gen[y]) * EP[:vRETCAP][y]
else
eExistingCap[y] - EP[:vRETCAP][y]
end
elseif y in setdiff(intersect(RET_CAP, NEW_CAP), RETROFIT_CAP) # Resources eligible for retirement and new capacity
if y in COMMIT
eExistingCap[y] + cap_size(gen[y]) * (EP[:vCAP][y] - EP[:vRETCAP][y])
else
eExistingCap[y] + EP[:vCAP][y] - EP[:vRETCAP][y]
end
elseif y in setdiff(intersect(RET_CAP, RETROFIT_CAP), NEW_CAP) # Resources eligible for retirement and retrofitting
if y in COMMIT
eExistingCap[y] -
cap_size(gen[y]) * (EP[:vRETROFITCAP][y] + EP[:vRETCAP][y])
else
eExistingCap[y] - (EP[:vRETROFITCAP][y] + EP[:vRETCAP][y])
end
elseif y in intersect(setdiff(NEW_CAP, RET_CAP), setdiff(NEW_CAP, RETROFIT_CAP)) # Resources eligible for only new capacity
if y in COMMIT
eExistingCap[y] + cap_size(gen[y]) * EP[:vCAP][y]
else
eExistingCap[y] + EP[:vCAP][y]
end
else # Resources not eligible for new capacity or retirement
eExistingCap[y]
end) That's a much more impactful case than a few |
The most common are indeed |
In which case, rewriting has no benefit. And IMO, adding |
Yes, it also make it sounds like there is something sophisticated behind while the simplest thing (ternary) already works so I don't think we should do anything |
Many users use the ternary operator (
? :
) inside@expresion
and@constraint
.A very common usage is optional slack variables.
The following example illustrates that usage.
JuMP has options to do it efficiently, writing different expressions in a loop or using
add_to_expression!
. But:add_to_expression!
is readability.ifelse
is not an option as the variable frequently does not exist in this cases.--
As an alternative to:
@expression(model, 2x[1] + (iseven(j) ? 3x[j] : 0))
Maybe we can to something more clever? such as:
@expression(model, 2x[1] + @zero_if_not(iseven(j), 3x[j]))
--
Here is the example:
Which results in:
The text was updated successfully, but these errors were encountered: