Skip to content

Inefficiency in set_to_node_objectives when working with large models #126

@yhz0

Description

@yhz0

I am working with a large optimization model using Plasmo.jl, but I encountered a performance issue when calling set_to_node_objectives(graph) on a graph with many nodes.

graph = OptiGraph()
set_optimizer(graph, Gurobi.Optimizer)

# Initial call to build the tree
println("Building Graph")
build_layer1_tree(graph, SA[], 1.0, 0)
display(graph)

# An OptiGraph
#          g##284 #local elements  #total elements
#--------------------------------------------------
#          Nodes:    161617           161617
#          Edges:    182364           182364
#      Subgraphs:         0                0
#      Variables:    714177           714177
#    Constraints:   1306045          1306045

using JuMP


println("Setting Objective")
# set_to_node_objectives(graph) # hangs indefinitely

println("Optimizing")
optimize!(graph)

Upon investigating the source code of this function, I found two inefficiencies:

  1. The obj variable is initialized as an integer, but it accumulates more complex types (e.g., JuMP expressions).
  2. obj += sense * JuMP.objective_function(node) creates a copy of the expression each time it’s executed.
function set_to_node_objectives(graph::OptiGraph)
    obj = 0
    for node in all_nodes(graph)
        if has_objective(node)
            sense = JuMP.objective_sense(node) == MOI.MAX_SENSE ? -1 : 1
            obj += sense * JuMP.objective_function(node)  # Copies obj each time
        end
    end
    if obj != 0
        @objective(graph, Min, obj)
    end
    return nothing
end

For my specific case (which involves linear objectives), I was able to use the following workaround.

function set_to_node_objectives_linear(graph::OptiGraph)
    obj::GenericAffExpr{Float64, NodeVariableRef} = 0.0
    for node in all_nodes(graph)
        if Plasmo.has_objective(node)
            sense = JuMP.objective_sense(node) == MOI.MAX_SENSE ? -1 : 1
            JuMP.add_to_expression!(obj, JuMP.objective_function(node), sense)
        end
    end
    @objective(graph, Min, obj)
    return
end

Is there a general way to fix this performance issue?

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions