Skip to content

Commit 17467bb

Browse files
InterdisciplinaryPhysicsTeampitmonticoneClaudMor
committed
Update
Co-Authored-By: Pietro Monticone <38562595+pitmonticone@users.noreply.github.com> Co-Authored-By: Claudio Moroni <43729990+ClaudMor@users.noreply.github.com>
1 parent ec8dc55 commit 17467bb

File tree

7 files changed

+206
-387
lines changed

7 files changed

+206
-387
lines changed

README.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,9 @@ In the package documentation you can find a [tutorial](https://juliagraphs.org/M
5454
- [ ] [Implement more general configuration models / graph generators](https://github.com/JuliaGraphs/MultilayerGraphs.jl/issues/33);
5555
- [ ] [Implement graph of layers](https://github.com/JuliaGraphs/MultilayerGraphs.jl/issues/34);
5656
- [ ] [Implement projected monoplex and overlay graphs](https://github.com/JuliaGraphs/MultilayerGraphs.jl/issues/35);
57-
- [ ] [Implement more default multilayer graphs](https://github.com/JuliaGraphs/MultilayerGraphs.jl/issues/36) (e.g. multiplex graphs).
57+
- [ ] [Implement more default multilayer graphs](https://github.com/JuliaGraphs/MultilayerGraphs.jl/issues/36) (e.g. multiplex graphs);
58+
- [ ] [Implement configuration models / graph generators for interlayers](https://github.com/JuliaGraphs/MultilayerGraphs.jl/issues/46);
59+
- [ ] [Relax the requirement of same `T` and `U` for all `Layer`s and `Interlayer`s that are meant to constitute a `Multilayer(Di)Graph`](https://github.com/JuliaGraphs/MultilayerGraphs.jl/issues/53).
5860

5961
## How to Contribute
6062

docs/src/API.md

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,16 @@ Layer(
5050
allow_self_loops::Bool = false
5151
) where {T<:Integer, U <: Real, G<:AbstractGraph{T}}
5252
53+
layer_simplegraph
54+
layer_simpledigraph
55+
layer_simpleweightedgraph
56+
layer_simpleweighteddigraph
57+
layer_metadigraph
58+
layer_valgraph
59+
layer_valoutdigraph
60+
layer_valdigraph
61+
layer_metagraph
62+
5363
has_node(layer::Layer, n::Node)
5464
add_vertex!(layer::Layer, mv::MultilayerVertex)
5565
add_vertex!(layer::L, n::Node, args...; kwargs...) where {T, L <: Layer{T}}
@@ -80,6 +90,23 @@ Interlayer(
8090
transfer_vertex_metadata::Bool = false
8191
) where {T<:Integer, U <: Union{Nothing, <: Real}, G<:AbstractGraph{T}}
8292
93+
layer_simplegraph(
94+
name::Symbol,
95+
vertices::Union{Vector{MultilayerVertex{nothing}},Vector{Node}},
96+
edge_list::Union{Vector{<:MultilayerEdge}, Vector{NTuple{2, MultilayerVertex{nothing}}}};
97+
vertextype::Type{T} = Int64,
98+
weighttype::Type{U} = Float64
99+
) where {T<:Integer,U<:Real}
100+
101+
interlayer_simpleweightedgraph
102+
interlayer_metagraph
103+
interlayer_valgraph
104+
interlayer_simpledigraph
105+
interlayer_simpleweighteddigraph
106+
interlayer_metadigraph
107+
interlayer_valoutdigraph
108+
interlayer_valdigraph
109+
83110
84111
multiplex_interlayer(
85112
layer_1::Layer{T,U},

docs/src/index.md

Lines changed: 41 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -128,19 +128,19 @@ As said before, to define a multilayer graph we need to specify its layers and i
128128

129129
```julia
130130
Layer(
131-
name::Symbol, # The name of the layer
132-
vertices::Vector{ <: MultilayerVertex}, # The `MultilayerVertex`s of the Layer
133-
ne::Int64, # The number of edges of the Layer
134-
null_graph::G, # The Layer's underlying graph type, which must be passed as a null graph. If it is not, an error will be thrown.
135-
weighttype::Type{U}; # The type of the `MultilayerEdge` weights (even when the underlying Layer's graph is unweighted, we need to specify a weight type since the `MultilayerGraph`s will always be weighted)
136-
default_vertex_metadata::Function = mv -> NamedTuple(), # Function that takes a `MultilayerVertex` and returns a `Tuple` or a `NamedTuple` containing the vertex metadata. defaults to `mv -> NamedTuple()`;
137-
default_edge_weight::Function = (src, dst) -> nothing, # Function that takes a pair of `MultilayerVertex`s and returns an edge weight of type `weighttype` or `nothing` (which is compatible with unweighted underlying graphs and corresponds to `one(weighttype)` for weighted underlying graphs). Defaults to `(src, dst) -> nothing`;
138-
default_edge_metadata::Function = (src, dst) -> NamedTuple(), # Function that takes a pair of `MultilayerVertex`s and returns a `Tuple` or a `NamedTuple` containing the edge metadata, that will be called when `add_edge!(mg,src,dst, args...; kwargs...)` is called without the `metadata` keyword argument, and when generating the edges in this constructor. Defaults to `(src, dst) -> NamedTuple()`;
139-
allow_self_loops::Bool = false # whether to allow self loops to be generated or not. Defaults to `false`.
140-
)
131+
name::Symbol, # The name of the layer
132+
vertices::Union{Vector{MultilayerVertex{nothing}},Vector{Node}}, # The `MultilayerVertex`s of the Layer. May be a vector of `MultilayerVertex{nothing}`s or a vector of `Node`s. In the latter case, the metadata of the `MultilayerVertex` to be added are computed via the `default_vertex_metadata` before the vertex is added (the function will act on each element of `MV.(vertices)`);
133+
ne::Int64, # The number of edges of the Layer
134+
null_graph::AbstractGraph{T}, # The Layer's underlying graph type, which must be passed as a null graph. If it is not, an error will be thrown.
135+
weighttype::Type{U}; # The type of the `MultilayerEdge` weights (even when the underlying Layer's graph is unweighted, we need to specify a weight type since the `MultilayerGraph`s will always be weighted)
136+
default_vertex_metadata::Function = mv -> NamedTuple(), # Function that takes a `MultilayerVertex` and returns a `Tuple` or a `NamedTuple` containing the vertex metadata. Defaults to `mv -> NamedTuple()`;
137+
default_edge_weight::Function = (src, dst) -> nothing, # Function that takes a pair of `MultilayerVertex`s and returns an edge weight of type `weighttype` or `nothing` (which is compatible with unweighted underlying graphs and corresponds to `one(weighttype)` for weighted underlying graphs). Defaults to `(src, dst) -> nothing`;
138+
default_edge_metadata::Function = (src, dst) -> NamedTuple(), # Function that takes a pair of `MultilayerVertex`s and returns a `Tuple` or a `NamedTuple` containing the edge metadata, that will be called when `add_edge!(mg,src,dst, args...; kwargs...)` is called without the `metadata` keyword argument, and when generating the edges in this constructor. Defaults to `(src, dst) -> NamedTuple()`;
139+
allow_self_loops::Bool = false # whether to allow self loops to be generated or not. Defaults to `false`.
140+
) where {T<:Integer, U<: Real}
141141
```
142142

143-
A `Layer` is considered "weighted" if its underlying graph (`null_graph` argument) has been given the `IsWeighted` trait (traits throughout this package are implemented via [SimpleTraits.jl](https://github.com/mauro3/SimpleTraits.jl), just like Graphs.jl does). Since one may at any moment add a new weighted `Layer` to a `MultilayerGraph` (see below for details), the latter is always considered a "weighted graph", so it is given the `IsWeighted` trait. Thus, all `Layer`s and `Interlayer`s (collectively named "subgraphs" hereafter) must specify their `weighttype` as the last argument of their constructor, so the user may debug their weight matrices ([`weights(subgraph::AbstractSubGraph)`](@ref)) immediately after construction. As better specified below, all subgraphs that are meant to be part of the same `MultilayerGraph` must have the same `weighttype`.
143+
A `Layer` is considered "weighted" if its underlying graph (`null_graph` argument) has been given the `IsWeighted` trait (traits throughout this package are implemented via [SimpleTraits.jl](https://github.com/mauro3/SimpleTraits.jl), just like Graphs.jl does). Since one may at any moment add a new weighted `Layer` to a `MultilayerGraph` (see below for details), the latter is always considered a "weighted graph", so it is given the `IsWeighted` trait. Thus, all `Layer`s and `Interlayer`s (collectively named "subgraphs" hereafter) must specify their `weighttype` as the last argument of their constructor, so the user may debug their weight matrices ([`weights(subgraph::AbstractSubGraph)`](@ref)) immediately after construction. As better specified below, all subgraphs that are meant to be part of the same `MultilayerGraph` must have the same `weighttype`. Moreover, also the vertex type `T` (i.e. the internal representation of vertices) should be the same.
144144

145145
Before instantiating `Layer`s, we define an utility function to ease randomization:
146146

@@ -154,18 +154,25 @@ end
154154

155155
# Utility function that returns two vertices of a Layer that are not adjacent.
156156
function _get_srcmv_dstmv_layer(layer::Layer)
157-
158-
mvs = get_bare_mv.(collect(mv_vertices(layer)))
159-
160-
src_mv = nothing
161-
_collection = []
162-
163-
while isempty(_collection)
164-
src_mv = rand(mvs)
165-
_collection = setdiff(Set(mvs), Set(vcat(get_bare_mv.(mv_outneighbors(layer, src_mv)), src_mv ) ) )
166-
end
167-
168-
dst_mv = get_bare_mv(rand(_collection))
157+
mvs = MultilayerGraphs.get_bare_mv.(collect(mv_vertices(layer)))
158+
159+
src_mv_idx = findfirst(mv -> !isempty(setdiff(
160+
Set(mvs),
161+
Set(
162+
vcat(MultilayerGraphs.get_bare_mv.(mv_outneighbors(layer, mv)), mv)
163+
),
164+
)), mvs)
165+
166+
src_mv = mvs[src_mv_idx]
167+
168+
_collection = setdiff(
169+
Set(mvs),
170+
Set(
171+
vcat(MultilayerGraphs.get_bare_mv.(mv_outneighbors(layer, src_mv)), src_mv)
172+
),
173+
)
174+
175+
dst_mv = MultilayerGraphs.get_bare_mv(rand(_collection))
169176

170177
return mvs, src_mv, dst_mv
171178
end
@@ -219,7 +226,10 @@ layer_vg = Layer( :layer_vg,
219226
layers = [layer_sg, layer_swg, layer_mg, layer_vg]
220227
```
221228

222-
The API that inspects and modifies `Layer`s will be shown below together with that of `Interlayer`s, since they are usually the same. There are of course other constructors that you may discover by typing `?Layer` in the console.
229+
The API that inspects and modifies `Layer`s will be shown below together with that of `Interlayer`s, since they are usually the same. There are of course other constructors that you may discover by reading the [API](@ref subgraphs_eu). They include:
230+
231+
1. Constructors that exempt the user from having to explictly specify the `null_graph`, at the cost of some flexibility;
232+
2. Constructors that allow for a configuration model-like specifications.
223233

224234
### Interlayers
225235

@@ -264,7 +274,7 @@ Interlayer(
264274
default_edge_weight::Function = (x,y) -> nothing, # Function that takes a pair of `MultilayerVertex`s and returns an edge weight of type `weighttype` or `nothing` (which is compatible with unweighted underlying graphs and corresponds to `one(weighttype)` for weighted underlying graphs). Defaults to `(src, dst) -> nothing`;
265275
default_edge_metadata::Function = (x,y) -> NamedTuple(), # Function that takes a pair of `MultilayerVertex`s and returns a `Tuple` or a `NamedTuple` containing the edge metadata, that will be called when `add_edge!(mg,src,dst, args...; kwargs...)` is called without the `metadata` keyword argument, and when generating the edges in this constructor. Defaults to `(src, dst) -> NamedTuple()`;
266276
name::Symbol = Symbol("interlayer_$(layer_1.name)_$(layer_2.name)"), # The name of the Interlayer. Defaults to Symbol("interlayer_(layer_1.name)_(layer_2.name)");
267-
transfer_vertex_metadata::Bool = false # if true, vertex metadata found in both connected layers are carried over to the vertices of the Interlayer. NB: not all choice of underlying graph may support this feature. Graphs types that don't support metadata or that pose limitations to it may result in errors.;
277+
transfer_vertex_metadata::Bool = false # If true, vertex metadata found in both connected layers are carried over to the vertices of the Interlayer. NB: not all choice of underlying graph may support this feature. Graphs types that don't support metadata or that pose limitations to it may result in errors.;
268278
)
269279
```
270280
We will build a few of random `Interlayer`s:
@@ -311,6 +321,8 @@ interlayer_empty_sg_vg = empty_interlayer( layer_sg,
311321
interlayers = [interlayer_sg_swg, interlayer_swg_mg, interlayer_mg_vg, interlayer_multiplex_sg_mg, interlayer_empty_sg_vg]
312322
```
313323

324+
There are of course other constructors that you may discover by reading the [API](@ref subgraphs_eu). They include constructors that exempt the user from having to explictly specify the `null_graph`, at the cost of some flexibility;
325+
314326
Next, we explore the API associated to modify and analyze `Layer`s and `Interlayer`s.
315327

316328
### Subgraphs API
@@ -619,7 +631,7 @@ Given all the `Layer`s and the `Interlayer`s, let's instantiate a multilayer gra
619631
```julia
620632
multilayergraph = MultilayerGraph( layers, # The (ordered) list of layers the multilayer graph will have
621633
interlayers; # The list of interlayers specified by the user. Note that the user does not need to specify all interlayers, as the unspecified ones will be automatically constructed using the indications given by the `default_interlayers_null_graph` and `default_interlayers_structure` keywords.
622-
default_interlayers_null_graph = SimpleGraph{vertextype}(), # Sets the underlying graph for the interlayers that are to be automatically specified. Defaults to `SimpleGraph{T}()`. See the `Layer` constructors for more information.
634+
default_interlayers_null_graph = SimpleGraph{vertextype}(), # Sets the underlying graph for the interlayers that are to be automatically specified. Defaults to `SimpleGraph{T}()`, where `T` is the `T` of all the `layers` and `interlayers`. See the `Layer` constructors for more information.
623635
default_interlayers_structure = "multiplex" # Sets the structure of the interlayers that are to be automatically specified. May be "multiplex" for diagonally coupled interlayers, or "empty" for empty interlayers (no edges). "multiplex". See the `Interlayer` constructors for more information.
624636
);
625637
```
@@ -867,7 +879,9 @@ Read a complete list of analytical methods exclusive to multilayer graphs in the
867879
- [Implement more general configuration models / graph generators](https://github.com/JuliaGraphs/MultilayerGraphs.jl/issues/33);
868880
- [Implement graph of layers](https://github.com/JuliaGraphs/MultilayerGraphs.jl/issues/34);
869881
- [Implement projected monoplex and overlay graphs](https://github.com/JuliaGraphs/MultilayerGraphs.jl/issues/35);
870-
- [Implement more default multilayer graphs](https://github.com/JuliaGraphs/MultilayerGraphs.jl/issues/36) (e.g. multiplex graphs).
882+
- [Implement more default multilayer graphs](https://github.com/JuliaGraphs/MultilayerGraphs.jl/issues/36) (e.g. multiplex graphs);
883+
- [Implement configuration models / graph generators for interlayers](https://github.com/JuliaGraphs/MultilayerGraphs.jl/issues/46);
884+
- [Relax the requirement of same `T` and `U` for all `Layer`s and `Interlayer`s that are meant to constitute a `Multilayer(Di)Graph`](https://github.com/JuliaGraphs/MultilayerGraphs.jl/issues/53).
871885

872886
## How to Contribute
873887

0 commit comments

Comments
 (0)