Composition
using Catlab
using DiagrammaticEquations
using Decapodes
Dependencies
using Catlab
using DiagrammaticEquations
using Decapodes
Decapodes composition is formally known as an "operad algebra". That means that we don't have to encode our composition in a single undirected wiring diagram (UWD) and then apply it. Rather, we can define several UWDs, compose those, and then apply those. Of course, since the output of oapply is another Decapode, we could perform an intermediate oapply, if that is convenient. In this tutorial we will learn how to use this capability to define more complex models, and how this modularity allows us to swap out models.
Besides it being convenient to break apart large UWDs into component UWDs, this hierarchical composition can enforce rules on our physical quantities.
Example: Klausmeier
We will study how the Klausmeier model uses the operad algebra to describe a phenomenon of vegetation patterns can be governed by the interaction of two different dynamics.
# See Klausmeier Equation 2.a
Hydrodynamics = @decapode begin
(n,w)::DualForm0
dX::Form1
(a,ν)::Constant
∂ₜ(w) == a - w - w * n^2 + ν * L(dX, w)
end
# See Klausmeier Equation 2.b
Phytodynamics = @decapode begin
(n,w)::DualForm0
m::Constant
∂ₜ(n) == w * n^2 - m*n + Δ(n)
end
However let's for a moment pretend we don't have a very good understanding of the hydrodynamics. We'll create an incorrect model:
WrongHydrodynamics = @decapode begin
(n,w)::DualForm0
dX::Form1
∂ₜ(w) == L(dX, w)
end
Now that we have our two component models, we can specify a means of composing them via a composition pattern. This defines placeholder models which accept variables as inputs. If the variables between any two models are the same, then we have asserted that they are shared. For example, in this @relation
diagram, we assert that there are two models, phyto
and hydro
, which each share the N
and W
variables.
# Specify Composition
compose_klausmeier = @relation () begin
phyto(N, W)
hydro(N, W)
end
draw_composition(compose_klausmeier)
We apply our composition pattern by plugging in component Decapodes, and specifying which internal quantities to share along edges. Decapodes are formalized via the field of Applied Category Theory. A practical consequence here is that we can view a Decapode as a sort of computation graph.
# Apply Composition
klausmeier_cospan = oapply(compose_klausmeier,
[Open(Phytodynamics, [:n, :w]),
Open(WrongHydrodynamics, [:n, :w])])
Klausmeier = apex(klausmeier_cospan)
to_graphviz(Klausmeier)
Let's pretend our understanding of the hydrodynamics model has improved. Since the composition pattern has not changed, we can just substitute the WrongHydrodynamics
model out for the correct one.
# Apply Composition
klausmeier_cospan = oapply(compose_klausmeier,
[Open(Phytodynamics, [:n, :w]),
Open(Hydrodynamics, [:n, :w])])
Klausmeier = apex(klausmeier_cospan)
to_graphviz(Klausmeier)