Skip to content

Commit 438dedc

Browse files
InterdisciplinaryPhysicsTeampitmonticoneClaudMor
committed
Update
Modified add_vertex! behavior so that it may automatically add the underlying node, should it be absent, instead of erroring Refactored multilayer(di)graph.jl's code Fixed a bug in layer.jl that prevented empty layers from being easily instantiated Co-Authored-By: Pietro Monticone <38562595+pitmonticone@users.noreply.github.com> Co-Authored-By: Claudio Moroni <43729990+ClaudMor@users.noreply.github.com>
1 parent 458deea commit 438dedc

File tree

8 files changed

+203
-187
lines changed

8 files changed

+203
-187
lines changed

docs/src/API.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -235,8 +235,7 @@ mv_vertices(mg::AbstractMultilayerGraph)
235235
mv_inneighbors(mg::AbstractMultilayerGraph, mv::MultilayerVertex)
236236
mv_outneighbors(mg::AbstractMultilayerGraph, mv::MultilayerVertex)
237237
mv_neighbors( mg::AbstractMultilayerGraph, mv::MultilayerVertex)
238-
add_vertex!(mg::M, V::MultilayerVertex) where {T, U, M <: AbstractMultilayerUGraph{T,U}}
239-
add_vertex!(mg::M, V::MultilayerVertex) where {T, U, M <: AbstractMultilayerDiGraph{T,U}}
238+
add_vertex!(mg::AbstractMultilayerGraph, mv::MultilayerVertex; add_node::Bool = true)
240239
rem_vertex!(mg::AbstractMultilayerUGraph, V::MultilayerVertex)
241240
rem_vertex!(mg::AbstractMultilayerDiGraph, V::MultilayerVertex)
242241
has_edge(mg::AbstractMultilayerGraph, edge::MultilayerEdge)

src/abstractmultilayerdigraph.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,11 @@ abstract type AbstractMultilayerDiGraph{T,U} <: AbstractMultilayerGraph{T,U} end
88
# Nodes
99
# Vertices
1010
"""
11-
add_vertex!(mg::M, V::MultilayerVertex) where {T, U, M <: AbstractMultilayerDiGraph{T,U}}
11+
add_vertex_specialized!(mg::M, V::MultilayerVertex) where {T, U, M <: AbstractMultilayerDiGraph{T,U}}
1212
1313
Add MultilayerVertex `V` to multilayer graph `mg`, provided that `node(V)` is a `Node` of `mg`. Return true if succeeds.
1414
"""
15-
function Graphs.add_vertex!(
15+
function add_vertex_specialized!(
1616
mg::M, V::MultilayerVertex
1717
) where {T,U,M<:AbstractMultilayerDiGraph{T,U}}
1818
!has_node(mg, V.node) && return false

src/abstractmultilayergraph.jl

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,20 @@ function set_metadata!(
168168
return true
169169
end
170170

171+
172+
"""
173+
add_vertex!(mg::AbstractMultilayerGraph, mv::MultilayerVertex; add_node::Bool = true)
174+
175+
Add MultilayerVertex `mv` to multilayer graph `mg`. If `add_node` is true and `node(mv)` is not already part of `mg`, then add `node(mv)` to `mg` before adding `mv` to `mg` instead of throwing an error.
176+
"""
177+
function Graphs.add_vertex!(mg::AbstractMultilayerGraph, mv::MultilayerVertex; add_node::Bool = true)
178+
_node = node(mv)
179+
if add_node && !has_node(mg, _node)
180+
add_node!(mg, _node)
181+
end
182+
add_vertex_specialized!(mg, mv)
183+
end
184+
171185
# Edges
172186
"""
173187
edgetype(::M) where {T,U,M<:AbstractMultilayerGraph{T,U}}

src/abstractmultilayerugraph.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,11 @@ abstract type AbstractMultilayerUGraph{T,U} <: AbstractMultilayerGraph{T,U} end
99

1010
# Vertices
1111
"""
12-
add_vertex!(mg::M, V::MultilayerVertex) where {T, U, M <: AbstractMultilayerUGraph{T,U}}
12+
add_vertex_specialized!(mg::M, V::MultilayerVertex) where {T, U, M <: AbstractMultilayerUGraph{T,U}}
1313
1414
Add MultilayerVertex `V` to multilayer graph `mg`, provided that `node(V)` is a `Node` of `mg`. Return true if succeeds.
1515
"""
16-
function Graphs.add_vertex!(
16+
function add_vertex_specialized!(
1717
mg::M, V::MultilayerVertex
1818
) where {T,U,M<:AbstractMultilayerUGraph{T,U}}
1919
!has_node(mg, node(V)) && return false

src/multilayerdigraph.jl

Lines changed: 84 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -54,88 +54,7 @@ function MultilayerDiGraph(
5454
return multilayerdigraph
5555
end
5656

57-
# General MultilayerDiGraph Utilities
58-
fadjlist(mg::MultilayerDiGraph) = mg.fadjlist
59-
badjlist(mg::MultilayerDiGraph) = mg.badjlist
6057

61-
# Nodes
62-
63-
# Vertices
64-
65-
# Edges
66-
"""
67-
add_edge!(mg::M, me::E) where {T,U, M <: AbstractMultilayerDiGraph{T,U}, E <: MultilayerEdge{ <: Union{U,Nothing}}}
68-
69-
Add MultilayerEdge `me` to the MultilayerDiGraph `mg`. Return true if succeeds, false otherwise.
70-
"""
71-
function Graphs.add_edge!(
72-
mg::M, me::E
73-
) where {T,U,M<:AbstractMultilayerDiGraph{T,U},E<:MultilayerEdge{<:Union{U,Nothing}}}
74-
_src = get_bare_mv(src(me))
75-
_dst = get_bare_mv(dst(me))
76-
has_vertex(mg, _src) ||
77-
throw(ErrorException("Vertex $_src does not belong to the multilayer graph."))
78-
has_vertex(mg, _dst) ||
79-
throw(ErrorException("Vertex $_dst does not belong to the multilayer graph."))
80-
81-
# Add edge to `edge_dict`
82-
src_V_idx = get_v(mg, _src)
83-
dst_V_idx = get_v(mg, _dst)
84-
85-
_weight = isnothing(weight(me)) ? one(U) : weight(me)
86-
_metadata = metadata(me)
87-
88-
if !has_edge(mg, _src, _dst)
89-
push!(mg.fadjlist[src_V_idx], HalfEdge(_dst, _weight, _metadata))
90-
push!(mg.badjlist[dst_V_idx], HalfEdge(_src, _weight, _metadata))
91-
else
92-
return false
93-
end
94-
#= else
95-
push!(mg.fadjlist[src_V_idx], HalfEdge(_dst, _weight, _metadata))
96-
end =#
97-
98-
return true
99-
end
100-
101-
"""
102-
rem_edge!(mg::MultilayerDiGraph, src::MultilayerVertex, dst::MultilayerVertex)
103-
104-
Remove edge from `src` to `dst` from `mg`. Return true if succeeds, false otherwise.
105-
"""
106-
function Graphs.rem_edge!(
107-
mg::MultilayerDiGraph, src::MultilayerVertex, dst::MultilayerVertex
108-
)
109-
110-
# Perform routine checks
111-
has_vertex(mg, src) ||
112-
throw(ErrorException("Vertex $_src does not belong to the multilayer graph."))
113-
has_vertex(mg, dst) ||
114-
throw(ErrorException("Vertex $_dst does not belong to the multilayer graph."))
115-
116-
has_edge(mg, src, dst) || return false
117-
118-
src_V_idx = get_v(mg, src)
119-
dst_V_idx = get_v(mg, dst)
120-
121-
_src = get_bare_mv(src)
122-
_dst = get_bare_mv(dst)
123-
124-
src_idx_tbr = findfirst(halfedge -> vertex(halfedge) == _dst, mg.fadjlist[src_V_idx])
125-
deleteat!(mg.fadjlist[src_V_idx], src_idx_tbr)
126-
127-
dst_idx_tbr = findfirst(halfedge -> halfedge.vertex == _src, mg.badjlist[dst_V_idx])
128-
deleteat!(mg.badjlist[dst_V_idx], dst_idx_tbr)
129-
130-
return true
131-
end
132-
133-
# Layers and Interlayers
134-
135-
# Graphs.jl's extensions
136-
137-
# Multilayer-specific methods
138-
# "empty graph" could be the correct way of calling a graph with no edges: https://math.stackexchange.com/questions/320859/what-is-the-term-for-a-graph-on-n-vertices-with-no-edges
13958
"""
14059
MultilayerDiGraph(
14160
empty_layers::Vector{<:Layer{T,U}},
@@ -286,6 +205,90 @@ function MultilayerDiGraph(
286205
)
287206
end
288207

208+
# General MultilayerDiGraph Utilities
209+
fadjlist(mg::MultilayerDiGraph) = mg.fadjlist
210+
badjlist(mg::MultilayerDiGraph) = mg.badjlist
211+
212+
# Nodes
213+
214+
# Vertices
215+
216+
# Edges
217+
"""
218+
add_edge!(mg::M, me::E) where {T,U, M <: AbstractMultilayerDiGraph{T,U}, E <: MultilayerEdge{ <: Union{U,Nothing}}}
219+
220+
Add MultilayerEdge `me` to the MultilayerDiGraph `mg`. Return true if succeeds, false otherwise.
221+
"""
222+
function Graphs.add_edge!(
223+
mg::M, me::E
224+
) where {T,U,M<:AbstractMultilayerDiGraph{T,U},E<:MultilayerEdge{<:Union{U,Nothing}}}
225+
_src = get_bare_mv(src(me))
226+
_dst = get_bare_mv(dst(me))
227+
has_vertex(mg, _src) ||
228+
throw(ErrorException("Vertex $_src does not belong to the multilayer graph."))
229+
has_vertex(mg, _dst) ||
230+
throw(ErrorException("Vertex $_dst does not belong to the multilayer graph."))
231+
232+
# Add edge to `edge_dict`
233+
src_V_idx = get_v(mg, _src)
234+
dst_V_idx = get_v(mg, _dst)
235+
236+
_weight = isnothing(weight(me)) ? one(U) : weight(me)
237+
_metadata = metadata(me)
238+
239+
if !has_edge(mg, _src, _dst)
240+
push!(mg.fadjlist[src_V_idx], HalfEdge(_dst, _weight, _metadata))
241+
push!(mg.badjlist[dst_V_idx], HalfEdge(_src, _weight, _metadata))
242+
else
243+
return false
244+
end
245+
#= else
246+
push!(mg.fadjlist[src_V_idx], HalfEdge(_dst, _weight, _metadata))
247+
end =#
248+
249+
return true
250+
end
251+
252+
"""
253+
rem_edge!(mg::MultilayerDiGraph, src::MultilayerVertex, dst::MultilayerVertex)
254+
255+
Remove edge from `src` to `dst` from `mg`. Return true if succeeds, false otherwise.
256+
"""
257+
function Graphs.rem_edge!(
258+
mg::MultilayerDiGraph, src::MultilayerVertex, dst::MultilayerVertex
259+
)
260+
261+
# Perform routine checks
262+
has_vertex(mg, src) ||
263+
throw(ErrorException("Vertex $_src does not belong to the multilayer graph."))
264+
has_vertex(mg, dst) ||
265+
throw(ErrorException("Vertex $_dst does not belong to the multilayer graph."))
266+
267+
has_edge(mg, src, dst) || return false
268+
269+
src_V_idx = get_v(mg, src)
270+
dst_V_idx = get_v(mg, dst)
271+
272+
_src = get_bare_mv(src)
273+
_dst = get_bare_mv(dst)
274+
275+
src_idx_tbr = findfirst(halfedge -> vertex(halfedge) == _dst, mg.fadjlist[src_V_idx])
276+
deleteat!(mg.fadjlist[src_V_idx], src_idx_tbr)
277+
278+
dst_idx_tbr = findfirst(halfedge -> halfedge.vertex == _src, mg.badjlist[dst_V_idx])
279+
deleteat!(mg.badjlist[dst_V_idx], dst_idx_tbr)
280+
281+
return true
282+
end
283+
284+
# Layers and Interlayers
285+
286+
# Graphs.jl's extensions
287+
288+
# Multilayer-specific methods
289+
# "empty graph" could be the correct way of calling a graph with no edges: https://math.stackexchange.com/questions/320859/what-is-the-term-for-a-graph-on-n-vertices-with-no-edges
290+
291+
289292
# Base overloads
290293
"""
291294
Base.getproperty(mg::M, f::Symbol) where { M <: MultilayerDiGraph }

0 commit comments

Comments
 (0)