Skip to content

Commit

Permalink
update assemble_optigraph
Browse files Browse the repository at this point in the history
  • Loading branch information
jalving committed Mar 31, 2024
1 parent df22b74 commit 3a2e02b
Show file tree
Hide file tree
Showing 10 changed files with 191 additions and 131 deletions.
6 changes: 4 additions & 2 deletions src/Plasmo.jl
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ add_node, add_edge, add_subgraph,

all_nodes, all_edges,

containing_optigraphs, source_graph,

# macros

@optinode, @nodevariables, @linkconstraint
Expand All @@ -48,8 +50,8 @@ include("macros.jl")

include("utils.jl")

# include("graph_interface/projections.jl")
include("graph_interface/projections.jl")

# include("graph_interface/topology.jl")
include("graph_interface/topology.jl")

end
62 changes: 31 additions & 31 deletions src/graph_interface/partition.jl
Original file line number Diff line number Diff line change
@@ -1,35 +1,36 @@
# The Partition object describes partitions of optinodes and optiedges.
# Different graph projections can be used to create a Partition object which is the standard interface to form subgraphs
abstract type AbstractPartition end
"""
Partition(hypergraph::HyperGraph,node_membership_vector::Vector{Int64},ref_map::Dict)
Partition(hypergraph::HyperGraph, node_membership_vector::Vector{Int64})
Create a partition of optinodes using `hypergraph`, `node_membership_vector`, and 'ref_map'. The 'ref_map' is a dictionary that maps hypernode indices (integers) and hyperedge indices (tuples) back to optinodes and optiedges.
Create a partition of optinodes using `hypergraph`, `node_membership_vector`, and 'ref_map'.
Partition(optigraph::OptiGraph,node_membership_vector::Vector{Int64},ref_map::Dict)
Partition(optigraph::OptiGraph, node_membership_vector::Vector{Int64})
Create a partition using `optigraph`, `node_membership_vector`, and 'ref_map'. The `ref_map` is a mapping of node_indices to the original optinodes.
Create a partition using `optigraph`, `node_membership_vector`, and 'ref_map'.
Partition(optigraph::OptiGraph,optinode_vectors::Vector{Vector{OptiNode}})
Partition(optigraph::OptiGraph, optinode_vectors::Vector{Vector{OptiNode}})
Manually create a partition using `optigraph` and a vector of vectors containing sets of optinodes that represent each partition.
"""
mutable struct Partition <: AbstractPartition
optinodes::Vector{OptiNode} #optinodes at partition level
optiedges::Vector{OptiEdge} #optiedges at partition level
subpartitions::Vector{AbstractPartition} #subpartitions
mutable struct Partition
optinodes::Vector{OptiNode}
optiedges::Vector{OptiEdge}
subpartitions::Vector{Partition}
end
Partition() = Partition(Vector{OptiNode}(), Vector{OptiEdge}(), Vector{Partition}())

# function Partition() = Partition(Vector{OptiNode}(), Vector{OptiEdge}(), Vector{Partition}())

function _check_valid_partition(
graph::OptiGraph, optinode_vectors::Vector{Vector{OptiNode}}
)
all_subnodes = vcat(optinode_vectors...)
all_graph_nodes = all_nodes(graph)

#nodes can only be in one partition
length(all_subnodes) == length(union(all_subnodes)) || error(
"An optinode appears in multiple partition vectors. A partition requires distinct optinode vectors ",
"An optinode appears in multiple partition vectors.
A partition requires distinct optinode vectors ",
)

#all nodes must be in the optigraph
all(node -> node in all_graph_nodes, all_subnodes) ||
error("The optinode vectors must contain all of the nodes in optigraph $graph")
Expand Down Expand Up @@ -69,7 +70,6 @@ function _check_valid_partition(graph::OptiGraph, subgraphs::Vector{OptiGraph})
return true
end

#Partition using HyperGraph backend
function Partition(graph::OptiGraph, node_membership_vector::Vector{Int64})
optinode_vectors = partition_list(graph, node_membership_vector)
return Partition(graph, optinode_vectors)
Expand Down Expand Up @@ -137,22 +137,21 @@ function Partition(graph::OptiGraph, subgraphs::Vector{OptiGraph})
return partition
end

########################################################################################################
#PARTITION USING DIFFERENT OPTIGRAPH REPRESENTATIONS (e.g. a hypergraph, cliquegraph, or bipartitegraph)
########################################################################################################
#######################################################
# PARTITION USING DIFFERENT OPTIGRAPH REPRESENTATIONS
# (e.g. a hypergraph, cliquegraph, or bipartitegraph)
#######################################################
function Partition(
graph::LightGraphs.AbstractGraph,
proj_map::ProjectionMap;
membership_vector::Vector{Int64},
ref_map::ProjectionMap;
kwargs...,
)
@assert graph == ref_map.projected_graph
return Partition(membership_vector, ref_map; kwargs...)
return Partition(proj_map, membership_vector; kwargs...)
end

function Partition(membership_vector::Vector{Int64}, ref_map::ProjectionMap; kwargs...)
optigraph = ref_map.optigraph
partition_vectors = Plasmo._partition_list(membership_vector)
function Partition(proj_map::ProjectionMap, membership_vector::Vector{Int64}; kwargs...)
optigraph = proj_map.optigraph
partition_vectors = _build_partition_list(membership_vector)
induced = Plasmo.induced_elements(ref_map.projected_graph, partition_vectors; kwargs...)
partition_elements = Plasmo._identify_partitions(induced, ref_map) #could be optinode_vectors, optiedge_vectors, or subgraphs
partition = Partition(optigraph, partition_elements)
Expand Down Expand Up @@ -202,11 +201,10 @@ end
Return a list of optinode partitions given a `membership_vector`
"""
function partition_list(graph::OptiGraph, membership_vector::Vector{Int64})
_init_graph_backend(graph)
hypergraph, hyper_map = Plasmo.graph_backend_data(graph)
partitions = _partition_list(membership_vector)
return [getindex.(Ref(hyper_map), partitions[i]) for i in 1:length(partitions)]
function partition_list(hyper_map::HyperMap, membership_vector::Vector{Int64})
partitions = _build_partition_list(membership_vector)
return get_mapped_elements.(Ref(hyper_map), partitions)
# return [getindex.(Ref(hyper_map), partitions[i]) for i in 1:length(partitions)]
end
@deprecate getpartitionlist partition_list

Expand All @@ -216,7 +214,7 @@ function partition_list(membership_vector::Vector{Int64}, ref_map::ProjectionMap
end

#convert membership_vector to a list of partitions
function _partition_list(membership_vector::Vector)
function _build_partition_list(membership_vector::Vector)
unique_parts = unique(membership_vector)
unique_parts = sort(unique_parts)

Expand Down Expand Up @@ -282,6 +280,8 @@ end
apply_partition!(optigraph::OptiGraph,partition::Partition)
Create subgraphs in `optigraph` using a `partition`.
Clears any current subgraphs and re-creates them
"""
function apply_partition!(graph::OptiGraph, partition::Partition)
root = partition
Expand Down
17 changes: 10 additions & 7 deletions src/graph_interface/projections.jl
Original file line number Diff line number Diff line change
Expand Up @@ -58,19 +58,21 @@ end
Base.broadcastable(graph_map::ProjectionMap) = Ref(graph_map)

"""
get_mapped_elements(proj_map::ProjectionMap, elements::Vector{OptiElement})
get_mapped_elements(proj_map::ProjectionMap, elements::Vector{<:OptiElement})
Get the projected graph elements that correspond to the supplied optigraph elements.
Get the projected graph elements that correspond to the supplied optigraph elements. Note
the use of `UnionAll` to catch vectors of either element.
get_mapped_elements(proj_map::ProjectionMap, elements::Vector{Any})
get_mapped_elements(proj_map::ProjectionMap, elements::Vector{<:GraphElement})
Get the optiraph elements that correspond to the supplied projected graph elements.
Get the optiraph elements that correspond to the supplied projected graph elements. Note
the use of `UnionAll` to catch vectors of either element.
"""
function get_mapped_elements(proj_map::ProjectionMap, elements::Vector{OptiElement})
function get_mapped_elements(proj_map::ProjectionMap, elements::Vector{<:OptiElement})
return getindex.(Ref(proj_map.opti_to_proj_map), elements)
end

function get_mapped_elements(proj_map::ProjectionMap, elements::Vector{GraphElement})
function get_mapped_elements(proj_map::ProjectionMap, elements::Vector{<:GraphElement})
return getindex.(Ref(proj_map.proj_to_opti_map), elements)
end

Expand Down Expand Up @@ -232,4 +234,5 @@ function build_bipartite_graph(optigraph::OptiGraph)
end
end
return graph, graph_map
end
end
@deprecate bipartite_graph build_bipartite_graph
149 changes: 75 additions & 74 deletions src/graph_interface/topology.jl
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
const HyperMap = ProjectionMap{GOI.HyperGraph,HyperGraphProjection}

"""
Graphs.all_neighbors(graph::OptiGraph, node::OptiNode)
Graphs.all_neighbors(hyper_map::HyperMap, node::OptiNode)
Retrieve the optinode neighbors of `node` in the optigraph `graph`.
Uses an underlying hypergraph to query for neighbors.
"""
function Graphs.all_neighbors(hyper_map::HyperMap, node::OptiNode)
vertex = hyper_map[node]
neighbors = Graphs.all_neighbors(hyper_map.projected_graph, vertex)
return get_mapped_elements(hyper_map, neighbors) #getindex.(Ref(hyper_map), neighbors)
return get_mapped_elements(hyper_map, neighbors)
end

"""
Expand All @@ -26,15 +26,15 @@ function Graphs.induced_subgraph(hyper_map::HyperMap, nodes::Vector{OptiNode})
end

"""
incident_edges(graph::OptiGraph, nodes::Vector{OptiNode})
incident_edges(hyper_map::HyperMap, nodes::Vector{OptiNode})
Retrieve incident edges to a set of optinodes.
incident_edges(graph::OptiGraph, node::OptiNode)
incident_edges(hyper_map::HyperMap, node::OptiNode)
Retrieve incident edges to a single optinode.
"""
function incident_edges(hyper_map::HyperMap, nodes::Vector{OptiNode{OptiGraph}})
function incident_edges(hyper_map::HyperMap, nodes::Vector{OptiNode})
hypernodes = Base.getindex.(Ref(hyper_map), nodes)
edges = GOI.incident_edges(hyper_map.projected_graph, hypernodes)
return get_mapped_elements(hyper_map, edges) #getindex.(Ref(hyper_map), incidentedges))
Expand All @@ -50,77 +50,78 @@ end
Retrieve induced edges to a set of optinodes.
"""
function induced_edges(hyper_map::HyperMap, nodes::Vector{OptiNode{OptiGraph}})
function induced_edges(hyper_map::HyperMap, nodes::Vector{OptiNode})
hypernodes = get_mapped_elements(hyper_map, nodes)
induced = induced_edges(hyper_map.projected_graph, hypernodes)
induced = GOI.induced_edges(hyper_map.projected_graph, hypernodes)
optiedges = get_mapped_elements(hyper_map, induced)

#optiedges = convert(Vector{OptiEdge}, getindex.(Ref(hyper_map), inducededges))
return optiedges
end

# """
# identify_edges(graph::OptiGraph, node_vectors::Vector{Vector{OptiNode}})

# Identify induced edges and edge separators from a vector of optinode partitions.
# """
# function identify_edges(graph::OptiGraph, node_vectors::Vector{Vector{OptiNode}})
# _init_graph_backend(graph)
# hypergraph, hyper_map = Plasmo.graph_backend_data(graph)
# hypernode_vectors = [getindex.(Ref(hyper_map), nodes) for nodes in node_vectors]
# part_edges, cross_edges = identify_edges(hypergraph, hypernode_vectors)
# link_part_edges = [getindex.(Ref(hyper_map), edges) for edges in part_edges]
# link_cross_edges = getindex.(Ref(hyper_map), cross_edges)
# return link_part_edges, link_cross_edges
# end

# """
# identify_nodes(graph::OptiGraph, node_vectors::Vector{Vector{OptiEdge}})

# Identify induced nodes and node separators from a vector of optiedge partitions.
# """
# function identify_nodes(graph::OptiGraph, edge_vectors::Vector{Vector{OptiEdge}})
# _init_graph_backend(graph)
# hypergraph, hyper_map = Plasmo.graph_backend_data(graph)
# hyperedge_vectors = [getindex.(Ref(hyper_map), edges) for edges in edge_vectors]
# part_nodes, cross_nodes = identify_nodes(hypergraph, hyperedge_vectors)
# part_optinodes = [getindex.(Ref(hyper_map), nodes) for nodes in part_nodes]
# cross_optinodes = getindex.(Ref(hyper_map), cross_nodes)
# return part_optinodes, cross_optinodes
# end

# """
# neighborhood(graph::OptiGraph, nodes::Vector{OptiNode}, distance::Int64)::Vector{OptiNode})

# Return the optinodes within `distance` of the given `nodes` in the optigraph `graph`.
# """
# function neighborhood(graph::OptiGraph, nodes::Vector{OptiNode}, distance::Int64)
# _init_graph_backend(graph)
# hypergraph, hyper_map = Plasmo.graph_backend_data(graph)
# vertices = getindex.(Ref(hyper_map), nodes)
# new_nodes = neighborhood(hypergraph, vertices, distance)
# return getindex.(Ref(hyper_map), new_nodes)
# end

# """
# expand(graph::OptiGraph, subgraph::OptiGraph, distance::Int64)

# Return a new expanded subgraph given the optigraph `graph` and an existing subgraph `subgraph`.
# The returned subgraph contains the expanded neighborhood within `distance` of the given `subgraph`.
# """
# function expand(graph::OptiGraph, subgraph::OptiGraph, distance::Int64)
# _init_graph_backend(graph)
# hypergraph, hyper_map = Plasmo.graph_backend_data(graph)

# nodes = all_nodes(subgraph)
# hypernodes = getindex.(Ref(hyper_map), nodes)

# new_nodes = neighborhood(hypergraph, hypernodes, distance)
# new_edges = induced_edges(hypergraph, new_nodes)

# new_optinodes = getindex.(Ref(hyper_map), new_nodes)
# new_optiedges = getindex.(Ref(hyper_map), new_edges)
# new_subgraph = OptiGraph(new_optinodes, new_optiedges)

# return new_subgraph
# end
"""
identify_edges(hyper_map::HyperMap, node_vectors::Vector{Vector{OptiNode}})
Identify induced edges and edge separators from a vector of optinode partitions.
# Arguments
- `hyper_map::HyperMap`: A `HyperMap` obtained from `build_hypergraph`.
- `node_vectors::Vector{Vector{OptiNode}}`: A vector of vectors that contain `OptiNode`s.
# Returns
- partition_optiedges::Vector{Vector{OptiEdge}}: The `OptiEdge` vectors for each partition.
- cross_optiedges::Vector{OptiEdge}: A vector of optiedges that cross partitions.
"""
function identify_edges(hyper_map::HyperMap, node_vectors::Vector{Vector{OptiNode}})
hypernode_vectors = get_mapped_elements.(Ref(hyper_map), node_vectors)
partition_edges, cross_edges = GOI.identify_edges(
hyper_map.projected_graph,
hypernode_vectors
)
partition_optiedges = get_mapped_elements.(Ref(hyper_map), partition_edges)
cross_optiedges = get_mapped_elements(hyper_map, cross_edges)
return partition_optiedges, cross_optiedges
end

"""
identify_nodes(hyper_map::HyperMap, node_vectors::Vector{Vector{OptiEdge}})
Identify induced nodes and node separators from a vector of optiedge partitions.
"""
function identify_nodes(hyper_map::HyperMap, edge_vectors::Vector{Vector{OptiEdge}})
hyperedge_vectors = get_mapped_elements.(Ref(hyper_map), edge_vectors)
partition_nodes, cross_nodes = GOI.identify_nodes(
hyper_map.projected_graph,
hyperedge_vectors
)
partition_optinodes = get_mapped_elements.(Ref(hyper_map), partition_nodes)
cross_optinodes = get_mapped_elements(hyper_map, cross_nodes)
return partition_optinodes, cross_optinodes
end

"""
neighborhood(
hyper_map::HyperMap,
nodes::Vector{OptiNode},
distance::Int64
)::Vector{OptiNode}
Return the optinodes within `distance` of the given `nodes` in the optigraph `graph`.
"""
function neighborhood(hyper_map::HyperMap, nodes::Vector{OptiNode}, distance::Int64)
vertices = get_mapped_elements(hyper_map, nodes)
new_nodes = GOI.neighborhood(hyper_map.projected_graph, vertices, distance)
return get_mapped_elements(hyper_map, new_nodes) #getindex.(Ref(hyper_map), new_nodes)
end

"""
expand(hyper_map::HyperMap, subgraph::OptiGraph, distance::Int64)
Return a new expanded subgraph given the optigraph `graph` and an existing subgraph `subgraph`.
The returned subgraph contains the expanded neighborhood within `distance` of the given `subgraph`.
"""
function expand(hyper_map::HyperMap, subgraph::OptiGraph, distance::Int64)
nodes = all_nodes(subgraph)
new_optinodes = neighborhood(hyper_map, nodes, distance)
new_optiedges = induced_edges(hyper_map, new_optinodes)
expanded_subgraph = assemble_optigraph(new_optinodes, new_optiedges)
return expanded_subgraph
end
2 changes: 1 addition & 1 deletion src/macros.jl
Original file line number Diff line number Diff line change
Expand Up @@ -86,4 +86,4 @@ macro nodevariables(nodes, args...)
end

# TODO: @nodeconstraints
# We would need to intercept variable arguments and lookup the actual node variables (tough)
# We would need to intercept variable arguments and lookup the actual node variables
Loading

0 comments on commit 3a2e02b

Please sign in to comment.