# Alterna AI chapter 09: verified standalone examples
x,w,b=2,3,1
a=x*w; z=a+b; L=z*z
assert (a,z,L)==(6,7,49)


z=7
grad_z=0
grad_z+=1*z
grad_z+=1*z
assert grad_z==14


x,w,b=2,3,1
z=x*w+b
assert [2*z*w,2*z*x,2*z]==[42,28,14]


x=2
u=x*x
grad_u=1+1
grad_x=grad_u*x+grad_u*x
assert u+u==8 and grad_x==8


class Value:
    def __init__(self,data,parents=()):
        self.data=float(data); self.grad=0.0; self.parents=list(parents)
    def __add__(self,other):
        return Value(self.data+other.data,[(self,1.0),(other,1.0)])
    def __mul__(self,other):
        return Value(self.data*other.data,[(self,other.data),(other,self.data)])
    def backward(self):
        order=[]; seen=set()
        def visit(node):
            if node in seen: return
            seen.add(node)
            for parent,_ in node.parents: visit(parent)
            order.append(node)
        visit(self)
        for node in order: node.grad=0.0
        self.grad=1.0
        for node in reversed(order):
            for parent,local in node.parents: parent.grad+=node.grad*local
x=Value(2); u=x*x; L=u+u
L.backward()
assert L.data==8 and x.grad==8
L.backward()
assert x.grad==8

print('Chapter 09: 5 examples PASS')
