Skip to content

Commit fd5c7d0

Browse files
committed
Update tutorials to the new API
1 parent da8eecc commit fd5c7d0

18 files changed

+1564
-1056
lines changed

Algae/Algae.jl

+35-19
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1-
#=
2-
Algae growth
1+
#= Algae growth
2+
3+
Alejandro Morales
34
4-
Alejandro Morales - May 2023
5+
Centre for Crop Systems Analysis - Wageningen University
56
67
In this first example, we learn how to create a `Graph` and update it
78
dynamically with rewriting rules.
@@ -12,10 +13,11 @@ Lindermayer as one of the first L-systems.
1213
1314
First, we need to load the VPL metapackage, which will automatically load all
1415
the packages in the VPL ecosystem.
15-
=#
16-
using VPL
1716
17+
=#
18+
using VirtualPlantLab
1819
#=
20+
1921
The rewriting rules of the L-system are as follows:
2022
2123
**axiom**: A
@@ -29,23 +31,25 @@ type `A` or `B` and inherit from the abstract type `Node`. It is advised to
2931
include type definitions in a module to avoid having to restart the Julia
3032
session whenever we want to redefine them. Because each module is an independent
3133
namespace, we need to import `Node` from the VPL package inside the module:
34+
3235
=#
3336
module algae
34-
import VPL: Node
37+
import VirtualPlantLab: Node
3538
struct A <: Node end
3639
struct B <: Node end
3740
end
3841
import .algae
39-
4042
#=
43+
4144
Note that in this very example we do not need to store any data or state inside
4245
the nodes, so types `A` and `B` do not require fields.
4346
4447
The axiom is simply defined as an instance of type of `A`:
48+
4549
=#
4650
axiom = algae.A()
47-
4851
#=
52+
4953
The rewriting rules are implemented in VPL as objects of type `Rule`. In VPL, a
5054
rewriting rule substitutes a node in a graph with a new node or subgraph and is
5155
therefore composed of two parts:
@@ -68,21 +72,23 @@ objects that inherit from `Node`. The operation `+` implies a linear
6872
relationship between two nodes and `[]` indicates branching.
6973
7074
The implementation of the two rules of algae growth model in VPL is as follows:
75+
7176
=#
7277
rule1 = Rule(algae.A, rhs = x -> algae.A() + algae.B())
7378
rule2 = Rule(algae.B, rhs = x -> algae.A())
74-
7579
#=
80+
7681
Note that in each case, the argument `rhs` is being assigned an anonymous (aka
7782
*lambda*) function. This is a function without a name that is defined directly
7883
in the assigment to the argument. That is, the Julia expression `x -> A() + B()`
7984
is equivalent to the following function definition:
85+
8086
=#
8187
function rule_1(x)
8288
algae.A() + algae.B()
8389
end
84-
8590
#=
91+
8692
For simple rules (especially if the right hand side is just a line of code) it
8793
is easier to just define the right hand side of the rule with an anonymous
8894
function rather than creating a standalone function with a meaningful name.
@@ -92,45 +98,55 @@ from the REPL.
9298
With the axiom and rules we can now create a `Graph` object that represents the
9399
algae organism. The first argument is the axiom and the second is a tuple with
94100
all the rewriting rules:
101+
95102
=#
96103
organism = Graph(axiom = axiom, rules = (rule1, rule2))
97-
98104
#=
105+
99106
If we apply the rewriting rules iteratively, the graph will grow, in this case
100107
representing the growth of the algae organism. The rewriting rules are applied
101108
on the graph with the function `rewrite!()`:
109+
102110
=#
103111
rewrite!(organism)
104-
105112
#=
113+
106114
Since there was only one node of type `A`, the only rule that was applied was
107115
`rule1`, so the graph should now have two nodes of types `A` and `B`,
108116
respectively. We can confirm this by drawing the graph. We do this with the
109117
function `draw()` which will always generate the same representation of the
110118
graph, but different options are available depending on the context where the
111119
code is executed. By default, `draw()` will create a new window where an
112120
interactive version of the graph will be drawn and one can zoom and pan with the
113-
mouse.
121+
mouse (in this online document a static version is shown, see
122+
[Backends](../../manual/Visualization.md) for details):
123+
114124
=#
115125
import GLMakie
116126
draw(organism)
117-
118127
#=
128+
119129
Notice that each node in the network representation is labelled with the type of
120130
node (`A` or `B` in this case) and a number in parenthesis. This number is a
121131
unique identifier associated to each node and it is useful for debugging
122132
purposes (this will be explained in more advanced examples).
123133
124134
Applying multiple iterations of rewriting can be achieved with a simple loop:
135+
125136
=#
126137
for i in 1:4
127138
rewrite!(organism)
128139
end
140+
#=
129141
130-
# And we can verify that the graph grew as expected:
142+
ANd we can verify that the graph grew as expected:
143+
144+
=#
131145
draw(organism)
146+
#=
132147
133-
# The network is rather boring as the system is growing linearly (no branching)
134-
# but it already illustrates how graphs can grow rapidly in just a few
135-
# iterations. Remember that the interactive visualization allows adjusting the
136-
# zoom, which is handy when graphs become large.
148+
The network is rather boring as the system is growing linearly (no branching)
149+
but it already illustrates how graphs can grow rapidly in just a few iterations.
150+
Remember that the interactive visualization allows adjusting the zoom, which is
151+
handy when graphs become large.
152+
=#

Algae/Algae.md

+16-14
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
# Algae growth
22

3-
Alejandro Morales - May 2023
3+
Alejandro Morales
4+
5+
Centre for Crop Systems Analysis - Wageningen University
46

57
In this first example, we learn how to create a `Graph` and update it
68
dynamically with rewriting rules.
@@ -12,8 +14,8 @@ Lindermayer as one of the first L-systems.
1214
First, we need to load the VPL metapackage, which will automatically load all
1315
the packages in the VPL ecosystem.
1416

15-
```{julia}
16-
using VPL
17+
```julia
18+
using VirtualPlantLab
1719
```
1820

1921
The rewriting rules of the L-system are as follows:
@@ -30,9 +32,9 @@ include type definitions in a module to avoid having to restart the Julia
3032
session whenever we want to redefine them. Because each module is an independent
3133
namespace, we need to import `Node` from the VPL package inside the module:
3234

33-
```{julia}
35+
```julia
3436
module algae
35-
import VPL: Node
37+
import VirtualPlantLab: Node
3638
struct A <: Node end
3739
struct B <: Node end
3840
end
@@ -44,7 +46,7 @@ the nodes, so types `A` and `B` do not require fields.
4446

4547
The axiom is simply defined as an instance of type of `A`:
4648

47-
```{julia}
49+
```julia
4850
axiom = algae.A()
4951
```
5052

@@ -71,7 +73,7 @@ relationship between two nodes and `[]` indicates branching.
7173

7274
The implementation of the two rules of algae growth model in VPL is as follows:
7375

74-
```{julia}
76+
```julia
7577
rule1 = Rule(algae.A, rhs = x -> algae.A() + algae.B())
7678
rule2 = Rule(algae.B, rhs = x -> algae.A())
7779
```
@@ -81,7 +83,7 @@ Note that in each case, the argument `rhs` is being assigned an anonymous (aka
8183
in the assigment to the argument. That is, the Julia expression `x -> A() + B()`
8284
is equivalent to the following function definition:
8385

84-
```{julia}
86+
```julia
8587
function rule_1(x)
8688
algae.A() + algae.B()
8789
end
@@ -97,15 +99,15 @@ With the axiom and rules we can now create a `Graph` object that represents the
9799
algae organism. The first argument is the axiom and the second is a tuple with
98100
all the rewriting rules:
99101

100-
```{julia}
102+
```julia
101103
organism = Graph(axiom = axiom, rules = (rule1, rule2))
102104
```
103105

104106
If we apply the rewriting rules iteratively, the graph will grow, in this case
105107
representing the growth of the algae organism. The rewriting rules are applied
106108
on the graph with the function `rewrite!()`:
107109

108-
```{julia}
110+
```julia
109111
rewrite!(organism)
110112
```
111113

@@ -117,9 +119,9 @@ graph, but different options are available depending on the context where the
117119
code is executed. By default, `draw()` will create a new window where an
118120
interactive version of the graph will be drawn and one can zoom and pan with the
119121
mouse (in this online document a static version is shown, see
120-
[Backends](../../manual/Visualization/index.qmd) for details):
122+
[Backends](../../manual/Visualization.md) for details):
121123

122-
```{julia}
124+
```julia
123125
import GLMakie
124126
draw(organism)
125127
```
@@ -131,15 +133,15 @@ purposes (this will be explained in more advanced examples).
131133

132134
Applying multiple iterations of rewriting can be achieved with a simple loop:
133135

134-
```{julia}
136+
```julia
135137
for i in 1:4
136138
rewrite!(organism)
137139
end
138140
```
139141

140142
ANd we can verify that the graph grew as expected:
141143

142-
```{julia}
144+
```julia
143145
draw(organism)
144146
```
145147

Context/Context.jl

+26-13
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
1-
#=
21

3-
Context sensitive rules
2+
#= Context sensitive rules
3+
4+
Alejandro Morales
45
5-
Alejandro Morales - May 2023
6+
Centre for Crop Systems Analysis - Wageningen University
67
78
This examples goes back to a very simple situation: a linear sequence of 3
89
cells. The point of this example is to introduce relational growth rules and
@@ -29,10 +30,11 @@ the right hand side, we replace the cell with a new cell with the state of the
2930
parent node that was captured. Note that that now, the rhs component gets a new
3031
argument, which corresponds to the context of the father node captured in the
3132
lhs.
33+
3234
=#
33-
using VPL
35+
using VirtualPlantLab
3436
module types
35-
using VPL
37+
using VirtualPlantLab
3638
struct Cell <: Node
3739
state::Int64
3840
end
@@ -48,46 +50,57 @@ end
4850
rule = Rule(Cell, lhs = transfer, rhs = (context, father) -> Cell(data(father).state), captures = true)
4951
axiom = Cell(1) + Cell(0) + Cell(0)
5052
pop = Graph(axiom = axiom, rules = rule)
51-
5253
#=
54+
5355
In the original state defined by the axiom, only the first node contains a state
5456
of 1. We can retrieve the state of each node with a query. A `Query` object is a
5557
like a `Rule` but without a right-hand side (i.e., its purpose is to return the
5658
nodes that match a particular condition). In this case, we just want to return
5759
all the `Cell` nodes. A `Query` object is created by passing the type of the
5860
node to be queried as an argument to the `Query` function. Then, to actually
5961
execute the query we need to use the `apply` function on the graph.
62+
6063
=#
6164
getCell = Query(Cell)
6265
apply(pop, getCell)
66+
#=
6367
64-
# If we rewrite the graph one we will see that a second cell now has a state of 1.
68+
If we rewrite the graph one we will see that a second cell now has a state of 1.
69+
70+
=#
6571
rewrite!(pop)
6672
apply(pop, getCell)
73+
#=
74+
75+
And a second iteration results in all cells have a state of 1
6776
68-
# And a second iteration results in all cells have a state of 1
77+
=#
6978
rewrite!(pop)
7079
apply(pop, getCell)
71-
7280
#=
81+
7382
Note that queries may not return nodes in the same order as they were created
7483
because of how they are internally stored (and because queries are meant to
7584
return collection of nodes rather than reconstruct the topology of a graph). If
7685
we need to process nodes in a particular order, then it is best to use a
7786
traversal algorithm on the graph that follows a particular order (for example
78-
depth-first traversal with `traverseDFS()`). This algorithm requires a function
87+
depth-first traversal with `traverse_dfs()`). This algorithm requires a function
7988
that applies to each node in the graph. In this simple example we can just store
8089
the `state` of each node in a vector (unlike Rules and Queries, this function
8190
takes the actual node as argument rather than a `Context` object, see the
8291
documentation for more details):
92+
8393
=#
8494
pop = Graph(axiom = axiom, rules = rule)
8595
states = Int64[]
86-
traversedfs(pop, fun = node -> push!(states, node.state))
96+
traverse_dfs(pop, fun = node -> push!(states, node.state))
8797
states
98+
#=
8899
89-
# Now the states of the nodes are in the same order as they were created:
100+
Now the states of the nodes are in the same order as they were created:
101+
102+
=#
90103
rewrite!(pop)
91104
states = Int64[]
92-
traversedfs(pop, fun = node -> push!(states, node.state))
105+
traverse_dfs(pop, fun = node -> push!(states, node.state))
93106
states

Context/Context.md

+8-6
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11

22
# Context sensitive rules
33

4-
Alejandro Morales - May 2023
4+
Alejandro Morales
5+
6+
Centre for Crop Systems Analysis - Wageningen University
57

68
This examples goes back to a very simple situation: a linear sequence of 3
79
cells. The point of this example is to introduce relational growth rules and
@@ -30,9 +32,9 @@ argument, which corresponds to the context of the father node captured in the
3032
lhs.
3133

3234
```julia
33-
using VPL
35+
using VirtualPlantLab
3436
module types
35-
using VPL
37+
using VirtualPlantLab
3638
struct Cell <: Node
3739
state::Int64
3840
end
@@ -82,7 +84,7 @@ because of how they are internally stored (and because queries are meant to
8284
return collection of nodes rather than reconstruct the topology of a graph). If
8385
we need to process nodes in a particular order, then it is best to use a
8486
traversal algorithm on the graph that follows a particular order (for example
85-
depth-first traversal with `traverseDFS()`). This algorithm requires a function
87+
depth-first traversal with `traverse_dfs()`). This algorithm requires a function
8688
that applies to each node in the graph. In this simple example we can just store
8789
the `state` of each node in a vector (unlike Rules and Queries, this function
8890
takes the actual node as argument rather than a `Context` object, see the
@@ -91,7 +93,7 @@ documentation for more details):
9193
```julia
9294
pop = Graph(axiom = axiom, rules = rule)
9395
states = Int64[]
94-
traversedfs(pop, fun = node -> push!(states, node.state))
96+
traverse_dfs(pop, fun = node -> push!(states, node.state))
9597
states
9698
```
9799

@@ -100,6 +102,6 @@ Now the states of the nodes are in the same order as they were created:
100102
```julia
101103
rewrite!(pop)
102104
states = Int64[]
103-
traversedfs(pop, fun = node -> push!(states, node.state))
105+
traverse_dfs(pop, fun = node -> push!(states, node.state))
104106
states
105107
```

0 commit comments

Comments
 (0)