import numpy as np
import matplotlib.pyplot as plt
import time

def make_data():
	data0 = np.tile([1,2],(500,1))+0.5*np.random.randn(500,2)	# creates 500 data points centered around (1,2)
	data1 = np.tile([3,1],(500,1))+0.5*np.random.randn(500,2)	# creates 500 data points centered around (3,1)
	data = np.concatenate((data0,data1))						# creates a 1000 row 2 column matrix by joining the above two
	return data

def make_labels():
	labels = np.concatenate((np.zeros((500,1)),np.ones((500,1))))	# first 500 rows are labelled 0 and the next 500 1
	return labels

def plot_data(data, labels):
	plt.scatter(data[:,0], data[:,1], s=10, c=labels, edgecolors='none')
	plt.show()

def show_neuron(data, labels, w, b):
	plt.clf()
	plt.scatter(data[:,0], data[:,1], s=10, c=labels, edgecolors='none')

	xmin = np.min(data[:,0])
	xmax = np.max(data[:,0])

	x = np.arange(xmin,xmax+0.01,0.01)
	y = -b/w[1] - (w[0]/w[1])*x		# equation of line w[1]y + w[0]x = b

	plt.plot(x,y,'g')
	plt.xlim((-1,5))
	plt.ylim((-1.5,4.5))
	plt.draw()
	time.sleep(0.01)

def learn_neuron(data, labels):
	w = 0.01*np.random.randn(2,1)	# initialize parameter w
	b = 0	# initialize parameter b
	epsilon = 0.0001	# the learning rate for the neuron

	x = data
	t = labels

	for i in xrange(1000):
		show_neuron(data,labels,w,b)	# draw current state
		plt.pause(0.1)		# gives time for the plot to draw
		z = np.dot(x, w)+b
		y = 1/(1+np.exp(-z))

		prediction = y > 0.5	# y>0.5 get labelled as True; others get labelled as False
		acc = np.mean(prediction.astype(int)==t)

		L = 0.5*np.sum(np.square(y-t))
		print 'w[0] = ', w[0], ' w[1] = ', w[1], ' b = ', b, ' L = ', np.sum(L), ' acc = ', acc

		# Compute dw, db (equations explained in pdf)
		dLbydy = y-t
		dLbydz = dLbydy * y * (1-y)
		dLbydw = np.dot(x.T, dLbydz)  
		dLbydb = np.sum(dLbydz)

		dw = -epsilon * dLbydw
		db = -epsilon * dLbydb

		w = w + dw
		b = b + db
	plt.ioff()	# no need for interactive mode now
	plt.show()	# keeps the plot open


plt.ion()		# interactive mode makes it possible to continue doing calculations while plotting each iteration in the learn_neuron() function
data = make_data()
labels = make_labels()
#plot_data(data,labels)
learn_neuron(data, labels)
