ファジイ推論

############################
# ファジイ推論
#      coded by Y.Suganuma
############################

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

class Fuzzy
	
	#####################################
	# コンストラクタ
	#      name : 入力データファイル名
	#####################################
	
	def initialize(name)

		in_f = open(name, "r")
			# 基本データの入力
		s        = in_f.gets().split(" ")
		@_method = Integer(s[1])   # 推論方法
	                               #    =0 : and,or
	                               #    =1 : *,or
	                               #    =2 : *,+
		@_n_rule = Integer(s[3])   # 規則の数
		@_n_val  = Integer(s[5])   # 変数の数
		@_bun    = Integer(s[7])   # 積分の分割数
			# 領域の確保
		@_omega = Array.new(@_n_rule)   # ωの値
		@_rule  = Array.new(@_n_rule)
		               # [i][j] =0 : i番目の規則はj番目の変数を使用しない
		               #        =1 : i番目の規則はj番目の変数を使用する
		@_right = Array.new(@_n_rule)
		               # [i][0] : 中心
		               # [i][1] : 幅
		@_left  = Array.new(@_n_rule)
		               # [i][j][0] : 中心
		               # [i][j][1] : 幅
		for i1 in 0 ... @_n_rule
			@_rule[i1]  = Array.new(@_n_val)
			@_right[i1] = Array.new(2)
			@_left[i1]  = Array.new(@_n_rule)
			for i2 in 0 ... @_n_rule
				@_left[i1][i2]  = Array.new(2)
			end
		end
			# 規則データの入力
		for i1 in 0 ... @_n_rule
	
			in_f.gets()
							# 左辺
			for i2 in 0 ... @_n_val
				s              = in_f.gets().split(" ")
				@_rule[i1][i2] = Integer(s[1])
				if @_rule[i1][i2] > 0
					@_left[i1][i2][0] = Float(s[3])
					@_left[i1][i2][1] = Float(s[4])
				end
			end
							# 右辺
			s              = in_f.gets().split(" ")
			@_right[i1][0] = Float(s[1])
			@_right[i1][1] = Float(s[2])
		end
	
		in_f.close()
	end
	
	###########################################
	# 交点の計算
	#      x : x
	#      c : 中心
	#      h : 幅
	#      r : <0 : 左辺のメンバーシップ関数
	#          >=0 : 右辺(ω) 
	#      return : 交点
	###########################################
	
	def Cross(x, c, h, r)
	
		if x < c
			x1 = c - h
			x2 = c
			y1 = 0.0
			if r < 0.0 or (r >= 0.0 and @_method == 0)
				y2 = 1.0
			else
				y2 = r
			end
		else
			x1 = c
			x2 = c + h
			if r < 0.0 or (r >= 0.0 and @_method == 0)
				y1 = 1.0
			else
				y1 = r
			end
			y2 = 0.0
		end
	
		y = y1 + (y2 - y1) * (x - x1) / (x2 - x1)
	
		if y < 0.0
			y = 0.0
		else
			if r >= 0.0 and @_method == 0 and y > r
				y = r
			end
		end
	
		return y
	end
	
	##############################################
	# 右辺の計算
	#      x : 値
	#      om[i] : <0 : i番目の規則を使用しない
	#              >=0 : ωの値
	#      return : xにおける右辺の値
	##############################################
	
	def Height(x, om)

		y  = 0.0
		sw = 0
	
		for i1 in 0 ... @_n_rule
	
			if om[i1] >= 0.0
	
				y1 = Cross(x, @_right[i1][0], @_right[i1][1], om[i1])
	
				if sw == 0
					y  = y1
					sw = 1
				else
					if @_method < 2
						if y1 > y
							y = y1
						end
					else
						y += y1
					end
				end
			end
		end
	
		return y
	end
	
	##########################
	# 推論の実行
	#      x[i] : 各変数の値
	#      return : 推論値
	##########################
	
	def Inf(x)
	
			# ωの計算
		for i1 in 0 ... @_n_rule
	
			@_omega[i1] = -1.0
	
			for i2 in 0 ... @_n_val
	
				if @_rule[i1][i2] > 0
	
					if x[i2] > @_left[i1][i2][0]-@_left[i1][i2][1] and x[i2] < @_left[i1][i2][0]+@_left[i1][i2][1]
						x1 = Cross(x[i2], @_left[i1][i2][0], @_left[i1][i2][1], -1.0)
					else
						x1 = 0.0
					end
	
					if @_omega[i1] < 0.0
						@_omega[i1] = x1
					else
						if @_method == 0
							if x1 < @_omega[i1]
								@_omega[i1] = x1
							end
						else
							@_omega[i1] *= x1
						end
					end
				end
			end
		end
			# 右辺の計算
		y = Result(@_omega)
	
		return y
	end
	
	##############################################
	# 右辺による推論
	#      om[i] : <0 : i番目の規則を使用しない
	#              >=0 : ωの値
	#      return : 推論値
	##############################################
	
	def Result(om)

		max = 0.0
		min = 0.0
		y   = 0.0
		sw  = 0
			# 積分範囲と積分幅の計算
		for i1 in 0 ... @_n_rule
			if om[i1] >= 0.0
				x1 = @_right[i1][0] - @_right[i1][1]
				x2 = @_right[i1][0] + @_right[i1][1]
				if sw == 0
					min = x1
					max = x2
					sw  = 1
				else
					if x1 < min
						min = x1
					end
					if x2 > max
						max = x2
					end
				end
			end
		end
	
		h = (max - min) / @_bun
	
		if h < 1.0e-15
			print("***error  invalid data (h = 0) ***\n")
		end
			# 積分(重心の計算,台形則)
		z1 = Height(min, om)
		z2 = Height(max, om)
		y1 = 0.5 * (min * z1 + max * z2)
		y2 = 0.5 * (z1 + z2)
		x1 = min
	
		for i1 in 0 ... @_bun-1
			x1 += h
			z1  = Height(x1, om)
			y1 += x1 * z1
			y2 += z1
		end
	
		y1 *= h
		y2 *= h
	
		if y2.abs() > 1.0e-10
			y = y1 / y2
		else
			print("***error  invalid data (y2 = 0) ***\n")
		end
	
		return y
	end
end

if ARGV.length == 3
	file1 = ARGV[0]
	file2 = ARGV[1]
	file3 = ARGV[2]
				# オブジェクトの生成
	fz = Fuzzy.new(file1)
				# 推論データの読み込み
	in_f  = open(file2, "r")
	s     = in_f.gets().split(" ")
	n_val = Integer(s[1])
	n_d   = Integer(s[3])
	x     = Array.new(n_val)
	xx    = Array.new(n_val)
	for i1 in 0 ... n_val
		xx[i1] = Array.new(n_d)
		s      = in_f.gets().split(" ")
		for i2 in 0 ... n_d
			xx[i1][i2] = Float(s[i2+1])
		end
	end
	in_f.close()
				# 推論とその結果の出力
	out = open(file3, "w")
	for i1 in 0 ... n_d
		for i2 in 0 ... n_val
			x[i2] = xx[i2][i1]
			out.print(String(x[i2]) + " ")
		end
		y = fz.Inf(x)   # 推論
		out.print(String(y) + "\n")
	end
	out.close()

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

=begin
------------------------規則ファイル--------------
推論方法 0 規則の数 3 変数の数 1 積分の分割数 100
規則1
 変数1 1 中心と幅 1.0 1.0
 右辺(中心と幅) 1.0 15.0
規則2
 変数1 1 中心と幅 2.0 1.0
 右辺(中心と幅) 11.0 15.0
規則3
 変数1 1 中心と幅 3.0 1.0
 右辺(中心と幅) 21.0 15.0

------------------------推論ファイル--------------
変数の数 1 データ数 21
変数1 1.0 1.1 1.2 1.3 1.4 1.5 1.6 1.7 1.8 1.9 2.0 2.1 2.2 2.3 2.4 2.5 2.6 2.7 2.8 2.9 3.0
=end