Current reading:resources and reusable boundaries · wiring and its algebra · course-by-course dynamics. This earlier working preserves function-composition examples and a manually coupled dynamics experiment. Its simplified interfaces and numeric “House” score are teaching choices; they do not reconstruct the complete resource boundary or establish physical performance.
A simple “build walls then put on a roof” project, modeled compositionally with wiring diagrams,
with illustrations of equality laws (operad algebra law + interchange), plus a toy hybrid simulation:
wall height (discrete) and roof stability (continuous).
This is the project “scope” view: boxes are tasks; wires are typed resources / artefacts carried across tasks.
The diagram is deliberately simple and left-to-right.
Colours group related roles; matching colours do not establish matching types. Read the named ports and signatures. Bundled material inputs and signal branches are shorthand in this older drawing; an exact one-wire-per-port resource diagram would need separate ports or explicit unpacking/copying operations.
Tip: tap/click any wire label in the diagram to see what it represents.
(No hover required — this works on mobile.)
Interpretation rule of thumb
A box is a process. A wire is a “thing” (material, information, constraint, state) whose
type stays consistent end-to-end. Composition is “plugging outputs into inputs”.
In operad terms: a wiring diagram is syntax; choosing a meaning for each box
(e.g., a dynamical system, a function, a resource transformer) is semantics.
L = set-out line / reference, produced before wall building
W = walls, produced before roof install
Stab = roof stability signal/state (used for assurance)
Why this catches scope mistakes
With distinct declared types, a downstream task expecting “Walls” cannot accept “Damaged walls” without
a suitable conversion. This page illustrates that modelling principle; it does not implement a general type checker for its diagrams.
What we model in the simulation
We treat “wall height” as a discrete state updated once per day (difference equation), while “roof stability”
evolves continuously (an ODE integrated by Euler in-browser).
2) Equality laws and bounded illustrations
Here are two kinds of equality that matter in compositional project thinking:
(A) equality from symmetric monoidal structure (interchange law), and
(B) equality from the operad algebra substitution law (hierarchical vs flattened modeling).
A) Interchange law equality (parallel vs sequential grouping)
Suppose we are building two independent walls (Left, Right). Each wall has two steps:
Mix mortar, then Build wall. We can group the work in two ways:
Interchange equates these two well-typed ways of grouping independent processes. Here both pictures are
drawn from the same underlying diagram (same boxes + same wires); only the grouping boundaries differ.
Not checked
This button compares two layout/group variants copied from one diagram. It illustrates interchange;
it does not compile independent expressions or perform a general isomorphism check up to relabelling.
Interchange: two groupings, same diagram
B) Operad algebra law: hierarchical vs flattened model
Let ψ be the “Prep” subdiagram (mix mortar + set out line),
and φ be the outer diagram (Prep feeding Wall+Roof).
There are two strategies:
By the operad algebra axiom, total = total' as functions,
i.e. they have identical denotational semantics.
Not checked
The button evaluates both composite functions on one input vector. Agreement checks that example;
it does not prove equality on all inputs. The general substitution law is a requirement on an operad algebra,
and needs a construction or argument showing that the interpretation preserves substitution.
Hierarchical term vs flattened term
Output check not run yet.
The law and the evidence shown here
There are two complementary notions:
Axiomatic proof: The equality follows from the defining laws of the structure you chose
(SMC axioms like interchange; operad-algebra axioms like substitution preservation).
Implemented illustrations: Compare two variants of one fixed diagram, then evaluate
hierarchical and flattened functions on one sample. Neither button is a general normal-form proof procedure.
A separate term compiler and a justified diagram normal form could support stronger automated equality checks.
The linked current algebra essay makes the interfaces and substitution argument explicit.
The goal is not a perfect engineering model — it’s a compositional “toy” that is faithful to the
idea of mixing discrete project events (daily progress) with continuous physical dynamics (stability).
Parameters
Ready
Tap/click on a chart to pin a data tooltip at the nearest timepoint.
Derived milestones
(Run the simulation to populate this.)
Dynamics wiring diagram (the “semantic” model)
The diagram below sketches the manually coupled hybrid model: a height threshold and delay derived
from the discrete wall subsystem drive the continuous roof subsystem. Those conversions are implemented
in the simulation; a literal typed diagram would show them as boxes.
Wall height over time (discrete updates)
Roof stability over time (continuous ODE)
Model equations used in-browser
Discrete wall update (daily):
hn+1 = min(Htarget, hn + rwall) for n = 0,1,2,...
Coupling rule (hybrid):
kinstall(t) = 0 until walls are complete (h ≥ Htarget) and a delay has passed.
This is intentionally minimal: it’s enough to demonstrate how a wiring diagram organizes
the dependency of one subsystem’s inputs on another subsystem’s outputs.
4) Julia / AlgebraicJulia (AlgebraicDynamics) notebook template
This page is fully self-contained and runs its simulation in JavaScript.
Below is a Julia notebook-style template that mirrors the same structure using the AlgebraicJulia ecosystem:
wiring diagrams (Catlab) + operad algebras (AlgebraicDynamics) + solvers (DifferentialEquations).
Notebook status and scope
The original generation run did not execute Julia. The code below is a preserved, unverified template;
its package APIs and results need checking in a Julia environment before relying on it.
It illustrates the operad-algebra idea by defining primitive systems and a wiring pattern. The actual
simulation couples a daily wall loop to a separate roof ODE manually. It does not execute or verify
mixed discrete/continuous composition with oapply.
What the template attempts
Installs Catlab and AlgebraicDynamics
Builds a wiring diagram for wall→roof coupling
Defines a discrete wall machine + continuous roof machine (same equations as above)
Simulates wall height (discrete) and roof stability (continuous)
Visualizes diagrams and plots (your plotting library of choice)
Julia notebook cells
# ╔══════════════════════════════════════════════════════════════════════╗
# ║ 0) Package install (first run) ║
# ╚══════════════════════════════════════════════════════════════════════╝
import Pkg
Pkg.activate(".")
Pkg.add([
"Catlab",
"AlgebraicDynamics",
"OrdinaryDiffEq", # ODE solvers
"DiffEqCallbacks", # hybrid / callbacks (optional)
"Plots" # or CairoMakie, GLMakie, etc.
])
# ╔══════════════════════════════════════════════════════════════════════╗
# ║ 1) Imports ║
# ╚══════════════════════════════════════════════════════════════════════╝
using Catlab
using Catlab.WiringDiagrams
using AlgebraicDynamics
using OrdinaryDiffEq
using DiffEqCallbacks
using Plots
# ╔══════════════════════════════════════════════════════════════════════╗
# ║ 2) Define primitive subsystems ║
# ╚══════════════════════════════════════════════════════════════════════╝
# Discrete wall height (daily difference equation)
# State u = [h], Input x = [work_on], Output y = [h]
wall = DiscreteMachine{Float64}(1, 1, 1,
(u, x, p, t) -> begin
h = u[1]
work_on = x[1]
h2 = min(p[:H_target], h + work_on * p[:wall_rate])
return [h2]
end,
u -> u
)
# Continuous roof stability
# State u = [s], Inputs x = [walls_ready, wind], Output y = [s]
roof = ContinuousMachine{Float64}(1, 2, 1,
(u, x, p, t) -> begin
s = u[1]
walls_ready = x[1]
wind = x[2]
install = walls_ready * p[:install_rate]
ds = install * (1 - s) - p[:decay_rate] * wind * s
return [ds]
end,
u -> u
)
# ╔══════════════════════════════════════════════════════════════════════╗
# ║ 3) Build a wiring diagram (directed) ║
# ╚══════════════════════════════════════════════════════════════════════╝
# We conceptually want: WallHeight ─▶ (determine walls_ready) ─▶ Roof
# AlgebraicDynamics wiring-diagram composition expects all primitives
# to live in the *same* semantic category (all discrete or all continuous).
# For a hybrid simulation, we do:
# - run the wall DiscreteMachine for daily steps
# - feed a walls_ready signal into the roof ContinuousMachine, solved as an ODE
#
# Still, we can use Catlab to *visualize* the wiring diagram:
d = WiringDiagram([:work_on, :wind], [:height, :stability])
wall_box = add_box!(d, Box(:WallDiscrete, [:work_on], [:height]))
roof_box = add_box!(d, Box(:RoofContinuous, [:walls_ready, :wind], [:stability]))
# external -> wall input
add_wire!(d, (input_id(d), 1) => (wall_box, 1)) # work_on -> WallDiscrete
# wall output -> roof input 1 (walls_ready)
# In a hybrid sim we'll compute walls_ready = height >= H_target
# Here we visualize the conceptual dependency as a wire:
add_wire!(d, (wall_box, 1) => (roof_box, 1)) # height -> RoofContinuous.walls_ready (conceptual)
# external wind -> roof input 2
add_wire!(d, (input_id(d), 2) => (roof_box, 2)) # wind -> RoofContinuous
# outputs
add_wire!(d, (wall_box, 1) => (output_id(d), 1)) # height out
add_wire!(d, (roof_box, 1) => (output_id(d), 2)) # stability out
to_graphviz(d) |> display
# ╔══════════════════════════════════════════════════════════════════════╗
# ║ 4) Hybrid simulation (one simple approach) ║
# ╚══════════════════════════════════════════════════════════════════════╝
H_target = 2.4
wall_rate = 0.2
delay = 1.0 # days after wall completion before roof starts
install_rate = 1.2
decay_rate = 0.45
# Discrete wall simulation (daily)
T_days = 30
h = 0.0
height = Float64[]
time_d = Int[]
wall_done_day = nothing
for day in 0:T_days
push!(time_d, day)
push!(height, h)
if h < H_target
h = min(H_target, h + wall_rate)
if h >= H_target && wall_done_day === nothing
wall_done_day = day
end
end
end
# Continuous roof ODE, driven by walls_ready(t) and wind(t)
wind(t) = 1.0 + 0.35*sin(2π*t/7)
walls_ready(t) = (wall_done_day === nothing) ? 0.0 :
(t >= (wall_done_day + delay) ? 1.0 : 0.0)
function roof_ode!(du, u, p, t)
s = u[1]
w = wind(t)
ready = walls_ready(t)
install = ready * p[:install_rate]
du[1] = install * (1 - s) - p[:decay_rate] * w * s
end
u0 = [0.0]
p = Dict(:install_rate => install_rate, :decay_rate => decay_rate)
prob = ODEProblem(roof_ode!, u0, (0.0, T_days), p)
sol = solve(prob, Tsit5(); dtmax=0.1)
# Plot results
plt1 = plot(time_d, height; label="wall height", xlabel="day", ylabel="height")
plt2 = plot(sol.t, getindex.(sol.u,1); label="roof stability", xlabel="day", ylabel="stability")
plot(plt1, plt2; layout=(2,1))
Note: the “hybrid” coupling is implemented explicitly (wall as daily loop, roof as ODE).
If you want a single integrated hybrid state vector, consider DifferentialEquations callbacks
to apply discrete updates inside a continuous solve.
How this relates to operads (conceptually)
The wiring diagram is the syntax, and each “machine” (wall, roof) is a semantic object
that can be composed along wires. This is the “systems-as-algebras” viewpoint: you pick an operad
of diagrams and give an algebra that interprets them as concrete systems.