# Perceptron Algorithm on the Sonar Dataset
from random import seed
from random import randrange
from csv import reader
 
# Load a CSV file
def load_csv(filename):
	dataset = list()
	with open(filename, 'r') as file:
		csv_reader = reader(file)
		for row in csv_reader:
			if not row:
				continue
			dataset.append(row)

	return dataset
 
# Convert string column to float
def str_column_to_float(dataset, column):
	for row in dataset:
		row[column] = float(row[column].strip())
 
# Convert string column to integer
def str_column_to_int(dataset, column):
	class_values = [row[column] for row in dataset]
	unique = set(class_values)
	lookup = dict()
	for i, value in enumerate(unique):
		lookup[value] = i
	for row in dataset:
		row[column] = lookup[row[column]]
	return lookup
 
# Split a dataset into k folds
def cross_validation_split(dataset, n_folds):
	dataset_split = list()
	dataset_copy = list(dataset)
	fold_size = int(len(dataset) / n_folds)
	for i in range(n_folds):
		fold = list()
		while len(fold) < fold_size:
			index = randrange(len(dataset_copy))
			fold.append(dataset_copy.pop(index))
		dataset_split.append(fold)
	return dataset_split
 
# Calculate accuracy percentage
def accuracy_metric(actual, predicted):
	correct = 0
	for i in range(len(actual)):
		if actual[i] == predicted[i]:
			correct += 1
	return correct / float(len(actual)) * 100.0
 
# Evaluate an algorithm using a cross validation split
def evaluate_algorithm(dataset, algorithm, n_folds, *args):
	folds = cross_validation_split(dataset, n_folds)
	scores = list()
	for fold in folds:
		train_set = list(folds)
		train_set.remove(fold)
		train_set = sum(train_set, [])
		test_set = list()
		for row in fold:
			row_copy = list(row)
			test_set.append(row_copy)
			row_copy[-1] = None
		predicted = algorithm(train_set, test_set, *args)
		actual = [row[-1] for row in fold]
		accuracy = accuracy_metric(actual, predicted)
		scores.append(accuracy)
	return scores
 
# Make a prediction with weights
def predict(row, weights):
	activation = weights[0]
	for i in range(len(row)-1):
		activation += weights[i + 1] * row[i]
	return 1.0 if activation >= 0.0 else 0.0
 
# Estimate Perceptron weights using stochastic gradient descent
def train_weights(train, l_rate, n_epoch):
	weights = [0.0 for i in range(len(train[0]))]
	for epoch in range(n_epoch):
		for row in train:
			prediction = predict(row, weights)
			error = row[-1] - prediction
			weights[0] = weights[0] + l_rate * error
			for i in range(len(row)-1):
				weights[i + 1] = weights[i + 1] + l_rate * error * row[i]
	return weights
 
# Perceptron Algorithm With Stochastic Gradient Descent
def perceptron(train, test, l_rate, n_epoch):
	predictions = list()
	weights = train_weights(train, l_rate, n_epoch)
	for row in test:
		prediction = predict(row, weights)
		predictions.append(prediction)
	return(predictions)
 
# Test the Perceptron algorithm on the sonar dataset
seed(1)
# load and prepare data
filename = 'C:\\Users\\frup68962\\GFI\\Projet_Perso\\03 - BDD\\A_VERIF_PRONOS.csv'
dataset = load_csv(filename)
for i in range(len(dataset[0])-1):
	str_column_to_float(dataset, i)
# convert string class to integers
str_column_to_int(dataset, len(dataset[0])-1)
# evaluate algorithm
n_folds = 3
l_rate = 0.01
n_epoch = 500
print(dataset[1])
#scores = evaluate_algorithm(dataset, perceptron, n_folds, l_rate, n_epoch)
#print('Scores: %s' % scores)
#print('Mean Accuracy: %.3f%%' % (sum(scores)/float(len(scores)))) 










#!/usr/bin/python
#coding: UTF-8
 
import math
 
import numpy as np
 
# our sigmoid function, tanh is a little nicer than the standard 1/(1+e^-x)
def sigmoid(x):
    return np.tanh(x)
 
# derivative of our sigmoid function
def dsigmoid(x):
    return 1.0 - x**2
     
     
class MLP:
    def __init__(self, *args):
        self.args = args
        n = len(args)
         
        self.layers = [np.ones(args[i] + (i==0)) for i in range(0, n)]
         
        self.weights = list()
        for i in range(n-1):
            R = np.random.random((self.layers[i].size, self.layers[i+1].size))
            self.weights.append((2*R-1)*0.20)
             
        self.m = [0 for i in range(len(self.weights))]
             
         
    def update(self, inputs):
        self.layers[0][:-1] = inputs
         
        for i in range(1, len(self.layers)):
            self.layers[i] = sigmoid(np.dot(self.layers[i-1], self.weights[i-1]))
 
             
        return self.layers[-1]
         
         
    def backPropagate(self, inputs, outputs, a=0.1, m=0.1):
         
        error = outputs - self.update(inputs)
        de = error*dsigmoid(self.layers[-1])
        deltas = list()
        deltas.append(de)
         
         
        for i in range(len(self.layers)-2, 0, -1):
 
            deh = np.dot(deltas[-1], self.weights[i].T) * dsigmoid(self.layers[i])
            deltas.append(deh)
             
        deltas.reverse()
         
        for i, j in enumerate(self.weights):
             
            layer = np.atleast_2d(self.layers[i])
            delta = np.atleast_2d(deltas[i])
             
            dw = np.dot(layer.T,delta)
            self.weights[i] += a*dw + m*self.m[i]
            self.m[i] = dw
             
 
 
 
pat = (((0, 0), 0),
    ((0, 1), 1),
    ((1, 0), 1),
    ((1, 1), 0))
 
 
n = MLP(2, 3, 1)
 
for i in range(1000):
    for p in pat:
        n.backPropagate(p[0], p[1])
         
for p in pat:
    print n.update(p[0])
