import numpy as np

def nonlin(x, deriv=False):
    if(deriv==True):
        return x * (1-x)

    return 1 / (1+np.exp(-x))

#input data
X = np.array([
    [0, 0, 1],
    [0, 1, 1],
    [1, 0, 1],
    [1, 1, 1]
])
# output data
y = np.array([
    [0],
    [1],
    [1],
    [0]
])
np.random.seed(1)

# synapses that connect our layers
syn0 = 2 * np.random.random((3, 4)) - 1
syn1 = 2 * np.random.random((4, 4)) - 1
syn2 = 2 * np.random.random((4, 1)) - 1

# training step
for j in xrange(60000):
    # First layer is input
    # syn0 takes us to our hidden layer
    # syn1 takes us to our output layer
    l0 = X
    l1 = nonlin(np.dot(l0, syn0))
    l2 = nonlin(np.dot(l1, syn1))
    l3 = nonlin(np.dot(l2, syn2))

    # Our error is how far off we are from answer (y)
    l3_error = y - l3

    if (j % 10000) == 0:
        print "Error:" + str(np.mean(np.abs(l3_error)))

    # Use back propogation to find error of each step
    l3_delta = l3_error * nonlin(l3, deriv=True)
    l2_error = l3_delta.dot(syn2.T)
    l2_delta = l2_error * nonlin(l2, deriv=True)
    l1_error = l2_delta.dot(syn1.T)
    l1_delta = l1_error * nonlin(l1, deriv=True)

    # update weights to improve after each iteration
    syn2 += l2.T.dot(l3_delta)
    syn1 += l1.T.dot(l2_delta)
    syn0 += l0.T.dot(l1_delta)

print "Output after training"
print l3
print "Final Accuracy"
print np.mean((1 - np.abs((y - l3))) * 100)
