require 'matrix'
def generate_random(min = 0.0, max = 1.0)
rand * (max - min) + min
end
def generate_random_array(size, min = 0.0, max = 1.0)
arr = Array.new
size.times do
arr << generate_random(min, max)
end
arr
end
def hamming_distance(x, y)
d = 0
x.each_with_index do |a, i|
d += (a - y[i])**2
end
Math.sqrt d
end
class Perceptron
attr_reader :output_pattern
def initialize(number_of_input, number_of_output, a = 1)
@number_of_input = number_of_input
@number_of_output = number_of_output
@a = a
@weight = Array.new
number_of_output.times do
@weight << Vector[*generate_random_array(number_of_input+1, -1.0, 1.0)]
end
end
def recall(input_pattern)
x = Vector[1, *input_pattern]
@output_pattern = Array.new
@number_of_output.times do |i|
@output_pattern << af(x.inner_product(@weight[i]))
end
@output_pattern
end
def learn(input_pattern, target_pattern)
recall input_pattern
errors = Array.new
x = Vector[1, *input_pattern]
@output_pattern.each_with_index do |out, i|
errors << target_pattern[i] - out
end
for i in 0..@weight.size-1
delta_weight = x * (@a * errors[i])
@weight[i] = @weight[i] + delta_weight
end
hamming_distance target_pattern, @output_pattern
end
private
def af(x)
@t = 0
if x == @t
return 0.0
elsif x > @t
return 1.0
else
return -1.0
end
end
end
net = Perceptron.new(2, 1)
x = [ [-1, -1], [-1, 1], [1, -1], [1, 1] ]
y = [ [-1], [1], [1], [1] ]
print "Perceptron(bipolar) OR-gate simulation\n\n"
puts "Before training"
x.each do |inp|
puts "[#{inp.join(", ")}] : #{net.recall(inp)}"
end
print "\n\n"
print "Training.....\n"
10.times do |p|
puts "Path : #{p}"
total_error = 0
x.each_with_index do |inp, i|
error = net.learn(inp, y[i])
total_error += error
puts " input [#{inp.join(", ")}], output #{net.output_pattern}"
puts " error : #{error}"
end
print "\n"
break if total_error == 0
end
print "\n\n"
puts "After training"
x.each do |inp|
puts "[#{inp.join(", ")}] : #{net.recall(inp)}"
end
puts "\n\nd>_<b"