Skip to content

Commit 961ad26

Browse files
author
unknown
committed
improved readability
1 parent 5dda53f commit 961ad26

File tree

1 file changed

+107
-92
lines changed

1 file changed

+107
-92
lines changed
Lines changed: 107 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
#=
22
# [Network Diffusion](@id Getting Started)
33
4-
This example explains the use of the basic functions and constructors
5-
in NetworkDynamics.jl by modeling a simple diffusion on an undirected network.
4+
This example explains the use of the basic functions and constructors in NetworkDynamics.jl by modeling a simple
5+
diffusion on an undirected network.
66
7-
This page will walk you through:
8-
* the theoretical background of a simple diffusion propagating in an undirected network
7+
This page will:
8+
* walk you through the theoretical background of a simple diffusion propagating in an undirected network
99
* explain the network dynamics of the system
10-
* explain how to program the dynamics
10+
* explain how to program them
1111
1212
!!! note
1313
An Undirected Network is a network where all the connections between the nodes are bidirectional.
@@ -20,12 +20,13 @@ This example can be downloaded as a normal Julia script [here](@__NAME__.jl). #m
2020
2121
Diffusion processes appear in phenomena as diverse as heat conduction, electrical currents, and random walks.
2222
Generally speaking they describe the tendency of systems to evolve towards a state of equally distributed entropy
23-
(that entropy being in the form of e.g. heat, charge or concentration). If we assume a thermal system, the temperature
24-
of a specific spot changes depending on the temperature gradient between itself and its neighborhood.
23+
(the entropy being in the form of e.g. heat, charge or concentration). If we assume a thermal system, the temperature
24+
of a specific spot changes depending on the temperature gradient between the temperature of the spot itself and that of
25+
its neighborhood.
2526
26-
We will build a graph $g$ with $N$ nodes and an adjacency matrix $A$, where $v = (v_1, \dots, v_n)$ is the vector of
27+
We will build a graph $g$ with $N$ nodes and an adjacency matrix $A$, where $v = (v_1, \dots, v_n)$ is the vector of the
2728
(abstract) temperatures at each node $i = 1, \dots, N$. The rate of change of state $v_i$ will be described by the
28-
difference between the temperature of the node and that of its neighbors. For the above we obtain the following ordinary
29+
difference between the temperature of the node and that of its neighbours. From the above we obtain the following ordinary
2930
differential equation:
3031
```math
3132
\dot v_i = \sum_{j=1}^N A_{ji} (v_j - v_i).
@@ -44,8 +45,8 @@ In order to bring this equation into the form required by NetworkDynamics.jl we
4445
dynamics and vertex dynamics and bring them into the correct input-output formulation.
4546
4647
47-
#### Vertex Dynamics:
48-
All vertices have one internal state $v$. This state is also the vertex output. It is the sum over all incoming edge
48+
### Vertex Dynamics:
49+
All vertices have one internal state $v$, which is also the vertex output. It is the sum over all incoming edge
4950
flows connected to the vertex. This directly corresponds to the component model definition outlined in [Mathematical Model](@ref):
5051
```math
5152
\begin{aligned}
@@ -56,7 +57,7 @@ y^\mathrm{v} &= g^{\mathrm v}(u^{\mathrm v}, \sum_k^{\text{incident}} y^{\mathrm
5657
=#
5758

5859
#=
59-
#### Edge Dynamics:
60+
### Edge Dynamics:
6061
The edge dynamics on the other hand do not have any internal states. Thus we can define the edge output as the
6162
difference between the source and destination vertices:
6263
```math
@@ -68,10 +69,11 @@ y^{\mathrm e}_{\mathrm{src}} &= g_\mathrm{src}^{\mathrm e}(u^{\mathrm e}, y^{\ma
6869
=#
6970

7071
#=
71-
### Modelling dynamics in NetworkDynamics.jl
72-
To model the vertex dynamics we need to create a `VertexModel` and to model the edge dynamics we need to create an `EdgeModel`.
72+
## Modelling dynamics in NetworkDynamics.jl
73+
To model the vertex and edge dynamics we need to create a `VertexModel` and an `EdgeModel`, respectively.
7374
74-
First we need to have Julia and the necessary packages (`Graphs`, `Revise`, `LiveServer`, `NetworkDynamics`, `OrdinaryDiffEqTsit5`, `StableRNGs` and `Plots`) installed. Then we need to load the packages:
75+
As a first step we need to install Julia and the necessary packages (`Graphs`, NetworkDynamics`, `OrdinaryDiffEqTsit5`,
76+
`StableRNGs` and `Plots`). Then we need to load them:
7577
=#
7678

7779
using Graphs
@@ -81,27 +83,28 @@ using StableRNGs
8183
using Plots
8284
nothing #hide
8385

86+
8487
#=
8588
86-
#### Defining an `EdgeModel`
89+
### Defining the `EdgeModel`
90+
91+
Then we must define the `EdgeModel`. To define it we use the function `diffusionedge_g!` which takes as inputs
92+
the current state of the edge `e`, its source vertex `v_src`, its destination vertex `v_dst`, a vector of parameters `p`
93+
and the time `t`. In order to comply with the syntax of NetworkDynamics.jl we must always define functions for edges
94+
with exactly these arguments. (In the case of this example, the values for `p` and `t` are not used since there are no
95+
parameters and there is no explicit time dependency in the system).
8796
88-
Then we define the `EdgeModel`.
89-
To define it we use the function `diffusionedge_g!`. The function takes as inputs the current state of the edge `e`,
90-
its source vertex `v_src`, its destination vertex `v_dst`, a vector of parameters `p` and the time `t`. In order to
91-
comply with the syntax of NetworkDynamics.jl we must always define functions for edges with exactly these arguments.
92-
(In the case of this example, the values for `p` and `t` are not used since there are no parameters and ther is no
93-
#explicit time dependency in the system).
94-
After the function call the edge's output value `e` equals the difference between its source and its destination
95-
vertex (i.e. the discrete gradient along that edge).
97+
After the function call the edge's output value `e` equals the difference between its source and its destination vertex
98+
(i.e. the discrete gradient along that edge).
9699
97100
!!! note
98101
`diffusionedge_g!` is called a **mutating** function, because it mutates (modifies) the edge state `e` (which is the
99102
first of its inputs). (In Julia, names of mutating functions end with an `!`.) We use mutating functions because
100-
they reduce the computational resource allocations and, therefore, speed up the computations.
103+
they reduce the computational resource allocations and therefore, speed up the computations.
101104
=#
102105

103106
function diffusionedge_g!(e_dst, v_src, v_dst, p, t)
104-
## e_dst, v_src, v_dst are arrays, so we use the broadcasting operator
107+
## e_dst, v_src, v_dst are arrays, so we use the broadcasting operator .
105108
e_dst .= v_src .- v_dst
106109
nothing
107110
end
@@ -116,10 +119,11 @@ nd_diffusion_edge = EdgeModel(; g=AntiSymmetric(diffusionedge_g!), outsym=[:flow
116119

117120

118121
#=
119-
#### Defining a `VertexModel`
122+
### Defining the `VertexModel`
120123
Next we need to define the `VertexModel`. For undirected graphs, the `edgefunction!` specifies the coupling from a
121-
source- to a destination vertex. The contributions of the connected edges to a single vertex are "aggregated". By default, the aggregation is the summation of
122-
all incident edge states. The aggregated edge state is made available via the `esum` argument of the vertex function.
124+
source to a destination vertex. The contributions of the connected edges to a single vertex are "aggregated".
125+
By default, the aggregation is the summation of all incident edge states. The aggregated edge state is made available
126+
via the `esum` argument of the vertex function.
123127
=#
124128

125129
function diffusionvertex_f!(dv, v, esum, p, t)
@@ -132,68 +136,67 @@ nothing #hide #md
132136
#=
133137
Just like above, the input arguments `v, esum, p, t` are mandatory for the syntax of vertex functions. The additional
134138
input `dv` corresponding to the derivative of the vertex' state is mandatory for vertices described by ordinary
135-
differential equations.
136-
137-
The outputs of the vertex function are just a subset of the internal states. For that we can use the [`StateMask`](@ref) helper
138-
function `g = StateMaks(1:1)`
139+
differential equations. The outputs of the vertex function are just a subset of the internal states. Therefore, we
140+
can use the [`StateMask`](@ref) helper function `g = StateMaks(1:1)` to access them.
139141
=#
140142

141143
nd_diffusion_vertex = VertexModel(; f=diffusionvertex_f!, g=StateMask(1:1), dim=1)
142144

143145
#=
146+
144147
## Constructing the network
145148
146-
With the components defined, we can define the topology and assemble the network dynamics.
149+
With the components defined, we can now define the topology and assemble the network dynamics.
147150
=#
148151

149-
# First we define the number of nodes the network is comprised of:
152+
# The first step is to define the number of nodes the network is comprised of:
150153
N = 20 # number of nodes
151-
k = 4 # average degree
154+
k = 4 # average degree distribution
155+
nothing #hide #md
152156

153-
#= we will use the [Barabási–Albert model](https://en.wikipedia.org/wiki/Barab%C3%A1si%E2%80%93Albert_model) generates
154-
a scale-free random graph.
155-
=#
157+
# Then we define the network model. We will use the
158+
# [Barabási–Albert model](https://en.wikipedia.org/wiki/Barab%C3%A1si%E2%80%93Albert_model) which generates a
159+
# scale-free random graph.
156160
g = barabasi_albert(N, k)
157161
nothing #hide #md
158162

159163
#=
160-
We then create the network of nodes and edges by using the constructor `Network`. It is combines the component
164+
We then create the network of nodes and edges by using the constructor `Network`. It combines the component
161165
model with the topological information contained in the graph **`g`** and returns an `Network` compatible with the
162166
solvers of `DifferentialEquations.jl`.
163167
=#
164168
nd = Network(g, nd_diffusion_vertex, nd_diffusion_edge)
165-
166-
167169
rng = StableRNG(1)
168170

169-
# We generate random initial conditions
171+
# We then generate random initial conditions
170172
x0 = randn(rng, N)
171173

172174
#=
173-
We are solving the diffusion problem on the time interval $[0, 2]$ with the `Tsit5()` algorithm, which is recommended
174-
by the authors of `DifferentialEquations.jl` for most non-stiff problems.
175+
We then solve the diffusion problem on the time interval $[0, 2]$ with the `Tsit5()` algorithm, which is recommended
176+
by the authors of `DifferentialEquations.jl` for most non-stiff problems. We first create an `ODEProblem`:
175177
=#
176178
ode_prob = ODEProblem(nd, x0, (0.0, 2.0))
177179

178180
# We test all ex styles #src
179181
Main.test_execution_styles(ode_prob) #src
180182

181-
182-
# Solve the simulation commend
183+
# And then solve the network using ´solve´:
183184
sol = solve(ode_prob, Tsit5());
184185
nothing #hide #md
185186

186187
#=
187-
The plotting of the results using the command `plot` is straightforward. The **`idxs`** keyword allows us to pass a
188-
list of indices. We can also use "symbolic" indices, which specify components and their symbols directly.
189-
For example `idxs = VIndex(1, :v)` accesses the state `:v` of vertex 1. See [Symbolic Indexing](@ref) for more details.
188+
We plot the results using the `plot` command, which takes three parameters as input `sol`, `idxs` and `fmt`.
189+
The first parameter is the solved network `sol`.
190+
The second parameter is `idxs`, which provides a set of indices. We can use "symbolic" indices, which specify specific
191+
components and their symbols directly (see [Symbolic Indexing](@ref) for more details). In order to collect multiple
192+
indices we can use the helper function [`vidxs`](@ref) and [`eidxs`](@ref), which help us collect all symbolic indices
193+
matching specific criteria. The third and last parameter is `fmt`, which provides the format of the generated plot, in
194+
this case that format being .png.
190195
=#
191196
plot(sol; idxs=vidxs(nd, :, :), fmt=:png)
192197

193198
#=
194-
In order to collect multiple indices we can use the helper function [`vidxs`](@ref) and [`eidxs`](@ref), which help to
195-
collect all symbolic indices matching specific criteria.
196-
199+
(@Hans can you provide a description of what we see in this plot? The y axis is missing so it is unclear to me.)
197200
198201
## Two Dimensional Extension
199202
@@ -202,67 +205,53 @@ The first diffusion uses the symbol `x` and is initiated with initial conditions
202205
distribution $N(0,1)$, while the second diffusion uses the symbol `ϕ` with squared standard normal initial conditions.
203206
204207
The symbols have to be passed with the keyword **`sym`** to `VertexModel`.
208+
209+
Once again we define the number of nodes and the type of network we want to generate:
205210
=#
206211

207212
N = 10 # number of nodes
208-
k = 4 # average degree
213+
k = 4 # average degrees distribution
209214
g = barabasi_albert(N, k)
210215

211-
# We have two independent diffusions on the network, hence dim = 2
212-
216+
# We have two independent diffusions on the network, hence dim = 2. We now define the `VertexModel` and the `EdgeModel`
213217
nd_diffusion_vertex_2 = VertexModel(; f=diffusionvertex_f!, g=1:2, dim=2, sym=[:x, ])
214218
nd_diffusion_edge_2 = EdgeModel(; g=AntiSymmetric(diffusionedge_g!), outsym=[:flow_x, :flow_ϕ])
215219
nd_2 = Network(g, nd_diffusion_vertex_2, nd_diffusion_edge_2)
216220

217-
# x ~ N(0,1)^2; ϕ ~ N(0,1)
221+
#= We define the first diffusion as x ~ $N(0,1)^\mathrm{2}$ and the second diffusion as ϕ ~ $N(0,1)$. So the propagation
222+
of the diffusion from node 0 to node 2 is given by creating a vector:
223+
=#
218224
x0_2 = vec(transpose([randn(rng, N) .^ 2 randn(rng, N)]))
225+
#(@Hans: is my explanation correct?)
226+
227+
# We then define the [ODEProblem](@ref)
219228
ode_prob_2 = ODEProblem(nd_2, x0_2, (0.0, 3.0))
220229
Main.test_execution_styles(ode_prob_2) #src
221-
sol_2 = solve(ode_prob_2, Tsit5());
222230

231+
# Then solve the network using:
232+
sol_2 = solve(ode_prob_2, Tsit5());
223233

224-
# To plot the variables ϕ_i yourself use the command:
234+
# To plot the evolution of variables ϕ_i over time we use the command:
225235
plot(sol_2; idxs=vidxs(nd_2, :, :x), fmt=:png)
226-
# [To write ϕ type \phi and press TAB]
236+
# [To write ϕ in the terminal type \phi and press TAB]
227237

228-
# Using the `eidxs` helper function we can also plot the flow variables
238+
# Using the `eidxs` helper function we can also plot the evolution of the flow variables over time:
229239
plot(sol_2; idxs=eidxs(nd_2, :, :flow_x), fmt=:png)
230240

231-
#=
232-
## Appendix: The network Laplacian $L$
233241

234-
The diffusion equation on a network can be rewritten as:
235-
```math
236-
\dot v_i = \sum_{j=1}^N A_{ji} v_j - d_i v_i = e_i^T A v - d_i v_i
237-
```
238-
where $d_i$ is the degree of node $i$ and $e_i^T$ is the $i$-th standard basis vector.
242+
#=
243+
## Putting it all together
239244
240-
By introducing the diagonal matrix $D$, that has the degree of node $i$ in its $i$-th row and the Laplacian matrix
241-
$L = D - A$ we arrive at:
242-
```math
243-
\dot v = e_i^T(A - D) v
244-
```
245-
and finally
246-
```math
247-
\dot v = - L v
248-
```
245+
(@Hans: when I am trying to run the script in the "Putting it all together" in a separate .jl file I am getting a
246+
UndefVarError: `AntiSymmetric` not defined in `Main`
247+
Suggestion: check for spelling errors or missing imports.
248+
Stacktrace:
249+
[1] top-level scope
250+
@ REPL[7]:1)
249251
250-
This is a linear system of ordinary differential equations (ODEs) and its solution is a matrix exponential.
251-
To study the asymptotic behaviour of the system it suffices to analyze the eigenspectrum of $L$.
252-
For this reason $L$ is an important construction in network science.
252+
and I have no idea why. Can you please check it? Because if someone copy-pastes it, it will not work for them)
253253
=#
254254

255-
#=
256-
# Putting it all together
257-
=#
258-
259-
using Graphs
260-
using NetworkDynamics
261-
using OrdinaryDiffEqTsit5
262-
using StableRNGs
263-
using Plots
264-
nothing #hide
265-
266255
using Graphs
267256
using NetworkDynamics
268257
using OrdinaryDiffEqTsit5
@@ -311,5 +300,31 @@ x0_2 = vec(transpose([randn(rng, N) .^ 2 randn(rng, N)]))
311300
ode_prob_2 = ODEProblem(nd_2, x0_2, (0.0, 3.0))
312301
Main.test_execution_styles(ode_prob_2) #src
313302
sol_2 = solve(ode_prob_2, Tsit5());
314-
plot(sol_2; idxs=vidxs(nd_2, :, :x), fmt=:png)
303+
plot(sol_2; idxs=vidxs(nd_2, :, :x), fmt=:png, xlabel = "x", ylabel = "nd_2",)
315304
plot(sol_2; idxs=eidxs(nd_2, :, :flow_x), fmt=:png)
305+
306+
307+
308+
#=
309+
## Appendix: The network Laplacian $L$
310+
311+
The diffusion equation on a network can be rewritten as:
312+
```math
313+
\dot v_i = \sum_{j=1}^N A_{ji} v_j - d_i v_i = e_i^T A v - d_i v_i
314+
```
315+
where $d_i$ is the degree distribution of node $i$ and $e_i^T$ is the $i$-th standard basis vector.
316+
317+
By introducing the diagonal matrix $D$, that has the degree of node $i$ in its $i$-th row and the Laplacian matrix
318+
$L = D - A$ we arrive at:
319+
```math
320+
\dot v = e_i^T(A - D) v
321+
```
322+
and finally
323+
```math
324+
\dot v = - L v
325+
```
326+
327+
This is a linear system of ordinary differential equations (ODEs) and its solution is a matrix exponential.
328+
To study the asymptotic behaviour of the system it suffices to analyze the eigenspectrum of $L$.
329+
For this reason $L$ is an important construction in network science.
330+
=#

0 commit comments

Comments
 (0)