jump-dev / JuMP.jl

Modeling language for Mathematical Optimization (linear, mixed-integer, conic, semidefinite, nonlinear)
http://jump.dev/JuMP.jl/
Other
2.22k stars 393 forks source link

How to improve the speed to build a complex model? #3688

Closed KennethAnn closed 7 months ago

KennethAnn commented 7 months ago

I am building a large MILP model in JuMP.jl, which was previously built by the Pyomo package in Python. However, I found that JuMP performs so slowly when building some expressions with complex indexes and conditions. An expression is shown below.

@expression(mod, Disp[z in ZONES, t in POINTS], sum(D1[(p, t)] + D2[(p, t)] for p in GENS[z] if (((p, t) in G_PS) & (is1[p] == false))) - sum(D1[(p, t)] * enerload[p] for p in GENS[z] if (((p, t) in G_PS) & (is1[p] == false))))

I'd like to know whether there are any performance suggestions on building the expressions and whether the model can be saved in a file so that I can re-run the model with revised inputs without spending too much time building the expressions.

KennethAnn commented 7 months ago

I got the idea that the condition should not be (p, t) in G_PS), which loops in a larger size of elements. The optimal way is by looping p in a list.

odow commented 7 months ago

This is yet another case of https://github.com/jump-dev/JuMP.jl/issues/2348#issuecomment-1707515885

Please post on https://discourse.julialang.org/c/domain/opt/13 if you need some suggestions.

I'd probably start with:

z_to_p_list = Dict([p for p in GENS[z] if !is1[p]] for z in ZONES)
@expression(
    mod,
    Disp[z in ZONES, t in POINTS],
    sum(D1[(p, t)] + D2[(p, t)] - D1[(p, t)] * enerload[p] for p in z_to_p_list[z] if (p, t) in G_PS)
)

But it depends on what G_PS is.

Even something like

z_to_p_list = Dict([p for p in GENS[z] if !is1[p]] for z in ZONES)
t_to_p_set = Dict()  # Could be Dict{typeof(t),Set{typeof(p)}} if types are known
for (p, t) in G_PS
    if !haskey(t_to_p_set, t)
        t_to_p_set[t] = Set()
    end
    push!(t_to_p_set[t], p)
end
@expression(
    mod,
    Disp[z in ZONES, t in POINTS],
    sum(D1[(p, t)] + D2[(p, t)] - D1[(p, t)] * enerload[p] for p in z_to_p_list[z] if p in t_to_p_set[t])
)