These are the human proofs of Straight-line program, at full length.
Correctness of evaluation, reverse-mode gradient, degree bound and zero test for straight-line programs full
This proof shows: correctness.
Setting.R is a commutative ring and γ1,…,γL is a program in n variables, as defined on the page. Its values v1,…,vL∈R[x1,…,xn] are defined by vj=xi, vj=c or vj=va∘vb, according to γj, and f=vL (with f=0 if L=0). For ξ∈Rn let ϕξ:R[x1,…,xn]→R be evaluation at ξ.
Theorem. (a) EVALUATE returns f(ξ), and with reduction modulo p it returns f(ξ)modp. (b) GRADIENT returns (∂f/∂x1(ξ),…,∂f/∂xn(ξ)), where ∂/∂xi is the formal derivative. (c) The propagated bound δj satisfies degvj≤δj, with δj=−1 only if vj=0. (d) If R=Z/pZ and f=0 has total degree at most D, then s independent uniform points all give 0 with probability at most (D/p)s; if f=0, they all give 0.
Proof of (a)
By induction on j, the stored value is ϕξ(vj). For a load this is the definition. For vj=va∘vb with a,b<j, the stored value is ϕξ(va)∘ϕξ(vb)=ϕξ(va∘vb), since ϕξ is a ring homomorphism. The map R→R/pR is also a ring homomorphism, so reducing after each step gives the image of ϕξ(vj), by the same induction. □
Proof of (b)
Introduce new indeterminates y1,…,yL. For j=L,L−1,…,0 define Fj∈R[x1,…,xn,y1,…,yj] by FL=yL and
Substituting the values for the y's shows that Fj(x,v1,…,vj)=f for every j, and F0=f. Write ⋅ˉ for evaluation at x=ξ, yk=vk(ξ).
Claim. When the loop of G4 is about to handle index j, we have wk=∂Fj/∂yk for all k≤j, and gi=∂Fj/∂xi for all i.
For j=L: FL=yL, so ∂FL/∂yL=1 and all other derivatives are 0, which matches G2 and G3.
Step from j to j−1. By the chain rule for formal derivatives (which holds over any commutative ring, because both sides are R-linear derivations that agree on monomials),
∂u∂Fj−1=(∂u∂Fj+∂yj∂Fj⋅∂u∂ej)yj←ej
for every indeterminate u other than yj. After evaluation, the substitution yj←ej has no effect, because eˉj=vj(ξ) by (a). So the new value for u is the old one plus wˉj⋅∂ej/∂u, where wj is the current value at index j. Now ∂ej/∂u is: 1 for u=xi if γj=xi (step G5); 1 for u=ya and ±1 for u=yb if γj=va±vb (step G6); yb for u=ya and ya for u=yb if γj=va×vb, with sum 2ya if a=b, and the code adds both terms (step G7); and 0 in all other cases and for constants. These are exactly the updates of the loop body, so the claim holds for j−1.
At the end (j=0), gi=∂F0/∂xi=∂f/∂xi(ξ). If L=0, then f=0 and G2 returns the zero vector, which is correct. □
Cost. The forward pass is L operations. In the backward pass each instruction costs at most two multiplications and two additions, so the total is at most 5L operations.
Proof of (c)
By induction on j. Loads: degxi=1, degc=0 for c=0, and the bound −1 is used only for c=0. For va±vb: deg(va±vb)≤max(degva,degvb)≤max(δa,δb), and if the maximum is −1 then both are 0, so the sum is 0. For vavb: deg(vavb)≤degva+degvb over any commutative ring (the product of the top parts may vanish, but no larger degree can appear), and the code sets −1 exactly when one factor has bound −1, in which case that factor is 0 and so is the product. □
Proof of (d)
If f=0 then f(ξ)=0 for all ξ, so by (a) every point gives 0. If f=0 has total degree at most D, the Schwartz-Zippel lemma gives Pr[f(ξ)=0]≤D/p for a uniform ξ∈(Z/pZ)n. The points are independent, so all s give 0 with probability at most (D/p)s. By (c), the propagated bound δL can serve as D. ■