1
1
module BipartiteGraphs
2
2
3
3
export BipartiteEdge, BipartiteGraph, DiCMOBiGraph, Unassigned, unassigned,
4
- Matching, ResidualCMOGraph
4
+ Matching, ResidualCMOGraph, InducedCondensationGraph, maximal_matching,
5
+ construct_augmenting_path!
5
6
6
7
export 𝑠vertices, 𝑑vertices, has_𝑠vertex, has_𝑑vertex, 𝑠neighbors, 𝑑neighbors,
7
8
𝑠edges, 𝑑edges, nsrcs, ndsts, SRC, DST, set_neighbors!, invview,
@@ -18,6 +19,14 @@ struct Unassigned
18
19
global unassigned
19
20
const unassigned = Unassigned. instance
20
21
end
22
+ # Behaves as a scalar
23
+ Base. length (u:: Unassigned ) = 1
24
+ Base. size (u:: Unassigned ) = ()
25
+ Base. iterate (u:: Unassigned ) = (unassigned, nothing )
26
+ Base. iterate (u:: Unassigned , state) = nothing
27
+
28
+ Base. show (io:: IO , :: Unassigned ) =
29
+ printstyled (io, " u" ; color= :light_black )
21
30
22
31
struct Matching{U #= > :Unassigned =# , V<: AbstractVector } <: AbstractVector{Union{U, Int}}
23
32
match:: V
@@ -30,6 +39,7 @@ function Matching{V}(m::Matching) where {V}
30
39
Matching {V} (convert (VUT, m. match),
31
40
m. inv_match === nothing ? nothing : convert (VUT, m. inv_match))
32
41
end
42
+ Matching (m:: Matching ) = m
33
43
Matching {U} (v:: V ) where {U, V<: AbstractVector } = Matching {U, V} (v, nothing )
34
44
Matching {U} (v:: V , iv:: Union{V, Nothing} ) where {U, V<: AbstractVector } = Matching {U, V} (v, iv)
35
45
Matching (v:: V ) where {U, V<: AbstractVector{Union{U, Int}} } =
@@ -135,10 +145,13 @@ mutable struct BipartiteGraph{I<:Integer, M} <: Graphs.AbstractGraph{I}
135
145
metadata:: M
136
146
end
137
147
BipartiteGraph (ne:: Integer , fadj:: AbstractVector , badj:: Union{AbstractVector,Integer} = maximum (maximum, fadj); metadata= nothing ) = BipartiteGraph (ne, fadj, badj, metadata)
148
+ BipartiteGraph (fadj:: AbstractVector , badj:: Union{AbstractVector,Integer} = maximum (maximum, fadj); metadata= nothing ) =
149
+ BipartiteGraph (mapreduce (length, + , fadj; init= 0 ), fadj, badj, metadata)
138
150
139
151
@noinline require_complete (g:: BipartiteGraph ) = g. badjlist isa AbstractVector || throw (ArgumentError (" The graph has no back edges. Use `complete`." ))
140
152
141
153
function invview (g:: BipartiteGraph )
154
+ require_complete (g)
142
155
BipartiteGraph (g. ne, g. badjlist, g. fadjlist)
143
156
end
144
157
@@ -215,7 +228,53 @@ ndsts(g::BipartiteGraph) = length(𝑑vertices(g))
215
228
function Graphs. has_edge (g:: BipartiteGraph , edge:: BipartiteEdge )
216
229
@unpack src, dst = edge
217
230
(src in 𝑠vertices (g) && dst in 𝑑vertices (g)) || return false # edge out of bounds
218
- insorted (𝑠neighbors (src), dst)
231
+ insorted (dst, 𝑠neighbors (g, src))
232
+ end
233
+ Base. in (edge:: BipartiteEdge , g:: BipartiteGraph ) = Graphs. has_edge (g, edge)
234
+
235
+ # ## Maximal matching
236
+ """
237
+ construct_augmenting_path!(m::Matching, g::BipartiteGraph, vsrc, dstfilter, vcolor=falses(ndsts(g)), ecolor=falses(nsrcs(g))) -> path_found::Bool
238
+
239
+ Try to construct an augmenting path in matching and if such a path is found,
240
+ update the matching accordingly.
241
+ """
242
+ function construct_augmenting_path! (matching:: Matching , g:: BipartiteGraph , vsrc, dstfilter, dcolor= falses (ndsts (g)), scolor= falses (nsrcs (g)))
243
+ scolor[vsrc] = true
244
+
245
+ # if a `vdst` is unassigned and the edge `vsrc <=> vdst` exists
246
+ for vdst in 𝑠neighbors (g, vsrc)
247
+ if dstfilter (vdst) && matching[vdst] === unassigned
248
+ matching[vdst] = vsrc
249
+ return true
250
+ end
251
+ end
252
+
253
+ # for every `vsrc` such that edge `vsrc <=> vdst` exists and `vdst` is uncolored
254
+ for vdst in 𝑠neighbors (g, vsrc)
255
+ (dstfilter (vdst) && ! dcolor[vdst]) || continue
256
+ dcolor[vdst] = true
257
+ if construct_augmenting_path! (matching, g, matching[vdst], dstfilter, dcolor, scolor)
258
+ matching[vdst] = vsrc
259
+ return true
260
+ end
261
+ end
262
+ return false
263
+ end
264
+
265
+ """
266
+ maximal_matching(g::BipartiteGraph, [srcfilter], [dstfilter])
267
+
268
+ For a bipartite graph `g`, construct a maximal matching of destination to source
269
+ vertices, subject to the constraint that vertices for which `srcfilter` or `dstfilter`,
270
+ return `false` may not be matched.
271
+ """
272
+ function maximal_matching (g:: BipartiteGraph , srcfilter= vsrc-> true , dstfilter= vdst-> true )
273
+ matching = Matching (ndsts (g))
274
+ foreach (Iterators. filter (srcfilter, 𝑠vertices (g))) do vsrc
275
+ construct_augmenting_path! (matching, g, vsrc, dstfilter)
276
+ end
277
+ return matching
219
278
end
220
279
221
280
# ##
@@ -508,4 +567,66 @@ function Graphs.neighbors(rcg::ResidualCMOGraph, v::Integer)
508
567
invview (rcg. matching)[vsrc] === unassigned))
509
568
end
510
569
570
+ # TODO : Fix the function in Graphs to do this instead
571
+ function Graphs. neighborhood (rcg:: ResidualCMOGraph , v:: Integer )
572
+ worklist = Int[v]
573
+ ns = BitSet ()
574
+ while ! isempty (worklist)
575
+ v′ = popfirst! (worklist)
576
+ for n in neighbors (rcg, v′)
577
+ if ! (n in ns)
578
+ push! (ns, n)
579
+ push! (worklist, n)
580
+ end
581
+ end
582
+ end
583
+ return ns
584
+ end
585
+
586
+ """
587
+ struct InducedCondensationGraph
588
+
589
+ For some bipartite-graph and an orientation induced on its destination contraction,
590
+ records the condensation DAG of the digraph formed by the orientation. I.e. this
591
+ is a DAG of connected components formed by the destination vertices of some
592
+ underlying bipartite graph.
593
+
594
+ N.B.: This graph does not store explicit neighbor relations of the sccs.
595
+ Therefor, the edge multiplicity is derived from the underlying bipartite graph,
596
+ i.e. this graph is not strict.
597
+ """
598
+ struct InducedCondensationGraph{G <: BipartiteGraph } <: AbstractGraph {Vector{Union{Int, Vector{Int}}}}
599
+ graph:: G
600
+ # Records the members of a strongly connected component. For efficiency,
601
+ # trivial sccs (with one vertex member) are stored inline. Note: the sccs
602
+ # here are stored in topological order.
603
+ sccs:: Vector{Union{Int, Vector{Int}}}
604
+ # Maps the vertices back to the scc of which they are a part
605
+ scc_assignment:: Vector{Int}
606
+ end
607
+
608
+ function InducedCondensationGraph (g:: BipartiteGraph , sccs:: Vector{Union{Int, Vector{Int}}} )
609
+ scc_assignment = Vector {Int} (undef, ndsts (g))
610
+ for (i, c) in enumerate (sccs)
611
+ for v in c
612
+ scc_assignment[v] = i
613
+ end
614
+ end
615
+ InducedCondensationGraph (g, sccs, scc_assignment)
616
+ end
617
+
618
+ Graphs. is_directed (:: Type{<:InducedCondensationGraph} ) = true
619
+ Graphs. nv (icg:: InducedCondensationGraph ) = length (icg. sccs)
620
+ Graphs. vertices (icg:: InducedCondensationGraph ) = icg. sccs
621
+
622
+ _neighbors (icg:: InducedCondensationGraph , cc:: Integer ) =
623
+ Iterators. flatten (Iterators. flatten (rcg. graph. fadjlist[vsrc] for vsrc in rcg. graph. badjlist[v]) for v in icg. sccs[cc])
624
+
625
+ Graphs. outneighbors (rcg:: InducedCondensationGraph , v:: Integer ) =
626
+ (scc_assignment[n] for n in _neighbors (rcg, v) if scc_assignment[n] > v)
627
+
628
+ Graphs. inneighbors (rcg:: InducedCondensationGraph , v:: Integer ) =
629
+ (scc_assignment[n] for n in _neighbors (rcg, v) if scc_assignment[n] < v)
630
+
631
+
511
632
end # module
0 commit comments