Skip to content

Commit b9847b7

Browse files
InterdisciplinaryPhysicsTeamClaudMorpitmonticone
committed
Add example folder
Co-Authored-By: Claudio Moroni <[email protected]> Co-Authored-By: Pietro Monticone <[email protected]>
1 parent 643514a commit b9847b7

File tree

2 files changed

+360
-0
lines changed

2 files changed

+360
-0
lines changed

example/example.jl

Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
#################################################
2+
################### PACKAGES ####################
3+
#################################################
4+
5+
# Import necessary dependencies
6+
using Distributions, Graphs, SimpleValueGraphs
7+
using MultilayerGraphs
8+
# Set the number of nodes
9+
const n_nodes = 100
10+
# Create a list of nodes
11+
const node_list = [Node("node_$i") for i in 1:n_nodes]
12+
13+
#################################################
14+
#################### LAYERS #####################
15+
#################################################
16+
17+
# Create a simple directed layer
18+
n_vertices = rand(1:100) # Number of vertices
19+
layer_simple_directed = layer_simpledigraph( # Layer constructor
20+
:layer_simple_directed, # Layer name
21+
sample(node_list, n_vertices; replace=false), # Nodes represented in the layer
22+
Truncated(Normal(5, 5), 0, 20), # Indegree sequence distribution
23+
Truncated(Normal(5, 5), 0, 20), # Outdegree sequence distribution
24+
)
25+
26+
# Create a simple directed weighted layer
27+
n_vertices = rand(1:n_nodes) # Number of vertices
28+
n_edges = rand(n_vertices:(n_vertices * (n_vertices - 1) - 1)) # Number of edges
29+
layer_simple_directed_weighted = layer_simpleweighteddigraph( # Layer constructor
30+
:layer_simple_directed_weighted, # Layer name
31+
sample(node_list, n_vertices; replace=false), # Nodes represented in the layer
32+
n_edges; # Number of randomly distributed edges
33+
default_edge_weight=(src, dst) -> rand(), # Function assigning weights to edges
34+
)
35+
36+
# Create a simple directed value layer
37+
n_vertices = rand(1:n_nodes) # Number of vertices
38+
n_edges = rand(n_vertices:(n_vertices * (n_vertices - 1) - 1)) # Number of edges
39+
default_vertex_metadata = v -> ("vertex_$(v)_metadata") # Vertex metadata
40+
default_edge_metadata = (s, d) -> (rand(),) # Edge metadata
41+
layer_simple_directed_value = Layer( # Layer constructor
42+
:layer_simple_directed_value, # Layer name
43+
sample(node_list, n_vertices; replace=false), # Nodes represented in the layer
44+
n_edges, # Number of randomly distributed edges
45+
ValDiGraph(
46+
SimpleDiGraph{Int64}();
47+
vertexval_types=(String,),
48+
vertexval_init=default_vertex_metadata,
49+
edgeval_types=(Float64,),
50+
edgeval_init=default_edge_metadata,
51+
),
52+
Float64;
53+
default_vertex_metadata=default_vertex_metadata, # Vertex metadata
54+
default_edge_metadata=default_edge_metadata, # Edge metadata
55+
)
56+
57+
# Create a list of layers
58+
layers = [
59+
layer_simple_directed, layer_simple_directed_weighted, layer_simple_directed_value
60+
]
61+
62+
#################################################
63+
################# INTERLAYERS ###################
64+
#################################################
65+
66+
# Create a simple directed interlayer
67+
n_vertices_1 = nv(layer_simple_directed) # Number of vertices of layer 1
68+
n_vertices_2 = nv(layer_simple_directed_weighted) # Number of vertices of layer 2
69+
n_edges = rand(1:(n_vertices_1 * n_vertices_2 - 1)) # Number of interlayer edges
70+
interlayer_simple_directed = interlayer_simpledigraph( # Interlayer constructor
71+
layer_simple_directed, # Layer 1
72+
layer_simple_directed_weighted, # Layer 2
73+
n_edges, # Number of edges
74+
)
75+
76+
# Create a simple directed meta interlayer
77+
n_vertices_1 = nv(layer_simple_directed_weighted) # Number of vertices of layer 1
78+
n_vertices_2 = nv(layer_simple_directed_value) # Number of vertices of layer 2
79+
n_edges = rand(1:(n_vertices_1 * n_vertices_2 - 1)) # Number of interlayer edges
80+
interlayer_simple_directed_meta = interlayer_metadigraph( # Interlayer constructor
81+
layer_simple_directed_weighted, # Layer 1
82+
layer_simple_directed_value, # Layer 2
83+
n_edges; # Number of edges
84+
default_edge_metadata=(src, dst) -> # Edge metadata
85+
(edge_metadata = "metadata_of_edge_from_$(src)_to_$(dst)"),
86+
transfer_vertex_metadata=true, # Boolean deciding layer vertex metadata inheritance
87+
)
88+
89+
# Create a list of interlayers
90+
interlayers = [interlayer_simple_directed, interlayer_simple_directed_meta]
91+
92+
#################################################
93+
################## MULTILAYER ###################
94+
#################################################
95+
96+
# Create a simple directed multilayer graph
97+
multilayerdigraph = MultilayerDiGraph( # Constructor
98+
layers, # The (ordered) collection of layers
99+
interlayers; # The manually specified interlayers
100+
# The interlayers that are left unspecified
101+
# will be automatically inserted according
102+
# to the keyword argument below
103+
default_interlayers_structure="multiplex",
104+
# The automatically specified interlayers will have only diagonal couplings
105+
)
106+
107+
# Layers and interlayer can be accessed as properties using their names
108+
multilayerdigraph.layer_simplevaldigraph
109+
110+
# Create a node
111+
new_node_1 = Node("new_node_1")
112+
# Add the node to the multilayer graph
113+
add_node!(multilayerdigraph, new_node_1)
114+
# Create a vertex representing the node
115+
new_vertex_1 = MV( # Constructor (alias for "MultilayerVertex")
116+
new_node_1, # Node represented by the vertex
117+
:layer_simplevaldigraph, # Layer containing the vertex
118+
("new_metadata"), # Vertex metadata
119+
)
120+
# Add the vertex
121+
add_vertex!(
122+
multilayerdigraph, # MultilayerDiGraph the vertex will be added to
123+
new_vertex_1, # MultilayerVertex to add
124+
)
125+
126+
# Create another node in another layer
127+
new_node_2 = Node("new_node_2")
128+
# Create another vertex representing the new node
129+
new_vertex_2 = MV(new_node_2, :layer_simpledigraph)
130+
# Add the new vertex
131+
add_vertex!(
132+
multilayerdigraph,
133+
new_vertex_2;
134+
add_node=true, # Add the associated node before adding the vertex
135+
)
136+
# Create an edge
137+
new_edge = MultilayerEdge( # Constructor
138+
new_vertex_1, # Source vertex
139+
new_vertex_2, # Destination vertex
140+
("some_edge_metadata"), # Edge metadata
141+
)
142+
# Add the edge
143+
add_edge!(
144+
multilayerdigraph, # MultilayerDiGraph the edge will be added to
145+
new_edge, # MultilayerVertex to add
146+
)
147+
148+
################### METRICS ####################
149+
150+
# Compute the global clustering coefficient
151+
multilayer_global_clustering_coefficient(multilayerdigraph)
152+
# Compute the overlay clustering coefficient
153+
overlay_clustering_coefficient(multilayerdigraph)
154+
# Compute the multilayer eigenvector centrality
155+
eigenvector_centrality(multilayerdigraph)
156+
# Compute the multilayer modularity
157+
modularity(
158+
multilayerdigraph,
159+
rand([1, 2, 3, 4], length(nodes(multilayerdigraph)), length(multilayerdigraph.layers)),
160+
)

example/example.md

Lines changed: 200 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,200 @@
1+
# Example
2+
3+
Here we are going to synthetically illustrate some of the main features of MultilayerGraphs.jl. For a more comprehensive exploration of the package functionalities we strongly recommend to consult the [documentation](https://juliagraphs.org/MultilayerGraphs.jl).
4+
5+
## Installation
6+
7+
To install MultilayerGraphs.jl it is sufficient to activate the `pkg` mode by pressing `]` in the Julia REPL and then run the following command:
8+
9+
```nothing
10+
pkg> add MultilayerGraphs
11+
```
12+
13+
## Usage
14+
15+
Let's begin by importing the necessary dependencies and setting the relevant constants.
16+
17+
```julia
18+
# Import necessary dependencies
19+
using Distributions, Graphs, SimpleValueGraphs
20+
using MultilayerGraphs
21+
# Set the number of nodes
22+
const n_nodes = 100
23+
# Create a list of nodes
24+
const node_list = [Node("node_$i") for i in 1:n_nodes]
25+
```
26+
27+
### Layers and Interlayers
28+
29+
We will instantiate layers and interlayers with randomly-selected edges and vertices adopting a variety of techniques. Layers and Interlayers are not immutable, and mostly behave like normal graphs. The user is invited to consult the [API](https://juliagraphs.org/MultilayerGraphs.jl/stable/API/) for further details.
30+
31+
Here we define a layer with an underlying simple directed graph using a graph generator-like (or "configuration model"-like) constructor which allows us to specify both the **indegree** and the **outdegree sequences**. Before instantiating each layer we sample the number of its vertices and, optionally, of its edges.
32+
33+
```julia
34+
# Create a simple directed layer
35+
n_vertices = rand(1:100) # Number of vertices
36+
layer_simple_directed = layer_simpledigraph( # Layer constructor
37+
:layer_simple_directed, # Layer name
38+
sample(node_list, n_vertices; replace=false), # Nodes represented in the layer
39+
Truncated(Normal(5, 5), 0, 20), # Indegree sequence distribution
40+
Truncated(Normal(5, 5), 0, 20) # Outdegree sequence distribution
41+
)
42+
```
43+
44+
Then we define a layer with an underlying simple weighted directed graph. This is another kind of constructor that allows the user to specify the number of edges to be randomly distributed among vertices.
45+
46+
```julia
47+
# Create a simple directed weighted layer
48+
n_vertices = rand(1:n_nodes) # Number of vertices
49+
n_edges = rand(n_vertices:(n_vertices * (n_vertices - 1) - 1)) # Number of edges
50+
layer_simple_directed_weighted = layer_simpleweighteddigraph( # Layer constructor
51+
:layer_simple_directed_weighted, # Layer name
52+
sample(node_list, n_vertices; replace=false), # Nodes represented in the layer
53+
n_edges; # Number of randomly distributed edges
54+
default_edge_weight=(src, dst) -> rand() # Function assigning weights to edges
55+
)
56+
```
57+
58+
Similar constructors, more flexible at the cost of ease of use, enable a finer tuning. The constructor we use below should be necessary only in rare circumstances, e.g. if the equivalent simplified constructor `layer_simplevaldigraph` is not able to infer the correct return types of `default_vertex_metadata` or `default_edge_metadata`, or to use and underlying graph structure that isn't currently supported.
59+
60+
```julia
61+
# Create a simple directed value layer
62+
n_vertices = rand(1:n_nodes) # Number of vertices
63+
n_edges = rand(n_vertices:(n_vertices * (n_vertices - 1) - 1)) # Number of edges
64+
default_vertex_metadata = v -> ("vertex_$(v)_metadata") # Vertex metadata
65+
default_edge_metadata = (s, d) -> (rand(),) # Edge metadata
66+
layer_simple_directed_value = Layer( # Layer constructor
67+
:layer_simple_directed_value, # Layer name
68+
sample(node_list, n_vertices; replace=false), # Nodes represented in the layer
69+
n_edges, # Number of randomly distributed edges
70+
ValDiGraph(
71+
SimpleDiGraph{Int64}();
72+
vertexval_types=(String,),
73+
vertexval_init=default_vertex_metadata,
74+
edgeval_types=(Float64,),
75+
edgeval_init=default_edge_metadata,
76+
),
77+
Float64;
78+
default_vertex_metadata=default_vertex_metadata, # Vertex metadata
79+
default_edge_metadata=default_edge_metadata # Edge metadata
80+
)
81+
82+
# Create a list of layers
83+
layers = [layer_simple_directed, layer_simple_directed_weighted, layer_simple_directed_value]
84+
```
85+
86+
There are many more constructors the user is encouraged to explore in the package [documentation](https://juliagraphs.org/MultilayerGraphs.jl).
87+
88+
The interface of interlayers is very similar to that of layers. It is very important to notice that, in order to define a `Multilayer(Di)Graph`, interlayers don't need to be explicitly constructed by the user since they are automatically identified by the `Multilayer(Di)Graph` constructor, but for more complex interlayers the manual instantiation is required.
89+
90+
Here we define an interlayer with an underlying simple directed graph.
91+
92+
```julia
93+
# Create a simple directed interlayer
94+
n_vertices_1 = nv(layer_simple_directed) # Number of vertices of layer 1
95+
n_vertices_2 = nv(layer_simple_directed_weighted) # Number of vertices of layer 2
96+
n_edges = rand(1:(n_vertices_1 * n_vertices_2 - 1)) # Number of interlayer edges
97+
interlayer_simple_directed = interlayer_simpledigraph( # Interlayer constructor
98+
layer_simple_directed, # Layer 1
99+
layer_simple_directed_weighted, # Layer 2
100+
n_edges # Number of edges
101+
)
102+
```
103+
104+
The interlayer exports a more flexible constructor too.
105+
106+
```julia
107+
# Create a simple directed meta interlayer
108+
n_vertices_1 = nv(layer_simple_directed_weighted) # Number of vertices of layer 1
109+
n_vertices_2 = nv(layer_simple_directed_value) # Number of vertices of layer 2
110+
n_edges = rand(1:(n_vertices_1 * n_vertices_2 - 1)) # Number of interlayer edges
111+
interlayer_simple_directed_meta = interlayer_metadigraph( # Interlayer constructor
112+
layer_simple_directed_weighted, # Layer 1
113+
layer_simple_directed_value, # Layer 2
114+
n_edges; # Number of edges
115+
default_edge_metadata=(src, dst) -> # Edge metadata
116+
(edge_metadata="metadata_of_edge_from_$(src)_to_$(dst)"),
117+
transfer_vertex_metadata=true # Boolean deciding layer vertex metadata inheritance
118+
)
119+
120+
# Create a list of interlayers
121+
interlayers = [interlayer_simple_directed, interlayer_simple_directed_meta]
122+
```
123+
124+
### Multilayer Graphs
125+
126+
Let's construct a directed multilayer graph (`MultilayerDiGraph`).
127+
128+
```julia
129+
# Create a simple directed multilayer graph
130+
multilayerdigraph = MultilayerDiGraph( # Constructor
131+
layers, # The (ordered) collection of layers
132+
interlayers; # The manually specified interlayers
133+
# The interlayers that are left unspecified
134+
# will be automatically inserted according
135+
# to the keyword argument below
136+
default_interlayers_structure="multiplex"
137+
# The automatically specified interlayers will have only diagonal couplings
138+
)
139+
140+
# Layers and interlayer can be accessed as properties using their names
141+
multilayerdigraph.layer_simplevaldigraph
142+
```
143+
144+
Then we proceed by showing how to add nodes, vertices and edges to a directed multilayer graph. The user may add vertices that do or do not represent nodes which are already present in the multilayer graph. In the latter case, we have to create a node first and then add the vertex representing such node to the multilayer graph. The vertex-level metadata are effectively considered only if the graph underlying the relevant layer or interlayer supports them, otherwise they are discarded. The same holds for edge-level metadata and/or weight.
145+
146+
```julia
147+
# Create a node
148+
new_node_1 = Node("new_node_1")
149+
# Add the node to the multilayer graph
150+
add_node!(multilayerdigraph, new_node_1)
151+
# Create a vertex representing the node
152+
new_vertex_1 = MV( # Constructor (alias for "MultilayerVertex")
153+
new_node_1, # Node represented by the vertex
154+
:layer_simplevaldigraph, # Layer containing the vertex
155+
("new_metadata") # Vertex metadata
156+
)
157+
# Add the vertex
158+
add_vertex!(
159+
multilayerdigraph, # MultilayerDiGraph the vertex will be added to
160+
new_vertex_1 # MultilayerVertex to add
161+
)
162+
163+
# Create another node in another layer
164+
new_node_2 = Node("new_node_2")
165+
# Create another vertex representing the new node
166+
new_vertex_2 = MV(new_node_2, :layer_simpledigraph)
167+
# Add the new vertex
168+
add_vertex!(
169+
multilayerdigraph,
170+
new_vertex_2;
171+
add_node=true # Add the associated node before adding the vertex
172+
)
173+
# Create an edge
174+
new_edge = MultilayerEdge( # Constructor
175+
new_vertex_1, # Source vertex
176+
new_vertex_2, # Destination vertex
177+
("some_edge_metadata") # Edge metadata
178+
)
179+
# Add the edge
180+
add_edge!(
181+
multilayerdigraph, # MultilayerDiGraph the edge will be added to
182+
new_edge # MultilayerVertex to add
183+
)
184+
```
185+
186+
Finally we illustrate how to compute a few multilayer metrics such as the global clustering coefficient, the overlay clustering coefficient, the multilayer eigenvector centrality, and the multilayer modularity as defined in [De Domenico et al. (2013)](https://doi.org/10.1103/physrevx.3.041022).
187+
188+
```julia
189+
# Compute the global clustering coefficient
190+
multilayer_global_clustering_coefficient(multilayerdigraph)
191+
# Compute the overlay clustering coefficient
192+
overlay_clustering_coefficient(multilayerdigraph)
193+
# Compute the multilayer eigenvector centrality
194+
eigenvector_centrality(multilayerdigraph)
195+
# Compute the multilayer modularity
196+
modularity(
197+
multilayerdigraph,
198+
rand([1, 2, 3, 4], length(nodes(multilayerdigraph)), length(multilayerdigraph.layers))
199+
)
200+
```

0 commit comments

Comments
 (0)