Skip to content

Commit 4ea6a50

Browse files
committed
Make back edges optional
1 parent afc84fd commit 4ea6a50

File tree

1 file changed

+23
-14
lines changed

1 file changed

+23
-14
lines changed

src/bipartite_graph.jl

Lines changed: 23 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -66,13 +66,13 @@ badjlist = [[1,2,5,6],[3,4,6]]
6666
bg = BipartiteGraph(7, fadjlist, badjlist)
6767
```
6868
"""
69-
mutable struct BipartiteGraph{I<:Integer,M} <: LightGraphs.AbstractGraph{I}
69+
mutable struct BipartiteGraph{I<:Integer,F<:Vector{Vector{I}},B<:Union{Vector{Vector{I}},Nothing},M} <: LightGraphs.AbstractGraph{I}
7070
ne::Int
71-
fadjlist::Vector{Vector{I}} # `fadjlist[src] => dsts`
72-
badjlist::Vector{Vector{I}} # `badjlist[dst] => srcs`
71+
fadjlist::F # `fadjlist[src] => dsts`
72+
badjlist::B # `badjlist[dst] => srcs`
7373
metadata::M
7474
end
75-
BipartiteGraph(ne::Integer, fadj::AbstractVector, badj::AbstractVector) = BipartiteGraph(ne, fadj, badj, nothing)
75+
BipartiteGraph(ne::Integer, fadj::AbstractVector, badj::Union{AbstractVector}=nothing) = BipartiteGraph(ne, fadj, badj, nothing)
7676

7777
"""
7878
```julia
@@ -84,7 +84,9 @@ Test whether two [`BipartiteGraph`](@ref)s are equal.
8484
function Base.isequal(bg1::BipartiteGraph{T}, bg2::BipartiteGraph{T}) where {T<:Integer}
8585
iseq = (bg1.ne == bg2.ne)
8686
iseq &= (bg1.fadjlist == bg2.fadjlist)
87-
iseq &= (bg1.badjlist == bg2.badjlist)
87+
if bg1.badjlist !== nothing && bg2.badjlist !== nothing
88+
iseq &= (bg1.badjlist == bg2.badjlist)
89+
end
8890
iseq
8991
end
9092

@@ -93,16 +95,16 @@ $(SIGNATURES)
9395
9496
Build an empty `BipartiteGraph` with `nsrcs` sources and `ndsts` destinations.
9597
"""
96-
function BipartiteGraph(nsrcs::T, ndsts::T; metadata=nothing) where T
98+
function BipartiteGraph(nsrcs::T, ndsts::T, backedge::Val{B}=Val(true); metadata=nothing) where {T,B}
9799
fadjlist = map(_->T[], 1:nsrcs)
98-
badjlist = map(_->T[], 1:ndsts)
100+
badjlist = B ? map(_->T[], 1:ndsts) : nothing
99101
BipartiteGraph(0, fadjlist, badjlist, metadata)
100102
end
101103

102104
Base.eltype(::Type{<:BipartiteGraph{I}}) where I = I
103105
function Base.empty!(g::BipartiteGraph)
104106
foreach(empty!, g.fadjlist)
105-
foreach(empty!, g.badjlist)
107+
g.badjlist === nothing || foreach(empty!, g.badjlist)
106108
g.ne = 0
107109
if g.metadata !== nothing
108110
foreach(empty!, g.metadata)
@@ -111,17 +113,22 @@ function Base.empty!(g::BipartiteGraph)
111113
end
112114
Base.length(::BipartiteGraph) = error("length is not well defined! Use `ne` or `nv`.")
113115

116+
@noinline throw_no_back_edges() = throw(ArgumentError("The graph has no back edges."))
117+
114118
if isdefined(LightGraphs, :has_contiguous_vertices)
115119
LightGraphs.has_contiguous_vertices(::Type{<:BipartiteGraph}) = false
116120
end
117121
LightGraphs.is_directed(::Type{<:BipartiteGraph}) = false
118122
LightGraphs.vertices(g::BipartiteGraph) = (𝑠vertices(g), 𝑑vertices(g))
119123
𝑠vertices(g::BipartiteGraph) = axes(g.fadjlist, 1)
120-
𝑑vertices(g::BipartiteGraph) = axes(g.badjlist, 1)
124+
𝑑vertices(g::BipartiteGraph) = g.badjlist === nothing ? throw_no_back_edges() : axes(g.badjlist, 1)
121125
has_𝑠vertex(g::BipartiteGraph, v::Integer) = v in 𝑠vertices(g)
122126
has_𝑑vertex(g::BipartiteGraph, v::Integer) = v in 𝑑vertices(g)
123127
𝑠neighbors(g::BipartiteGraph, i::Integer, with_metadata::Val{M}=Val(false)) where M = M ? zip(g.fadjlist[i], g.metadata[i]) : g.fadjlist[i]
124-
𝑑neighbors(g::BipartiteGraph, j::Integer, with_metadata::Val{M}=Val(false)) where M = M ? zip(g.badjlist[j], (g.metadata[i][j] for i in g.badjlist[j])) : g.badjlist[j]
128+
function 𝑑neighbors(g::BipartiteGraph, j::Integer, with_metadata::Val{M}=Val(false)) where M
129+
g.badjlist === nothing && throw_no_back_edges()
130+
M ? zip(g.badjlist[j], (g.metadata[i][j] for i in g.badjlist[j])) : g.badjlist[j]
131+
end
125132
LightGraphs.ne(g::BipartiteGraph) = g.ne
126133
LightGraphs.nv(g::BipartiteGraph) = sum(length, vertices(g))
127134
LightGraphs.edgetype(g::BipartiteGraph{I}) where I = BipartiteEdge{I}
@@ -157,14 +164,16 @@ function LightGraphs.add_edge!(g::BipartiteGraph, edge::BipartiteEdge, md=NO_MET
157164
end
158165

159166
g.ne += 1
160-
@inbounds list = badjlist[d]
161-
index = searchsortedfirst(list, s)
162-
insert!(list, index, s)
167+
if badjlist !== nothing
168+
@inbounds list = badjlist[d]
169+
index = searchsortedfirst(list, s)
170+
insert!(list, index, s)
171+
end
163172
return true # edge successfully added
164173
end
165174

166175
function LightGraphs.add_vertex!(g::BipartiteGraph{T}, type::VertType) where T
167-
if type === DST
176+
if type === DST && g.badjlist !== nothing
168177
push!(g.badjlist, T[])
169178
elseif type === SRC
170179
push!(g.fadjlist, T[])

0 commit comments

Comments
 (0)