In [ ]:
from math import sqrt, pi, sin
import random
import numpy
import matplotlib.pyplot as plt

neurons = 10
acceptable_error = .0001 #stops updating if the average squared error is less than this
max_iter = 100000 #stops updating if this number of iterations is reached
updates = 5 #number of times to calculate the average error (and write it to the console)

update_iter = max_iter / updates - 1

#the one-neuron function to predict sin(x) is: y = a * max(0, a1 * x + a2) + b
a = []
a1 = []
a2 = []
da = []
da1 = []
da2 = []
linear_combo = [] #this is a1 * x + a2
b = 0.0
db = 0.0

for i in range(neurons):
	a.append(random.uniform(-1, 1))
	a1.append(random.uniform(-1,1))
	a2.append(0.0)
	linear_combo.append(0.0)
	da.append(0.0)
	da1.append(0.0)
	da2.append(0.0)

avg_error = 0
current_error = 10

x = 1

#perhaps have the code increase the number of neurons if acceptable error isn't met
#in a future version of the code
while x < max_iter and current_error > acceptable_error:
	
	#get new input between -pi and pi
	input = random.uniform(-pi, pi)
	act = sin(input)
	predict = 0

	#update weights and predict sin(input) from the input
	for i in range(neurons):
		a[i] += da[i]
		a1[i] += da1[i]
		a2[i] += da2[i]
		linear_combo[i] = a1[i] * input + a2[i]
		if (linear_combo[i] > 0):
			predict += a[i] * linear_combo[i]
	b += db
	predict += b

	#calculate error, write avg error to console if needed	
	error = (act - predict) ** 2
	avg_error += error
	if (x % update_iter == 0):
		avg_error /= update_iter
                print('Iter: {}, Avg squared error: {:.5}'.format(x, avg_error))
		current_error = avg_error
		avg_error = 0
	
	#calculate weight changes
	step = .001
	sign = numpy.sign(act - predict)
	for i in range(neurons):
		if (linear_combo[i] > 0):
			da[i] = step * linear_combo[i] * sqrt(error) * sign	
			da1[i] = step * a[i] * input * sqrt(error) * sign
			da2[i] = step * a[i] * sqrt(error) * sign
	db = step * sqrt(error) * sign
	
	x += 1

#plot sin(x) against predictions for 100 values of x between -pi and pi
test = []
out = []
sine = []

for y in range (100):
	
	input = -pi + y * 2 * pi / 99
	test.append(input)
	sine.append(sin(input))

	output = 0
	for i in range(neurons):
		output += a[i] * max(0, a1[i] * input + a2[i])
	output += b
	out.append(output)

plt.plot(test, out, 'gs', test, sine)
plt.axis([-pi, pi, -1.5, 1.5])
plt.show()