Skip to content

Commit ea568bd

Browse files
committed
Format code
1 parent 2441957 commit ea568bd

9 files changed

Lines changed: 2003 additions & 1975 deletions

File tree

test/algae.jl

Lines changed: 95 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -38,101 +38,101 @@ end
3838
import .algae
3939

4040
let
41-
#=
42-
Note that in this very example we do not need to store any data or state inside
43-
the nodes, so types `A` and `B` do not require fields.
44-
45-
The axiom is simply defined as an instance of type of `A`:
46-
=#
47-
axiom = algae.A()
48-
49-
#=
50-
The rewriting rules are implemented in VPL as objects of type `Rule`. In VPL, a
51-
rewriting rule substitutes a node in a graph with a new node or subgraph and is
52-
therefore composed of two parts:
53-
54-
1. A condition that is tested against each node in a graph to choose which nodes
55-
to rewrite.
56-
2. A subgraph that will replace each node selected by the condition above.
57-
58-
In VPL, the condition is split into two components:
59-
60-
1. The type of node to be selected (in this example that would be `A` or `B`).
61-
2. A function that is applied to each node in the graph (of the specified type)
62-
to indicate whether the node should be selected or not. This function is
63-
optional (the default is to select every node of the specified type).
64-
65-
The replacement subgraph is specified by a function that takes as input the node
66-
selected and returns a subgraph defined as a combination of node objects.
67-
Subgraphs (which can also be used as axioms) are created by linearly combining
68-
objects that inherit from `Node`. The operation `+` implies a linear
69-
relationship between two nodes and `[]` indicates branching.
70-
71-
The implementation of the two rules of algae growth model in VPL is as follows:
72-
=#
73-
rule1 = Rule(algae.A, rhs = x -> algae.A() + algae.B())
74-
rule2 = Rule(algae.B, rhs = x -> algae.A())
75-
76-
#=
77-
Note that in each case, the argument `rhs` is being assigned an anonymous (aka
78-
*lambda*) function. This is a function without a name that is defined directly
79-
in the assigment to the argument. That is, the Julia expression `x -> A() + B()`
80-
is equivalent to the following function definition:
81-
=#
82-
function rule_1(x)
83-
algae.A() + algae.B()
84-
end
85-
86-
#=
87-
For simple rules (especially if the right hand side is just a line of code) it
88-
is easier to just define the right hand side of the rule with an anonymous
89-
function rather than creating a standalone function with a meaningful name.
90-
However, standalone functions are easier to debug as you can call them directly
91-
from the REPL.
92-
93-
With the axiom and rules we can now create a `Graph` object that represents the
94-
algae organism. The first argument is the axiom and the second is a tuple with
95-
all the rewriting rules:
96-
=#
97-
organism = Graph(axiom = axiom, rules = (rule1, rule2))
98-
99-
#=
100-
If we apply the rewriting rules iteratively, the graph will grow, in this case
101-
representing the growth of the algae organism. The rewriting rules are applied
102-
on the graph with the function `rewrite!()`:
103-
=#
104-
rewrite!(organism)
105-
106-
#=
107-
Since there was only one node of type `A`, the only rule that was applied was
108-
`rule1`, so the graph should now have two nodes of types `A` and `B`,
109-
respectively. We can confirm this by drawing the graph. We do this with the
110-
function `draw()` which will always generate the same representation of the
111-
graph, but different options are available depending on the context where the
112-
code is executed. By default, `draw()` will create a new window where an
113-
interactive version of the graph will be drawn and one can zoom and pan with the
114-
mouse.
115-
=#
116-
import GLMakie
117-
draw(organism)
118-
119-
#=
120-
Notice that each node in the network representation is labelled with the type of
121-
node (`A` or `B` in this case) and a number in parenthesis. This number is a
122-
unique identifier associated to each node and it is useful for debugging
123-
purposes (this will be explained in more advanced examples).
124-
125-
Applying multiple iterations of rewriting can be achieved with a simple loop:
126-
=#
127-
for i = 1:4
41+
#=
42+
Note that in this very example we do not need to store any data or state inside
43+
the nodes, so types `A` and `B` do not require fields.
44+
45+
The axiom is simply defined as an instance of type of `A`:
46+
=#
47+
axiom = algae.A()
48+
49+
#=
50+
The rewriting rules are implemented in VPL as objects of type `Rule`. In VPL, a
51+
rewriting rule substitutes a node in a graph with a new node or subgraph and is
52+
therefore composed of two parts:
53+
54+
1. A condition that is tested against each node in a graph to choose which nodes
55+
to rewrite.
56+
2. A subgraph that will replace each node selected by the condition above.
57+
58+
In VPL, the condition is split into two components:
59+
60+
1. The type of node to be selected (in this example that would be `A` or `B`).
61+
2. A function that is applied to each node in the graph (of the specified type)
62+
to indicate whether the node should be selected or not. This function is
63+
optional (the default is to select every node of the specified type).
64+
65+
The replacement subgraph is specified by a function that takes as input the node
66+
selected and returns a subgraph defined as a combination of node objects.
67+
Subgraphs (which can also be used as axioms) are created by linearly combining
68+
objects that inherit from `Node`. The operation `+` implies a linear
69+
relationship between two nodes and `[]` indicates branching.
70+
71+
The implementation of the two rules of algae growth model in VPL is as follows:
72+
=#
73+
rule1 = Rule(algae.A, rhs = x -> algae.A() + algae.B())
74+
rule2 = Rule(algae.B, rhs = x -> algae.A())
75+
76+
#=
77+
Note that in each case, the argument `rhs` is being assigned an anonymous (aka
78+
*lambda*) function. This is a function without a name that is defined directly
79+
in the assigment to the argument. That is, the Julia expression `x -> A() + B()`
80+
is equivalent to the following function definition:
81+
=#
82+
function rule_1(x)
83+
algae.A() + algae.B()
84+
end
85+
86+
#=
87+
For simple rules (especially if the right hand side is just a line of code) it
88+
is easier to just define the right hand side of the rule with an anonymous
89+
function rather than creating a standalone function with a meaningful name.
90+
However, standalone functions are easier to debug as you can call them directly
91+
from the REPL.
92+
93+
With the axiom and rules we can now create a `Graph` object that represents the
94+
algae organism. The first argument is the axiom and the second is a tuple with
95+
all the rewriting rules:
96+
=#
97+
organism = Graph(axiom = axiom, rules = (rule1, rule2))
98+
99+
#=
100+
If we apply the rewriting rules iteratively, the graph will grow, in this case
101+
representing the growth of the algae organism. The rewriting rules are applied
102+
on the graph with the function `rewrite!()`:
103+
=#
128104
rewrite!(organism)
129-
end
130-
131-
# And we can verify that the graph grew as expected:
132-
draw(organism)
133105

134-
# The network is rather boring as the system is growing linearly (no branching)
135-
# but it already illustrates how graphs can grow rapidly in just a few
136-
# iterations. Remember that the interactive visualization allows adjusting the
137-
# zoom, which is handy when graphs become large.
106+
#=
107+
Since there was only one node of type `A`, the only rule that was applied was
108+
`rule1`, so the graph should now have two nodes of types `A` and `B`,
109+
respectively. We can confirm this by drawing the graph. We do this with the
110+
function `draw()` which will always generate the same representation of the
111+
graph, but different options are available depending on the context where the
112+
code is executed. By default, `draw()` will create a new window where an
113+
interactive version of the graph will be drawn and one can zoom and pan with the
114+
mouse.
115+
=#
116+
import GLMakie
117+
draw(organism)
118+
119+
#=
120+
Notice that each node in the network representation is labelled with the type of
121+
node (`A` or `B` in this case) and a number in parenthesis. This number is a
122+
unique identifier associated to each node and it is useful for debugging
123+
purposes (this will be explained in more advanced examples).
124+
125+
Applying multiple iterations of rewriting can be achieved with a simple loop:
126+
=#
127+
for i = 1:4
128+
rewrite!(organism)
129+
end
130+
131+
# And we can verify that the graph grew as expected:
132+
draw(organism)
133+
134+
# The network is rather boring as the system is growing linearly (no branching)
135+
# but it already illustrates how graphs can grow rapidly in just a few
136+
# iterations. Remember that the interactive visualization allows adjusting the
137+
# zoom, which is handy when graphs become large.
138138
end

test/context.jl

Lines changed: 56 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -32,72 +32,72 @@ lhs.
3232
=#
3333
using VPL
3434
module types
35-
using VPL
36-
struct Cell <: Node
37-
state::Int64
38-
end
35+
using VPL
36+
struct Cell <: Node
37+
state::Int64
38+
end
3939
end
4040
import .types: Cell
4141

4242
let
43-
function transfer(context)
44-
if has_parent(context)
45-
return (true, (parent(context),))
46-
else
47-
return (false, ())
43+
function transfer(context)
44+
if has_parent(context)
45+
return (true, (parent(context),))
46+
else
47+
return (false, ())
48+
end
4849
end
49-
end
50-
rule = Rule(
51-
Cell,
52-
lhs = transfer,
53-
rhs = (context, father) -> Cell(data(father).state),
54-
captures = true,
55-
)
56-
axiom = Cell(1) + Cell(0) + Cell(0)
57-
pop = Graph(axiom = axiom, rules = rule)
50+
rule = Rule(
51+
Cell,
52+
lhs = transfer,
53+
rhs = (context, father) -> Cell(data(father).state),
54+
captures = true,
55+
)
56+
axiom = Cell(1) + Cell(0) + Cell(0)
57+
pop = Graph(axiom = axiom, rules = rule)
5858

59-
#=
60-
In the original state defined by the axiom, only the first node contains a state
61-
of 1. We can retrieve the state of each node with a query. A `Query` object is a
62-
like a `Rule` but without a right-hand side (i.e., its purpose is to return the
63-
nodes that match a particular condition). In this case, we just want to return
64-
all the `Cell` nodes. A `Query` object is created by passing the type of the
65-
node to be queried as an argument to the `Query` function. Then, to actually
66-
execute the query we need to use the `apply` function on the graph.
67-
=#
68-
getCell = Query(Cell)
69-
apply(pop, getCell)
59+
#=
60+
In the original state defined by the axiom, only the first node contains a state
61+
of 1. We can retrieve the state of each node with a query. A `Query` object is a
62+
like a `Rule` but without a right-hand side (i.e., its purpose is to return the
63+
nodes that match a particular condition). In this case, we just want to return
64+
all the `Cell` nodes. A `Query` object is created by passing the type of the
65+
node to be queried as an argument to the `Query` function. Then, to actually
66+
execute the query we need to use the `apply` function on the graph.
67+
=#
68+
getCell = Query(Cell)
69+
apply(pop, getCell)
7070

71-
# If we rewrite the graph one we will see that a second cell now has a state of 1.
72-
rewrite!(pop)
73-
apply(pop, getCell)
71+
# If we rewrite the graph one we will see that a second cell now has a state of 1.
72+
rewrite!(pop)
73+
apply(pop, getCell)
7474

75-
# And a second iteration results in all cells have a state of 1
76-
rewrite!(pop)
77-
apply(pop, getCell)
75+
# And a second iteration results in all cells have a state of 1
76+
rewrite!(pop)
77+
apply(pop, getCell)
7878

79-
#=
80-
Note that queries may not return nodes in the same order as they were created
81-
because of how they are internally stored (and because queries are meant to
82-
return collection of nodes rather than reconstruct the topology of a graph). If
83-
we need to process nodes in a particular order, then it is best to use a
84-
traversal algorithm on the graph that follows a particular order (for example
85-
depth-first traversal with `traverseDFS()`). This algorithm requires a function
86-
that applies to each node in the graph. In this simple example we can just store
87-
the `state` of each node in a vector (unlike Rules and Queries, this function
88-
takes the actual node as argument rather than a `Context` object, see the
89-
documentation for more details):
90-
=#
79+
#=
80+
Note that queries may not return nodes in the same order as they were created
81+
because of how they are internally stored (and because queries are meant to
82+
return collection of nodes rather than reconstruct the topology of a graph). If
83+
we need to process nodes in a particular order, then it is best to use a
84+
traversal algorithm on the graph that follows a particular order (for example
85+
depth-first traversal with `traverseDFS()`). This algorithm requires a function
86+
that applies to each node in the graph. In this simple example we can just store
87+
the `state` of each node in a vector (unlike Rules and Queries, this function
88+
takes the actual node as argument rather than a `Context` object, see the
89+
documentation for more details):
90+
=#
9191

92-
pop = Graph(axiom = axiom, rules = rule)
93-
states = Int64[]
94-
traversedfs(pop, fun = node -> push!(states, node.state))
95-
states
92+
pop = Graph(axiom = axiom, rules = rule)
93+
states = Int64[]
94+
traversedfs(pop, fun = node -> push!(states, node.state))
95+
states
9696

97-
# Now the states of the nodes are in the same order as they were created:
98-
rewrite!(pop)
99-
states = Int64[]
100-
traversedfs(pop, fun = node -> push!(states, node.state))
101-
states
97+
# Now the states of the nodes are in the same order as they were created:
98+
rewrite!(pop)
99+
states = Int64[]
100+
traversedfs(pop, fun = node -> push!(states, node.state))
101+
states
102102

103103
end

0 commit comments

Comments
 (0)