Algorithm Search⌘K

Proofs: Expression tree

These are the human proofs of Expression tree, at full length.

EVAL, SUBS and DIFF on expression trees are correct full

This proof shows: correctness, termination.

Let ee satisfy the invariant (T). For a node uu write ℓ(u)\ell(u) and i(u)i(u) for the numbers of leaves and of operator nodes in the subtree of uu, counting a shared child once per occurrence. Since each operator has two children, ℓ(u)=i(u)+1\ell(u) = i(u) + 1. Write [ ⁣[u] ⁣]ρ[\![u]\!]_\rho for the value of uu, defined by structural recursion as on the main page.

Lemma 1 (stack lemma for EVAL). Suppose that at the start of a pass of the loop of line L2 the stacks are S=S0⋅(u,false)S = S_0 \cdot (u, \text{false}) and V=WV = W. Then after exactly p(u)=ℓ(u)+2i(u)p(u) = \ell(u) + 2 i(u) passes the stacks are S=S0S = S_0 and V=W⋅[ ⁣[u] ⁣]ρV = W \cdot [\![u]\!]_\rho, and at no time in between is SS shorter than S0S_0 or VV shorter than WW, so no entry of S0S_0 or WW is read or changed.

Proof. By induction on the height of uu. If uu is a constant cc, the pass pops (u,false)(u, \text{false}) at line L3 and pushes cc at line L4, so after 1=p(u)1 = p(u) pass S=S0S = S_0 and V=W⋅cV = W \cdot c. A symbol ss is the same with line L5 and ρ(s)\rho(s). If u=a∘bu = a \circ b is an operator node, the first pass pops (u,false)(u, \text{false}) and line L6 leaves S=S0⋅(u,true)⋅(b,false)⋅(a,false)S = S_0 \cdot (u, \text{true}) \cdot (b, \text{false}) \cdot (a, \text{false}) with V=WV = W. By induction for aa, with S0⋅(u,true)⋅(b,false)S_0 \cdot (u, \text{true}) \cdot (b, \text{false}) in the role of S0S_0, after p(a)p(a) passes S=S0⋅(u,true)⋅(b,false)S = S_0 \cdot (u, \text{true}) \cdot (b, \text{false}) and V=W⋅[ ⁣[a] ⁣]ρV = W \cdot [\![a]\!]_\rho. By induction for bb, after p(b)p(b) more passes S=S0⋅(u,true)S = S_0 \cdot (u, \text{true}) and V=W⋅[ ⁣[a] ⁣]ρ⋅[ ⁣[b] ⁣]ρV = W \cdot [\![a]\!]_\rho \cdot [\![b]\!]_\rho. The next pass pops (u,true)(u, \text{true}); the tests of lines L4 to L6 fail, since uu is an operator and done is true, so line L7 pops b′=[ ⁣[b] ⁣]ρb' = [\![b]\!]_\rho, then a′=[ ⁣[a] ⁣]ρa' = [\![a]\!]_\rho, and pushes a′∘b′=[ ⁣[u] ⁣]ρa' \circ b' = [\![u]\!]_\rho. The total is 1+p(a)+p(b)+1=ℓ(a)+ℓ(b)+2(i(a)+i(b)+1)=p(u)1 + p(a) + p(b) + 1 = \ell(a) + \ell(b) + 2(i(a) + i(b) + 1) = p(u) passes. During the passes for aa and bb, the induction hypothesis keeps SS and VV at least as long as the stated prefixes, which contain S0S_0 and WW. □\square

Theorem 1. EVAL(e,ρ)(e, \rho) terminates after p(e)=n+i(e)p(e) = n + i(e) passes and returns [ ⁣[e] ⁣]ρ[\![e]\!]_\rho, provided ρ\rho defines every symbol of ee.

Proof. Line L1 sets S=(e,false)S = (e, \text{false}) with S0S_0 empty and VV empty. By Lemma 1, after p(e)p(e) passes SS is empty, so the loop of line L2 stops, and V=[ ⁣[e] ⁣]ρV = [\![e]\!]_\rho has one element, which line L8 returns. Since n=ℓ(e)+i(e)n = \ell(e) + i(e), the count is n+i(e)n + i(e). ■\blacksquare for EVAL.

Lemma 2 (postorder). The walk used by SUBS and DIFF lists every node occurrence of ee exactly once, and each operator node after both of its children.

Proof. The walk is EVAL with "append uu to the output" in place of lines L4, L5 and L7. Lemma 1, with the output list in place of VV, shows that the occurrences in the subtree of uu are output during its p(u)p(u) passes, with uu itself last. By induction this lists the occurrences of the left subtree, then of the right subtree, then uu. □\square

Theorem 2. SUBS(e,x,r)(e, x, r) returns e[x:=r]e[x := r], the tree obtained by replacing each leaf xx by rr. Hence, by the substitution lemma, [ ⁣[SUBS(e,x,r)] ⁣]ρ=[ ⁣[e] ⁣]ρ[x↦[ ⁣[r] ⁣]ρ][\![\text{SUBS}(e, x, r)]\!]_\rho = [\![e]\!]_{\rho[x \mapsto [\![r]\!]_\rho]}.

Proof. We show R[u]=u[x:=r]R[u] = u[x := r] for each node uu, by induction along the postorder of Lemma 2. A leaf that is the symbol xx gets rr at line S2, and every other leaf gets itself at line S3; this is the definition of substitution on leaves. For an operator node u=a∘bu = a \circ b, both children were processed earlier, so R[a]=a[x:=r]R[a] = a[x := r] and R[b]=b[x:=r]R[b] = b[x := r], and line S4 gives R[a]∘R[b]=(a∘b)[x:=r]R[a] \circ R[b] = (a \circ b)[x := r]. A node that occurs more than once gets the same result each time, since the computation depends only on its subtree. Line S5 returns R[e]R[e]. The substitution lemma follows by induction on ee: for u=xu = x both sides are [ ⁣[r] ⁣]ρ[\![r]\!]_\rho, for other leaves both are the value of the leaf, and for u=a∘bu = a \circ b both sides are computed from the children by the same operation. □\square

Theorem 3. For each environment ρ\rho, [ ⁣[DIFF(e,x)] ⁣]ρ=∂∂x[ ⁣[e] ⁣][\![\text{DIFF}(e, x)]\!]_\rho = \frac{\partial}{\partial x} [\![e]\!] evaluated at ρ\rho, where [ ⁣[e] ⁣][\![e]\!] is the polynomial function that ee denotes.

Proof. The smart constructors return an expression with the same value as the plain node: folding two constants computes the value, and the rules 0+u=u0 + u = u, u−0=uu - 0 = u, 0⋅u=00 \cdot u = 0, 1⋅u=u1 \cdot u = u and their mirror images hold in every ring. So it suffices to check lines D2 to D6 with plain nodes, by induction along the postorder. Constants have derivative 0 and a symbol ss has derivative 1 if s=xs = x and 0 otherwise (lines D2, D3). For u=a±bu = a \pm b and u=a×bu = a \times b, lines D4 and D5 are the sum and product rules applied to the children's derivatives, which are correct by induction. For u=aku = a^k, the power rule ∂(ak)=kak−1∂a\partial(a^k) = k a^{k-1} \partial a holds for k≥1k \ge 1, where a0a^0 means 1, and ∂(a0)=∂1=0\partial(a^0) = \partial 1 = 0; line D6 and the code use the factor 1 for k=1k = 1 and aa for k=2k = 2, both of which equal ak−1a^{k-1}. □\square

Termination and cost. Each walk is the loop of Lemma 1, which performs n+i(e)≤2nn + i(e) \le 2n passes, and each pass does O(1)O(1) stack and dictionary operations and at most a constant number of node constructions. So SUBS and DIFF stop after O(n)O(n) steps and create O(n)O(n) nodes. ■\blacksquare

Back to Expression tree