
A block $b$ is composed of $N$ ports $b_{p1}\dots b_{pN}$, one terminal $b_t$, and a $N$-ary function mapping values on the ports to a value on the terminal. The value of this function is denoted $b(b_{p1}\dots b_{pN})$.

A wire connects a terminal to a port. For a wire $w$, let $w_p$ and $w_t$ denote its port and terminal.
Terminals and ports are nodes. Nodes are composed of a set of values and a value. Let $U_n$ denote the set associated with the node $n$. At time $t$, let $n(t)$ denote the value of $n$. The value of a node is either an element of its space or nothing. That is, $\forall t(n(t)\in U_n\lor n(t)\equiv\varnothing)$.
A wire connecting port $p$ to terminal $t$ is valid if $U_p\subseteq U_t$. That is, all of the port's values are admissible values for the terminal.
A block diagram is composed of a set $B$ of blocks, and a set $W$ of valid wires. For a block $b\in B$ at time $t$, if $\exists b_p,b_p(t)\equiv\varnothing$, then $b(b_{p1}\dots b_{pN})\equiv\varnothing$. That is, if any of $b$'s ports have no value, then $b$'s function outputs no value.
To execute a block diagram, the value of each block's port is updated, then values are propogated along its wires.

_Update June 6._ This execution algorithm isn't quite right. Consider the block diagram from [First GDS](https://hackmd.io/lFTRNOAlTWuVCxgzFieV3w):

Suppose at $t=0$ each terminal has some initial state. At $t=1$, a new value for $\Delta$ is selected and this is propogated to the polar-to-cartesian block; However, at this point the output values of this block are not updated, and in turn the output values of the cartesian-to-polar block are not updated. At $t=2$, a new value for $\Delta$ is selected and added to the same polar coordinates used at $t=1$ (as the output values of the cartesian-to-polar block were updated). From then on, things are silly and weird.
To make this concrete, the program below implements the specification above.
```julia
struct Node{Space}
space::Type
value::Dict{UInt,Space}
function Node(t::Type)
new{t}(t, Dict())
end
end
struct Block
terminals::Vector{Node}
port::Node
logic::Function
end
struct Wire
port::Node
terminal::Node
function Wire(port::Node, terminal::Node)
new(port, terminal)
end
end
# Defining blocks
cartesian2radius = Block([Node(Int), Node(Int)], Node(Real), (x, y) -> sqrt(x*x + y*y))
cartesian2theta = Block([Node(Int), Node(Int)], Node(Real), (x, y) -> atan(y, x))
addDelta = Block([Node(Real)], Node(Real), (theta) -> theta + rand()*2*pi)
polar2x = Block([Node(Real), Node(Real)], Node(Int), (r, th) -> floor(r * cos(th)))
polar2y = Block([Node(Real), Node(Real)], Node(Int), (r, th) -> floor(r * sin(th)))
blocks = [cartesian2radius, cartesian2theta, addDelta, polar2x, polar2y]
# Wiring
wires = []
push!(wires, Wire(cartesian2radius.port, polar2x.terminals[1]))
push!(wires, Wire(cartesian2radius.port, polar2y.terminals[1]))
push!(wires, Wire(cartesian2theta.port, addDelta.terminals[1]))
push!(wires, Wire(addDelta.port, polar2x.terminals[2]))
push!(wires, Wire(addDelta.port, polar2y.terminals[2]))
push!(wires, Wire(polar2x.port, cartesian2radius.terminals[1]))
push!(wires, Wire(polar2y.port, cartesian2radius.terminals[2]))
push!(wires, Wire(polar2x.port, cartesian2theta.terminals[1]))
push!(wires, Wire(polar2y.port, cartesian2theta.terminals[2]))
# Initial state
time = 0
cartesian2radius.port.value[time] = 10
cartesian2theta.port.value[time] = 0
while cartesian2radius.port.value[time] > 0
global time += 1
for b in blocks
v = []
hasvs = true
for n in b.terminals
if !haskey(n.value, time - 1)
hasvs = false
break
end
push!(v, n.value[time-1])
end
if hasvs
b.port.value[time] = b.logic(v...)
elseif haskey(b.port.value, time - 1)
b.port.value[time] = b.port.value[time-1]
end
end
for w in wires
if haskey(w.port.value, time)
w.terminal.value[time] = w.port.value[time]
end
end
if haskey(cartesian2radius.port.value, time)
println(cartesian2radius.port.value[time])
end
end
```
Running it results in:
```
# ...
1.0
12.529964086141668
1.0
12.041594578792296
1.0
13.0
0.0
```
Which has the described behavior of interleaving the outputs.
Another stab which resolves this issue:
```julia
mutable struct Node{Space}
space::Type
value::Vector{Space}
function Node(t::Type)
new{t}(t, Vector())
end
end
mutable struct Block
terminals::Vector{Node}
port::Node
logic::Function
name::String
end
wire(port, terminal) = terminal.value = port.value
floor2zero(x) = x < 0 ? ceil(x) : floor(x)
cartesian2radius = Block([Node(Int), Node(Int)], Node(Real), (x, y) -> sqrt(x*x + y*y), "c2r")
cartesian2theta = Block([Node(Int), Node(Int)], Node(Real), (x, y) -> atan(y, x), "c2t")
addDelta = Block([Node(Real)], Node(Real), (theta) -> theta + rand()*2*pi, "Δ")
polar2x = Block([Node(Real), Node(Real)], Node(Int), (r, th) -> floor2zero(r * cos(th)), "p2x")
polar2y = Block([Node(Real), Node(Real)], Node(Int), (r, th) -> floor2zero(r * sin(th)), "p2y")
blocks = [cartesian2radius, cartesian2theta, addDelta, polar2x, polar2y]
wire(cartesian2radius.port, polar2x.terminals[1])
wire(cartesian2radius.port, polar2y.terminals[1])
wire(cartesian2theta.port, addDelta.terminals[1])
wire(addDelta.port, polar2x.terminals[2])
wire(addDelta.port, polar2y.terminals[2])
wire(polar2x.port, cartesian2radius.terminals[1])
wire(polar2y.port, cartesian2radius.terminals[2])
wire(polar2x.port, cartesian2theta.terminals[1])
wire(polar2y.port, cartesian2theta.terminals[2])
push!(cartesian2radius.port.value, 10)
push!(cartesian2theta.port.value, 0)
while cartesian2radius.port.value[length(cartesian2radius.port.value)] > 0
for block in blocks
v = []
g = true
for node in block.terminals
if length(block.port.value) > length(node.value)
g = false
break
end
push!(v, node.value[max(length(block.port.value), 1)])
end
if g
y = block.logic(v...)
push!(block.port.value, y)
end
end
end
```