Skip to content

Commit

Permalink
Merge pull request #13 from Robbybp/import
Browse files Browse the repository at this point in the history
More conventional importing of dependencies
  • Loading branch information
Robbybp authored Jul 23, 2023
2 parents 6c21075 + 6a71fea commit b932bcc
Show file tree
Hide file tree
Showing 3 changed files with 30 additions and 41 deletions.
28 changes: 14 additions & 14 deletions src/dulmage_mendelsohn.jl
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
# This software is distributed under the 3-clause BSD license.
# ___________________________________________________________________________

import Graphs as gjl
import Graphs

import JuMPIn: maximum_matching, _is_valid_bipartition

Expand All @@ -27,12 +27,12 @@ In this function, matching must contain a key for every matched node.
I.e., Set(keys(matching)) == Set(values(matching))
"""
function _get_projected_digraph(
graph::gjl.Graph, nodes::Vector, matching::Dict
graph::Graphs.Graph, nodes::Vector, matching::Dict
)
# Note that we are constructing a graph in a projected space, and must
# be aware of whether coordinates are in original or projected spaces.
orig_proj_map = Dict(n => i for (i, n) in enumerate(nodes))
n_nodes = gjl.nv(graph)
n_nodes = Graphs.nv(graph)
n_nodes_proj = length(nodes)
matched_nodes = keys(matching)
node_set = Set(nodes) # Set of nodes in the original space
Expand All @@ -41,7 +41,7 @@ function _get_projected_digraph(
orig_node = nodes[proj_node]
if orig_node in matched_nodes
# In-edges from all (other) neighbors of matched node
for nbr in gjl.neighbors(graph, matching[orig_node])
for nbr in Graphs.neighbors(graph, matching[orig_node])
if nbr != orig_node
nbr_proj = orig_proj_map[nbr]
push!(edge_set, (nbr_proj, proj_node))
Expand All @@ -50,29 +50,29 @@ function _get_projected_digraph(
end
# TODO: Out edges?
end
digraph = gjl.DiGraph(n_nodes_proj)
digraph = Graphs.DiGraph(n_nodes_proj)
for (n1, n2) in edge_set
gjl.add_edge!(digraph, n1, n2)
Graphs.add_edge!(digraph, n1, n2)
end
return digraph, orig_proj_map
end


function _get_reachable_from(digraph::gjl.DiGraph, nodes::Vector)
n_nodes = gjl.nv(digraph)
function _get_reachable_from(digraph::Graphs.DiGraph, nodes::Vector)
n_nodes = Graphs.nv(digraph)
source_set = Set(nodes)
gjl.add_vertex!(digraph)
Graphs.add_vertex!(digraph)
# Note that root needs to be in this scope so it can be accessed in
# finally block
root = n_nodes + 1
bfs_parents = Vector{Int64}()
try
for node in nodes
gjl.add_edge!(digraph, root, node)
Graphs.add_edge!(digraph, root, node)
end
bfs_parents = gjl.bfs_parents(digraph, root)
bfs_parents = Graphs.bfs_parents(digraph, root)
finally
gjl.rem_vertex!(digraph, root)
Graphs.rem_vertex!(digraph, root)
end
reachable = [
node for (node, par) in enumerate(bfs_parents)
Expand All @@ -82,11 +82,11 @@ function _get_reachable_from(digraph::gjl.DiGraph, nodes::Vector)
end


function dulmage_mendelsohn(graph::gjl.Graph, set1::Set)
function dulmage_mendelsohn(graph::Graphs.Graph, set1::Set)
if !_is_valid_bipartition(graph, set1)
throw(Exception)
end
n_nodes = gjl.nv(graph)
n_nodes = Graphs.nv(graph)
set2 = setdiff(Set(1:n_nodes), set1)

# Compute maximum matching between bipartite sets
Expand Down
23 changes: 6 additions & 17 deletions src/interface.jl
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,7 @@ import JuMP

import JuMPIn: get_bipartite_incidence_graph, maximum_matching, GraphDataTuple

import Graphs as gjl
import BipartiteMatching as bpm

import Graphs

"""
Utility function to convert a tuple of nodes and edges into a
Expand All @@ -39,17 +37,16 @@ function _tuple_to_graphs_jl(bip_graph)
# Assumption here is that A and B are disjoint. And also form
# a partition of 1:nv.
nv = length(A) + length(B)
graph = gjl.Graph(gjl.Edge.(E))
graph = Graphs.Graph(Graphs.Edge.(E))
# If E does not cover all vertices, some vertices may not appear in the
# graph. Add these missing vertices.
n_missing = nv - gjl.nv(graph)
gjl.add_vertices!(graph, n_missing)
n_missing = nv - Graphs.nv(graph)
Graphs.add_vertices!(graph, n_missing)
# Note that by constructing this graph, we have lost our particular
# bipartition.
return graph
end


function _maps_to_nodes(con_map, var_map)
n_nodes = length(con_map) + length(var_map)
nodes = Vector{Any}([nothing for _ in 1:n_nodes])
Expand All @@ -65,7 +62,6 @@ function _maps_to_nodes(con_map, var_map)
return nodes
end


"""
IncidenceGraphInterface(model; include_inequality = false)
Expand Down Expand Up @@ -99,7 +95,6 @@ struct IncidenceGraphInterface
_nodes
end


IncidenceGraphInterface(
args::GraphDataTuple
) = IncidenceGraphInterface(
Expand All @@ -109,23 +104,20 @@ IncidenceGraphInterface(
_maps_to_nodes(args[2], args[3]),
)


IncidenceGraphInterface(
m::JuMP.Model;
include_inequality::Bool = false,
) = IncidenceGraphInterface(
get_bipartite_incidence_graph(m, include_inequality = include_inequality)
)


IncidenceGraphInterface(
constraints::Vector{<:JuMP.ConstraintRef},
variables::Vector{JuMP.VariableRef},
) = IncidenceGraphInterface(
get_bipartite_incidence_graph(constraints, variables)
)


"""
get_adjacent(
igraph::IncidenceGraphInterface,
Expand All @@ -140,12 +132,11 @@ function get_adjacent(
constraint::JuMP.ConstraintRef,
)::Vector{JuMP.VariableRef}
con_node = igraph._con_node_map[constraint]
var_nodes = gjl.neighbors(igraph._graph, con_node)
var_nodes = Graphs.neighbors(igraph._graph, con_node)
variables = [igraph._nodes[n] for n in var_nodes]
return variables
end


"""
get_adjacent(
igraph::IncidenceGraphInterface,
Expand Down Expand Up @@ -176,12 +167,11 @@ function get_adjacent(
variable::JuMP.VariableRef,
)::Vector{JuMP.ConstraintRef}
var_node = igraph._var_node_map[variable]
con_nodes = gjl.neighbors(igraph._graph, var_node)
con_nodes = Graphs.neighbors(igraph._graph, var_node)
constraints = [igraph._nodes[n] for n in con_nodes]
return constraints
end


"""
maximum_matching(igraph::IncidenceGraphInterface)::Dict
Expand Down Expand Up @@ -351,7 +341,6 @@ function dulmage_mendelsohn(
return con_dmp, var_dmp
end


function dulmage_mendelsohn(
constraints::Vector{<:JuMP.ConstraintRef},
variables::Vector{JuMP.VariableRef},
Expand Down
20 changes: 10 additions & 10 deletions src/maximum_matching.jl
Original file line number Diff line number Diff line change
Expand Up @@ -17,46 +17,46 @@
# This software is distributed under the 3-clause BSD license.
# ___________________________________________________________________________

import Graphs as gjl
import BipartiteMatching as bpm
import Graphs
import BipartiteMatching as BM


"""
TODO: This should probably be promoted to Graphs.jl
"""
function _is_valid_bipartition(graph::gjl.Graph, set1::Set)
n_nodes = gjl.nv(graph)
function _is_valid_bipartition(graph::Graphs.Graph, set1::Set)
n_nodes = Graphs.nv(graph)
all_nodes = Set(1:n_nodes)
if !issubset(set1, all_nodes)
throw(Exception)
end
set2 = setdiff(all_nodes, set1)
for node in set1
if !issubset(gjl.neighbors(graph, node), set2)
if !issubset(Graphs.neighbors(graph, node), set2)
return false
end
end
for node in set2
if !issubset(gjl.neighbors(graph, node), set1)
if !issubset(Graphs.neighbors(graph, node), set1)
return false
end
end
return true
end


function maximum_matching(graph::gjl.Graph, set1::Set)
function maximum_matching(graph::Graphs.Graph, set1::Set)
if !_is_valid_bipartition(graph, set1)
throw(Exception)
end
n_nodes = gjl.nv(graph)
n_nodes = Graphs.nv(graph)
card1 = length(set1)
nodes1 = sort([node for node in set1])
set2 = setdiff(Set(1:n_nodes), set1)
nodes2 = sort([node for node in set2])
edge_set = Set((n1, n2) for n1 in nodes1 for n2 in gjl.neighbors(graph, n1))
edge_set = Set((n1, n2) for n1 in nodes1 for n2 in Graphs.neighbors(graph, n1))
amat = BitArray{2}((r, c) in edge_set for r in nodes1, c in nodes2)
matching, _ = bpm.findmaxcardinalitybipartitematching(amat)
matching, _ = BM.findmaxcardinalitybipartitematching(amat)
# Translate row/column coordinates back into nodes of the graph
graph_matching = Dict(nodes1[r] => nodes2[c] for (r, c) in matching)
return graph_matching
Expand Down

0 comments on commit b932bcc

Please sign in to comment.