# \[ANN\] MultilayerGraphs.jl: A Package to Construct, Handle and Analyse Multilayer Graphs

**URL:** https://discourse.julialang.org/t/ann-multilayergraphs-jl-a-package-to-construct-handle-and-analyse-multilayer-graphs/85988
**Category:** Package Announcements
**Tags:** package, announcement, lightgraphs, agents, graphs
**Created:** [August 19, 2022, 8:20am UTC](https://discourse.julialang.org/t/ann-multilayergraphs-jl-a-package-to-construct-handle-and-analyse-multilayer-graphs/85988 "2022-08-19T08:20:40Z")
**Posts on this page:** 4
**Page:** 1

<div class="post-metadata">

### Author: ![InPhyT](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/inphyt/32/36552_2.png) [@InPhyT](https://discourse.julialang.org/u/InPhyT)
#### Post date: [August 19, 2022, 8:20am UTC](https://discourse.julialang.org/t/ann-multilayergraphs-jl-a-package-to-construct-handle-and-analyse-multilayer-graphs/85988/1 "2022-08-19T08:20:40Z")

</div>

We are thrilled to announce [**MultilayerGraphs.jl**](https://github.com/InPhyT/MultilayerGraphs.jl): a Julia package for the construction, manipulation and analysis of multilayer graphs extending [**Graphs.jl**](https://github.com/JuliaGraphs/Graphs.jl).

**MultilayerGraphs.jl** provides two custom types, `MultilayerGraph` and `MultilayerDiGraph`, together with utilities to handle and analyse undirected and directed multilayer graphs implementing the mathematical formulation proposed by [De Domenico et al. (2013)](https://doi.org/10.1103/PhysRevX.3.041022).

The graphs composing the multilayer graph (i.e. _layers_ and _interlayers_) can be of any type as long as they are proper extensions of `AbstractGraph{T}`. Then, since this package heavily relies on Graphs.jl and all of its extensions, it may also serve as a playground to test the overall status and consistency of the ecosystem API.

### Main Features

In the code block below we illustrate the main features of the package.

```julia
# Import necessary packages  
using Graphs
using SimpleWeightedGraphs, MetaGraphs, SimpleValueGraphs
using MultilayerGraphs

# Set graph attributes
n_nodes = 5 # Number of nodes 
min_edges = n_nodes # Minimum number of edges  
max_edges = 10 # Maximum number of edges 

# Define some graphs underlying layers and interlayers 
simpledigraph = SimpleDiGraph(n_nodes, rand(min_edges:max_edges))
simpleweighteddigraph = SimpleWeightedDiGraph(n_nodes, rand(min_edges:max_edges))
metadigraph = MetaDiGraph(simpleweighteddigraph)
simplevalueoutgraph = ValOutDiGraph( SimpleDiGraph(n_nodes,rand(min_edges:max_edges)); 
                                        edgeval_types=(Int64, ),
                                        edgeval_init=(s, d) -> (s + d, )
                                     )

simplevaluedigraph = ValDiGraph( SimpleDiGraph(n_nodes,rand(min_edges:max_edges));
                                        edgeval_types=(Int64, ),
                                        edgeval_init=(s, d) -> (s + d, )
                                  ) 

# Collect all graphs in a vector
layer_graphs = [simpledigraph, simpleweighteddigraph, metadigraph, simplevalueoutgraph, simplevaluedigraph]                      

# Define layers
layers = [ Layer(Symbol("layer_$i"), # Layer's name
                graph; # Layer's underlying graph
                U = Float64) # Layer's adjacency matrix `eltype`                  
                for (i,graph) in enumerate(layer_graphs)
          ]

# Define interlayers. Here we use the constructor for random interlayers. 
## Note that the user does not need to specify all interlayers: the unspecified one s will be taken care of by the MultilayerDiGraph constructor, that will initialize them according to the a default interlayer type passed via the keyword argument `default_interlayer_type`
interlayers = [ Interlayer(n_nodes, # Number of nodes
                          :interlayer_layer_1_layer_2, # Interlayer's name
                          :layer_1, # Source layer name
                          :layer_2, # Destination layer name
                          SimpleDiGraph{Int64}, # Underlying graph type
                          rand(min_edges:max_edges); # Number of edges
                          U = Float64 # Interlayers's adjacency matrix `eltype`
                          ),
                 Interlayer(n_nodes, :interlayer_layer_1_layer_3,:layer_1, :layer_3, SimpleWeightedDiGraph{Int64}, rand(min_edges:max_edges); U = Float64 ), # Create another interlayer, the others will be automatically specified
              ]

# Define the MultilayerDiGraph
multilayerdigraph = MultilayerDiGraph(layers, interlayers)

# There are many other constructors for Layer, Interlayer and Multilayer(Di)Graph! Make sure to check them out in the documentation or in the REPL.

# Get all layers
multilayerdigraph.layers

# Get all Interlayers
multilayerdigraph.interlayers

# Get the adjacency_tensor
multilayerdigraph.adjacency_tensor

# Add an edge
add_edge!(multilayerdigraph, MultilayerVertex(1, :layer_1), MultilayerVertex(2, :layer_4)) # MultilayerVertex(1, :layer_1) refers to vertex 1 (i.e. the representation of node 1) in layer 1
## Check that the edge has been added
@assert has_edge(multilayerdigraph, MultilayerVertex(1, :layer_1), MultilayerVertex(2, :layer_4))
@assert multilayerdigraph.adjacency_tensor[1,2,1,4] == 1.0 # indexing is [vertex_1, vertex_2, vertex_1_layer_index, vertex_2_layer_index]

# Remove an edge
rem_edge!(multilayerdigraph, MultilayerVertex(1, :layer_1), MultilayerVertex(2, :layer_4))
## Check that the edge has been removed
@assert !has_edge(multilayerdigraph, MultilayerVertex(1, :layer_1), MultilayerVertex(2, :layer_4))
@assert multilayerdigraph.adjacency_tensor[1,2,1,4] == 0.0 # indexing is [vertex_1, vertex_2, vertex_1_layer_index, vertex_2_layer_index]

# Since Multilayer(Di)Graphs are extensions of Graphs.jl (https://juliagraphs.org/Graphs.jl/dev/ecosystem/interface/) all methods defined for AbstractGraph also work for Multilayer(Di)Graph. 
## Below are some examples of multilayer-specific functions and of Graphs.jl's functions that had to be reimplemented anyway for technical reasons.

# Get the overlay monoplex graph
get_overlay_monoplex_graph(multilayerdigraph)

# Get the depth-weighted global clustering coefficient, with weights so that it coincides with the global clustering coefficient
wcc = multilayer_weighted_global_clustering_coefficient(multilayerdigraph, [1/3, 1/3, 1/3])
@assert wcc ≈ multilayer_global_clustering_coefficient(multilayerdigraph)

# Get the eigenvector centrality of each vertex and the relative error at each iteration of the algorithm that computes it
eig_centrality, errs = eigenvector_centrality( multilayerdigraph;
                                               norm = "n", # Normalization factor
                                               tol = 1e-3 # Target relative inter-iteration error
                                             )

# Get the modularity, given a clustering
modularity( multilayerdigraph,
            rand([1, 2, 3, 4], length(nodes(multilayerdigraph)),length(multilayerdigraph.layers)) # Communities 
          )

# Von Neumann Entropy is currently implemented only for undirected multilayer graphs (i.e. for MultilayerGraph). 
## You can find it in the tutorial included in the package documentation. 

```

### Future Developments

The package is currently under development and further steps would benefit enormously from the precious feedback of the [JuliaGraph people](https://github.com/orgs/JuliaGraphs/people), graph theorists, network scientists and all the users who might have general questions or suggestions.

Here we highlight the major future developments we have currently identified:

- Better integration with [Graphs.jl](https://github.com/JuliaGraphs/Graphs.jl) (e.g. move the `AbstractVertex` to Graphs.jl, standardize graphs constructors, etc.);
- Better integration with [MetaGraphs.jl](https://github.com/JuliaGraphs/MetaGraphs.jl) and [SimpleValueGraphs.jl](https://github.com/simonschoelly/SimpleValueGraphs.jl). Although it is possible to specify a `MetaGraph` and `SimpleValueGraph` as layer and/or interlayer, they are not yet fully supported (i.e. API may be a little unfit for them). An example using MetaGraphs, SimpleValueGraphs can be found at our announcement post here;
- Optimise the adjacency tensor;
- More intuitive constructor for `Interlayer`;
- Implement specialised and simplified API for `MultiplexGraph`;
- Implement visualisation functionalities;
- Implement other features and methods for the analysis of multilayer graphs following the scientific literature:
  - Kivelä et al. (2014) [Multilayer networks](https://doi.org/10.1093/comnet/cnu016). _Journal of Complex Networks_
  - Cozzo et al. (2015) [Structure of triadic relations in multiplex networks](https://doi.org/10.1088/1367-2630/17/7/073029). _New Journal of Physics_
  - De Domenico et al. (2015) [MuxViz: a tool for multilayer analysis and visualization of networks](https://doi.org/10.1093/comnet/cnu038). _Journal of Complex Networks_
  - De Domenico et al. (2015) [Ranking in interconnected multilayer networks reveals versatile nodes](https://doi.org/10.1038/ncomms7868). _Nature Communications_
  - De Domenico (2022) [Multilayer Networks: Analysis and Visualization](https://doi.org/10.1007/978-3-030-75718-2). _Springer Cham_

### References

For more information, tutorials and API reference please visit the [documentation](https://inphyt.github.io/MultilayerGraphs.jl).

Feel free to open [discussions](https://github.com/InPhyT/MultilayerGraphs.jl/discussions), [issues](https://github.com/InPhyT/MultilayerGraphs.jl/issues) or [PRs](https://github.com/InPhyT/MultilayerGraphs.jl/pulls). They are very welcome!

### Contacts

| Author | GitHub | Twitter | Discourse | Forem |
| --- | --- | --- | --- | --- |
| Pietro Monticone | [@pitmonticone](https://github.com/pitmonticone) | [@PietroMonticone](https://twitter.com/PietroMonticone) | [@PietroMonticone](https://discourse.julialang.org/u/PietroMonticone) | [@pitmonticone](https://forem.julialang.org/pitmonticone) |
| Claudio Moroni | [@ClaudMor](https://github.com/ClaudMor) | [@Claudio\_\_Moroni](https://twitter.com/Claudio__Moroni) | [@claudio20497](https://discourse.julialang.org/u/claudio20497) | [@claudio\_moroni](https://forem.julialang.org/claudio_moroni) |

---

<div class="post-metadata">

### Author: ![gdalle](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/gdalle/32/27854_2.png) [@gdalle](https://discourse.julialang.org/u/gdalle)
#### Post date: [August 19, 2022, 8:30am UTC](https://discourse.julialang.org/t/ann-multilayergraphs-jl-a-package-to-construct-handle-and-analyse-multilayer-graphs/85988/2 "2022-08-19T08:30:27Z")

</div>

Pinging @mbesancon @etienne_dg @simonschoelly @jpfairbanks @viralbshah

---

<div class="post-metadata">

### Author: ![InPhyT](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/inphyt/32/36552_2.png) [@InPhyT](https://discourse.julialang.org/u/InPhyT)
#### Post date: [August 19, 2022, 9:42pm UTC](https://discourse.julialang.org/t/ann-multilayergraphs-jl-a-package-to-construct-handle-and-analyse-multilayer-graphs/85988/3 "2022-08-19T21:42:21Z")

</div>

Thank you @gdalle. Here is our new related [issue](https://github.com/JuliaGraphs/Graphs.jl/issues/165) on Graphs.jl.

---

<div class="post-metadata">

### Author: ![InPhyT](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/inphyt/32/36552_2.png) [@InPhyT](https://discourse.julialang.org/u/InPhyT)
#### Post date: [August 24, 2022, 2:47pm UTC](https://discourse.julialang.org/t/ann-multilayergraphs-jl-a-package-to-construct-handle-and-analyse-multilayer-graphs/85988/4 "2022-08-24T14:47:43Z")

</div>

[UPDATE] [MultilayerGraphs.jl](https://github.com/JuliaGraphs/MultilayerGraphs.jl) has been successfully transferred to [JuliaGraphs](https://github.com/JuliaGraphs).
