パーセプトロン

####################################
# パーセプトロン学習
# (Pocket Algorith with Ratcet)
#      coded by Y.Suganuma
####################################

###########################
# Perceptronクラスの定義
#      coded by Y.Suganuma
###########################

class Perceptron

	#########################
	# コンストラクタ
	#      max : 最大学習回数
	#      n : 訓練例の数
	#      p : 入力セルの数
	#########################
	def initialize(max_i, n_i, p_i)
			# 設定
		@_max = max_i
		@_n   = n_i
		@_p   = p_i
			# 領域の確保
		@_E   = Array.new(@_n)   # 訓練例
		for i1 in 0 ... @_n
			@_E[i1] = Array.new(@_p+1)
		end
		@_W_p = Array.new(@_p+1)   # 重み(ポケット)
		@_W   = Array.new(@_p+1)   # 重み
		@_C   = Array.new(@_n)   # 各訓練例に対する正しい出力
	end

	#########################################
	# 訓練例の分類
	#      return : 正しく分類した訓練例の数
	#########################################
	def Bunrui()

		num = 0
		for i1 in 0 ... @_n
			s = 0
			for i2 in 0 ... @_p+1
				s += @_W[i2] * @_E[i1][i2]
			end
			if (s > 0 and @_C[i1] > 0) or (s < 0 and @_C[i1] < 0)
				num += 1
			end
		end

		return num
	end

	##########################
	# 学習データの読み込み
	#      name : ファイル名
	##########################
	def Input(name)
	
		f = open(name, "r")
		f.gets()
		for i1 in 0 ... @_n
			@_E[i1][0] = 1
			s = f.gets().split(" ")
			for i2 in 1 ... @_p+1
				@_E[i1][i2] = Integer(s[i2-1])
			end
			@_C[i1] = Integer(s[@_p])
		end
	
		f.close()
	end

	#################################
	# 学習と結果の出力
	#      pr : =0 : 画面に出力
	#           =1 : ファイルに出力
	#      name : 出力ファイル名
	#################################
	def Learn(pr, name="")
	
		num   = Array.new(1)
		n_tri = Pocket(num)
	
		if pr == 0
			out = $stdout
		else
			out = open(name, "w")
		end

		out.print("重み\n")
		for i1 in 0 ... @_p+1
			out.print(" " + String(@_W_p[i1]))
		end
		out.print("\n")
	
		out.print("分類結果\n")
		for i1 in 0 ... @_n
			s  = 0
			for i2 in 0 ... @_p+1
				s += @_E[i1][i2] * @_W_p[i2]
			end
			if s > 0
				s = 1
			else
				if s < 0
					s = -1
				else
					s = 0
				end
			end
			for i2 in 1 ... @_p+1
				out.print(" " + String(@_E[i1][i2]))
			end
			out.print(" Cor " + String(@_C[i1]) + " Res " + String(s) + "\n")
		end
	
		if @_n == num[0]
			print("  !!すべてを分類(試行回数:" + String(n_tri) + ")\n")
		else
			print("  !!" + String(num[0]) + " 個を分類\n")
		end
	end
	
	############################################
	# Pocket Algorith with Ratcet
	#      num_p : 正しく分類した訓練例の数
	#      return : =0 : 最大学習回数
	#               >0  : すべてを分類(回数)
	############################################
	def Pocket(num_p)
			# 初期設定
		count    = 0
		run      = 0
		run_p    = 0
		sw       = -1
		num_p[0] = 0
		for i1 in 0 ... @_p+1
			@_W[i1] = 0
		end
			# 実行
		while sw < 0
	
			count += 1
			if count > @_max
				sw = 0
	
			else
					# 訓練例の選択
				k = Integer(rand(0) * @_n)
				if k >= @_n
					k = @_n - 1
				end
					# 出力の計算
				s = 0
				for i1 in 0 ... @_p+1
					s += @_W[i1] * @_E[k][i1]
				end
					# 正しい分類
				if (s > 0 and @_C[k] > 0) or (s < 0 and @_C[k] < 0)
					run += 1
					if run > run_p 
						num = Bunrui()
						if num > num_p[0]
							num_p[0] = num
							run_p    = run
							for i1 in 0 ... @_p+1
								@_W_p[i1] = @_W[i1]
							end
							if num == @_n
								sw = count
							end
						end
					end
					# 誤った分類
				else
					run = 0
					for i1 in 0 ... @_p+1
						@_W[i1] += @_C[k] * @_E[k][i1]
					end
				end
			end
		end
	
		return sw
	end
end

if ARGV[0] != nil
				# 基本データの入力
	s    = gets().split(" ")
	max  = Integer(s[1])
	p    = Integer(s[3])
	n    = Integer(s[5])
	s    = gets().split(" ")
	name = s[1]
				# ネットワークの定義
	srand()
	net = Perceptron.new(max, n, p)
	net.Input(name)
				# 学習と結果の出力
	if ARGV[0] == nil
		net.Learn(0)
	else
		net.Learn(1, ARGV[0])
	end

else
	print("***error   入力ファイル名を指定して下さい\n")
end

=begin
---------------------入力ファイル------------
最大試行回数 100 入力セルの数 2 訓練例の数 4
入力データファイル or.dat

---------------------or.dat--------------
OR演算の訓練例.最後のデータが目標出力値
-1 -1 -1
-1  1  1
 1 -1  1
 1  1  1
=end