using Random, LinearAlgebra
Random.seed!(13)

# Activation function: Step function
Step(X::Float64) = (X > 0 ? 1.0 : -1.0)

Step(X::Array{Float64,1}) = [Step(x) for x in X]

# Matrix rows sum
RowSum(A) = sum(A, dims=1)[1, :]

# Feedforward phase
F(X, α) = Step(X*α)

# Training function
function TrainPerceptron(Xin, Y, γ)
	# First step: add 1s to each row of X
	n, p = size(Xin)
	X = ones(n, p+1)
	X[:, 2:p+1] = Xin
	Random.seed!(13)
	# Initial random weigths
	α = rand(p+1)
	# Training loop
	for it in 1:100
		Yb = F(X, α)
		E = Y - Yb
		δ = E .* X
		α = α + γ * RowSum(δ)
		
		# Logging loss function values
		println(it, "-->  Loss(w): ", norm(E), " - Weights: ", α)
		# Stopping if error goes to zero
		if norm(E) < 0.0001
			break
		end
	end
	Yb = F(X, α)
	println(Yb)
end


Xand = [0 0; 0 1; 1 0; 1 1]
Yand = [-1, -1, -1, 1]
println("START LEARNING AND")
TrainPerceptron(Xand, Yand, 0.01)

#Xor = [0 0; 0 1; 1 0; 1 1]
#Yor = [-1, 1, 1, 1]
#println("START LEARNING OR")
#TrainPerceptron(Xor, Yor, 0.01)


#Xxor = [0 0; 0 1; 1 0; 1 1]
#Yxor = [-1, 1, 1, -1]
#println("START LEARNING OR")
#TrainPerceptron(Xxor, Yxor, 0.01)

#L = [1 1 1; 1 0 1; 1 1 0; 1 0 0; 0 1 1; 0 0 1; 0 1 0; 0 0 0]
#Y = [1, 1, 1, 1, 0, 1, 0, 0]
#TrainPerceptron(L, Y, 0.01)
println("DONE")