Skip to content

Commit f1a8bb5

Browse files
2 parents feaaa4a + 89b05b0 commit f1a8bb5

File tree

4 files changed

+34
-41
lines changed

4 files changed

+34
-41
lines changed

src/abstractmultilayerdigraph.jl

Lines changed: 17 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,3 @@
1-
# ne
2-
# has_edge
3-
# edges
4-
51
"""
62
AbstractMultilayerDiGraph{T,U} <: AbstractMultilayerGraph{T,U}
73
@@ -48,7 +44,6 @@ function Graphs.rem_vertex!(mg::AbstractMultilayerDiGraph, V::MultilayerVertex)
4844

4945
# Get the v corresponding to V, delete the association and replace it with a MissingVertex. Also substitute the metadata with an empty NamedTuple
5046
v = get_v(mg, V)
51-
5247
forward_halfedges_to_be_deleted = mg.fadjlist[v]
5348

5449
# Loop over the halfedges to be removed in `forward_halfedges_to_be_deleted`, get their v and remove halfedges to `V` in their corresponding arrays
@@ -100,7 +95,6 @@ function Graphs.rem_vertex!(mg::AbstractMultilayerDiGraph, V::MultilayerVertex)
10095
delete!(mg.v_V_associations, v)
10196
delete!(mg.v_metadata_dict, v)
10297
end
103-
10498
return true
10599

106100
end
@@ -112,11 +106,11 @@ end
112106
Return true if `mg` has edge between the `src` and `dst` (does not check edge or vertex metadata).
113107
"""
114108
function Graphs.has_edge(mg::M, src::T, dst::T) where { T,M <: AbstractMultilayerDiGraph{T}}
115-
109+
# Returns true if src is a vertex of mg
116110
has_vertex(mg,src) || return false
111+
# Returns true if dst is a vertex of mg
117112
has_vertex(mg,dst) || return false
118113

119-
120114
halfedges_from_src = mg.fadjlist[src]
121115
halfedges_to_dst = mg.badjlist[dst]
122116

@@ -127,57 +121,56 @@ function Graphs.has_edge(mg::M, src::T, dst::T) where { T,M <: AbstractMultilaye
127121
srcs_v = get_v.(Ref(mg), vertex.(halfedges_to_dst))
128122
return src in srcs_v
129123
end
130-
131124
end
132125

133-
134126
"""
135127
set_weight!(mg::M, src::MultilayerVertex{L1}, dst::MultilayerVertex{L2}, weight::U) where {L1 <: Symbol, L2 <: Symbol, T,U, M <: AbstractMultilayerGraph{T,U}}
136128
137129
Set the weight of the edge between `src` and `dst` to `weight`. Return true if succeeds (i.e. if the edge exists and the underlying graph chosen for the Layer/Interlayer where the edge lies is weighted under the `IsWeighted` trait).
138130
"""
139131
function set_weight!(mg::M, src::MultilayerVertex, dst::MultilayerVertex, weight::U) where { T,U, M <: AbstractMultilayerDiGraph{T,U}}
132+
# Get the subgraph descriptor for the layer containing both src and dst
140133
descriptor = get_subgraph_descriptor(mg, layer(src), layer(dst))
134+
# Check if the subgraph is weighted
141135
is_weighted(descriptor.null_graph) || return false
136+
# Check if an edge exists between src and dst
142137
has_edge(mg, src, dst) || return false
143-
138+
# Get the halfedge from src to dst
144139
halfedges_from_src = mg.fadjlist[get_v(mg, src)]
145140
halfedge_from_src = halfedges_from_src[findfirst(he -> vertex(he) == dst, halfedges_from_src)]
141+
# Set the weight of the halfedge from src to dst
146142
halfedge_from_src.weight = weight
147-
143+
# Get the halfedge from dst to src
148144
halfedges_to_dst = mg.badjlist[get_v(mg, dst)]
149145
halfedge_to_dst = halfedges_to_dst[findfirst(he -> vertex(he) == src, halfedges_to_dst)]
146+
# Set the weight of the halfedge from dst to src
150147
halfedge_to_dst.weight = weight
151-
152148
return true
153-
154149
end
155150

156-
157-
158151
"""
159152
set_metadata!(mg::M, src::MultilayerVertex{L1}, dst::MultilayerVertex{L2}, metadata::U) where {L1 <: Symbol, L2 <: Symbol, T,U, M <: AbstractMultilayerGraph{T,U}}
160153
161154
Set the metadata of the edge between `src` and `dst` to `metadata`. Return true if succeeds (i.e. if the edge exists and the underlying graph chosen for the Layer/Interlayer where the edge lies supports metadata at the edge level under the `IsMeta` trait).
162155
"""
163156
function set_metadata!(mg::M, src::MultilayerVertex, dst::MultilayerVertex, metadata::Union{Tuple, NamedTuple}) where M <: AbstractMultilayerDiGraph
157+
# Get the subgraph descriptor that corresponds to the layer of src and dst
164158
descriptor = get_subgraph_descriptor(mg, layer(src), layer(dst))
159+
# If the subgraph descriptor's null graph is true, then the edge does not exist
165160
is_meta(descriptor.null_graph) || return false
161+
# If the edge does not exist, return false
166162
has_edge(mg, src, dst) || return false
167-
163+
# Set the halfedge from src to dst
168164
halfedges_from_src = mg.fadjlist[get_v(mg, src)]
169165
halfedge_from_src = halfedges_from_src[findfirst(he -> vertex(he) == dst, halfedges_from_src)]
170166
halfedge_from_src.metadata = metadata
171-
167+
# Set the halfedge from dst to src
172168
halfedges_to_dst = mg.badjlist[get_v(mg, dst)]
173169
halfedge_to_dst = halfedges_to_dst[findfirst(he -> vertex(he) == src, halfedges_to_dst)]
174170
halfedge_to_dst.metadata = metadata
175-
176171
return true
177-
178172
end
179173

180-
181174
# Overloads that make AbstractMultilayerDiGraph an extension of Graphs.jl. These are all well-inferred .
182175
"""
183176
edges(mg::M) where {T,U,M<:AbstractMultilayerDiGraph{T,U}}
@@ -389,18 +382,19 @@ end
389382
return _inneighbors
390383
end
391384

392-
393-
# function get_overlay_monoplex_graph end #approach taken from https://github.com/JuliaGraphs/Graphs.jl/blob/7152d540631219fd51c43ab761ec96f12c27680e/src/core.jl#L124
394385
"""
395386
get_overlay_monoplex_graph(mg::M) where {M<: AbstractMultilayerDiGraph}
396387
Get overlay monoplex graph (i.e. the graph that has the same nodes as `mg` but the link between node `i` and `j` has weight equal to the sum of all edges weights between the various vertices representing `i` and `j` in `mg`, accounting for both layers and interlayers). See [De Domenico et al. (2013)](https://doi.org/10.1103/PhysRevX.3.041022).
397388
"""
398389
function get_overlay_monoplex_graph(mg::M) where {T,U,M<:AbstractMultilayerDiGraph{T,U}}
390+
# Convert the multilayer graph to a weight tensor
399391
wgt = weight_tensor(mg).array
392+
# Sum the weights for each edge in the multilayer graph
400393
projected_overlay_adjacency_matrix = sum([
401394
wgt[:, :, i, i] for i in 1:size(wgt, 3)
402395
])
403396
return SimpleWeightedDiGraph{T,U}(
404397
projected_overlay_adjacency_matrix
405398
)
399+
# Approach taken from https://github.com/JuliaGraphs/Graphs.jl/blob/7152d540631219fd51c43ab761ec96f12c27680e/src/core.jl#L124
406400
end

src/subgraphs/interlayer.jl

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ end
8181
8282
) where {T<:Integer, U <: Real, G<:AbstractGraph{T}}
8383
84-
Internal constructor used with InterlayerDescriptor
84+
Internal constructor used with InterlayerDescriptor.
8585
"""
8686
function _Interlayer(
8787
layer_1_multilayervertices::Vector{<: MultilayerVertex},
@@ -336,7 +336,7 @@ multiplex_interlayer(
336336
forbidden_edges::Vector{NTuple{2, MultilayerVertex}}
337337
) where {T <: Union{ <: Integer, AbstractVertex}, G <: AbstractGraph{T}
338338
339-
Internal method for multiplex_interlayer
339+
Internal method for multiplex_interlayer.
340340
"""
341341
function _multiplex_interlayer(
342342
layer_1_multilayervertices::Vector{MultilayerVertex{L1}},
@@ -433,9 +433,7 @@ function _empty_interlayer(
433433
name::Symbol = Symbol("interlayer_$(layer_1.name)_$(layer_2.name)")
434434
) where {L1, L2, T<:Integer, U <: Real, G<:AbstractGraph{T}}
435435

436-
437436
edge_list = MultilayerEdge{U}[]
438-
439437
descriptor = InterlayerDescriptor(L1, L2, null_graph, weighttype; default_edge_weight = default_edge_weight, default_edge_metadata = default_edge_metadata, transfer_vertex_metadata = transfer_vertex_metadata, name = name)
440438

441439
return _Interlayer(
@@ -452,13 +450,15 @@ end
452450
Check if `graph`, whose vertices are interpreted via `v_V_associations` can be the underlying bipartite graph of an Interlayer graph.
453451
"""
454452
function is_interlayer_bipartite(graph::G, v_V_associations::Bijection{T, MultilayerVertex}) where {T, G <: AbstractGraph{T}}
455-
456453
layers = unique([mv.layer for mv in image(v_V_associations)])
457454
# If it is an empty interlayer, we assume it is bipartite
458455
length(layers) == 0 && return true
459456
length(layers) == 2 || throw(ErrorException("The interlayer cannot be bipartite since more than two layers are involved. Found $layers in v_V_associations."))
457+
# This loop iterates through all edges of the graph
460458
for edge in edges(graph)
459+
# This if statement checks if the source and destination of the edge are on the same layer
461460
if !(v_V_associations[src(edge)].layer != v_V_associations[dst(edge)].layer)
461+
# If they are, the graph is not a valid layering
462462
return false
463463
end
464464
end
@@ -478,7 +478,9 @@ function is_multiplex_interlayer(interlayer::Interlayer)
478478
end
479479
return true
480480
else
481+
# Loop through all nodes in both layers.
481482
for node in intersect(interlayer.layer_1_nodes, interlayer.layer_2_nodes)
483+
# Check if there is an edge between the nodes in both layers.
482484
has_edge(interlayer, MV(node, interlayer.layer_1), MV(node, interlayer.layer_2)) || return false
483485
end
484486
return true
@@ -490,7 +492,7 @@ end
490492
491493
Return `true` if `n` is a `Node` of `interlayer`.
492494
"""
493-
has_node( interlayer::Interlayer, n::Node ) = n in nodes(interlayer.layer_1) || n in nodes(interlayer.layer_2)
495+
has_node(interlayer::Interlayer, n::Node ) = n in nodes(interlayer.layer_1) || n in nodes(interlayer.layer_2)
494496

495497

496498
"""
@@ -504,7 +506,6 @@ Graphs.has_vertex(interlayer::Interlayer, mv::MultilayerVertex) = get_bare_mv(mv
504506
"""
505507
"""
506508
function Graphs.add_edge!(interlayer::In, src::MultilayerVertex, dst::MultilayerVertex, args...; kwargs...) where { In <: Interlayer}
507-
508509
src_bare = get_bare_mv(src)
509510
dst_bare = get_bare_mv(dst)
510511
!has_vertex(interlayer, src) && throw( ErrorException( "Vertex $(src) does not belong to the interlayer."))
@@ -545,10 +546,9 @@ end
545546
Base.getproperty(interlayer::In, f::Symbol) where { In <: Interlayer}
546547
"""
547548
function Base.getproperty(interlayer::In, f::Symbol) where {In<:Interlayer}
548-
549549
if f (:descriptor, :graph, :v_V_associations)
550-
Base.getfield(interlayer, f)
551-
elseif f (:name, :layer_1, :layer_2, :null_graph, :default_edge_weight, :default_edge_metadata, :transfer_vertex_metadata) # edge_weight_function:, :edge_metadata_function,
550+
Base.getfield(interlayer, f)
551+
elseif f (:name, :layer_1, :layer_2, :null_graph, :default_edge_weight, :default_edge_metadata, :transfer_vertex_metadata)
552552
Base.getfield(interlayer.descriptor, f)
553553
elseif f == :edge_list
554554
edges(interlayer)
@@ -578,19 +578,19 @@ end
578578
"""
579579
get_symmetric_interlayer(interlayer::In; symmetric_interlayer_name::String) where{T,U,G, In <: Interlayer{T,U,G}}
580580
581-
Return the `Interlayer` corresponding to `interlayer` where `layer_1` and `layer_2` are swapped. Its name will be `symmetric_interlayer_name` (defaults to `interlayer_(interlayer.layer_2)_(interlayer.layer_1)` ).
581+
Return the `Interlayer` corresponding to `interlayer` where `layer_1` and `layer_2` are swapped. Its name will be `symmetric_interlayer_name` (defaults to `interlayer_(interlayer.layer_2)_(interlayer.layer_1)`).
582582
"""
583583
function get_symmetric_interlayer(
584584
interlayer::In;
585585
symmetric_interlayer_name::String = String(interlayer.name) * "_rev"
586586
) where {T,U,G,In<:Interlayer{T,U,G}}
587-
587+
# Create a symmetric interlayer descriptor
588588
symmetric_descriptor = InterlayerDescriptor(Symbol(symmetric_interlayer_name), interlayer.layer_2, interlayer.layer_1, interlayer.null_graph, interlayer.default_edge_weight, interlayer.default_edge_metadata, interlayer.transfer_vertex_metadata, U)
589-
589+
# Create a symmetrized interlayer with the symmetric descriptor
590590
symmetrized_interlayer = Interlayer(symmetric_descriptor, interlayer.graph, interlayer.v_V_associations)
591-
591+
# Recompute the interlayer, using the layer 1 and layer 2 vertices from the original interlayer
592592
recompute_interlayer!(symmetrized_interlayer, symmetrized_interlayer.layer_1_bare_multilayer_vertices, symmetrized_interlayer.layer_2_bare_multilayer_vertices)
593-
593+
# Return the symmetrized interlayer
594594
return symmetrized_interlayer
595595
end
596596

src/vertices/abstractgraphvertex.jl

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,2 @@
11
abstract type AbstractGraphVertex{G <: AbstractGraph} end
2-
3-
struct LayerVertex{L} <: AbstractGraphVertex{G} end
2+
struct LayerVertex{L} <: AbstractGraphVertex{G} end

src/vertices/multilayervertex.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,5 +112,5 @@ function compare_multilayervertices(V1::MultilayerVertex, V2::MultilayerVertex;
112112
end
113113

114114
# Console print utilities
115-
to_string( x::M) where {S , M <: MultilayerVertex{S}} = "MV($(x.node), :$(x.layer), $(x.metadata))" #{:$S}
115+
to_string( x::M) where {S , M <: MultilayerVertex{S}} = "MV($(x.node), :$(x.layer), $(x.metadata))"
116116
Base.show(io::IO, x::MultilayerVertex) = print(io, to_string(x))

0 commit comments

Comments
 (0)