遺伝的アルゴリズムによるTSPの解

####################################
# 遺伝的アルゴリズムによるTSPの解
#      coded by Y.Suganuma
####################################

######################
# クラスSpeciesの定義
######################

class Species
	
	#########################
	# コンストラクタ
	#      name : ファイル名
	#########################

	def initialize(name)
	
				# データの入力
		inn = open(name, "r")
	
		s = inn.gets().split(" ")
		@_allele_u = Integer(s[1])   # 対立遺伝子上限
		@_allele_l = Integer(s[3])   # 対立遺伝子下限

		s = inn.gets().split(" ")
		@_max_len = Integer(s[1])   # 最大遺伝子長
		@_min_len = Integer(s[3])   # 最小遺伝子長(負の時は,最大遺伝子長で固定)

		s = inn.gets().split(" ")
		@_dup_a = Integer(s[1])  # 遺伝子の重複
		                         #   =0 重複を許さない
		                         #   =1 重複を許す
		@_dup_s = Integer(s[3])   # 個体の重複(同じ染色体の個体)
		                          #   =0 重複を許さない
		                          #   =1 重複を許す

		s = inn.gets().split(" ")
		@_size   = Integer(s[1])   # 個体総数
		@_max_ch = Integer(s[3])   # 子供の数の最大値
				# データのチェック
		if @_size <= 0
			print("***error  個体総数≦0 (Constructor)\n")
		end
	
		if @_max_ch < 0
			print("***error  子供の数<0 (Constructor)\n")
		end
	
		if @_max_len <= 0 or @_min_len == 0
			print("***error  遺伝子長≦0 (Constructor)\n")
		end
	
		if @_max_len < @_min_len
			print("***error  最大遺伝子長<最小遺伝子長 (Constructor)\n")
		end
	
		if @_allele_u <= @_allele_l
			print("***error  対立遺伝子上限≦対立遺伝子下限 (Constructor)\n")
		end
	
		kind = @_allele_u - @_allele_l + 1
		if @_dup_a == 0 and @_max_len > kind
			print("***error  遺伝子の重複を防ぐことはできない (Constructor)\n")
		end
				# 領域の確保
		num   = @_size + @_max_ch
		@_ind = Array.new(num)   # 集団(個体の集まり)
		for i1 in 0 ... num
			@_ind[i1]  = Array.new(@_max_len)
		end
		@_edge = Array.new(@_max_len)   # エッジ組み替え交叉用ワークエリア
		for i1 in 0 ... @_max_len
			@_edge[i1] = Array.new(5)
		end
		@_pi = Array.new(@_max_len)   # 適応度
		for i1 in 0 ... @_max_len
			@_pi[i1]  = Array.new(5)
		end
		@_pi   = Array.new(num)   # 適応度
		@_ro   = Array.new(num)   # ルーレット板
		@_len  = Array.new(num)   # 各個体の遺伝子長
		@_kou1 = Array.new(@_max_len)   # 交叉・突然変異用作業場所1
		@_kou2 = Array.new(@_max_len)   # 交叉・突然変異用作業場所2
		@_s_w  = Array.new(num)   # 淘汰用指標(選択された回数)
		@_pi_w = Array.new(num)   # 適応度計算指標
		                          #   =0 未使用
		                          #   =1 適応度計算前(突然変異はこの個体だけに適用)
		                          #   =2 適応度計算済み(交叉時に親とみなす)
		@_max   = -999999999   # 最大適応度
		@_mean  = 0.0   # 平均適応度
		@_max_n = -1   # 最大適応度の個体番号
	end

	##################################################
	# 場所を探す
	#      n >=0 : n番目の親を捜す
	#        -1 : 空いている場所を探す
	#      return : 親の場所,または,空いている場所
	#               (存在しないときは負の値)
	##################################################

	def Position(n)
	
		k  = -1
		sw = 0
				# 空いている場所を探す
		if n < 0
			for i1 in 0 ... @_size+@_max_ch
				if @_pi_w[i1] == 0
					k = i1
					break
				end
			end
			if k < 0
				print("***error  空いている場所がない --Position--\n")
			end
				# n番目の親(pi_w[i]=2)を捜す
		else
			for i1 in 0 ... @_size+@_max_ch
				if @_pi_w[i1] == 2
					k += 1
					if k == n
						sw = 1
						k  = i1
						break
					end
				end
			end
		end
	
		return k
	end
	
	###################################################################
	# 個体の選択
	#      method : 選択方法
	#                 =-1 ランダム(default)
	#                 =0 適応度をそのまま使用
	#                 =1 最小値からの差(ただし,α以下の場合はα)
	#                 =2 評価値に順位をつけ,減少率βで線形化
	#      bias : α,または,method=2の場合は初期値(default=0)
	#      step : β(default=1)
	#      return : 個体番号
	###################################################################

	def Select(method, bias, step)
	
		sum = 0.0
					# ルーレット板の用意
							# ランダム
		if method == -1
			n = 0
			for i1 in 0 ... @_size+@_max_ch
				if @_pi_w[i1] > 1
					n += 1
				end
			end
			sum = 1.0 / n
			for i1 in 0 ... @_size+@_max_ch
				if @_pi_w[i1] > 1
					@_ro[i1] = sum
				end
			end
							# 評価値をそのまま利用
		elsif method == 0
			n = 0
			for i1 in 0 ... @_size+@_max_ch
				if @_pi_w[i1] > 1
					sum += @_pi[i1]
					n   += 1
				end
			end
			if sum.abs() > 1.0e-10
				sum = 1.0 / sum.abs()
				for i1 in 0 ... @_size+@_max_ch
					if @_pi_w[i1] > 1
						@_ro[i1] = @_pi[i1] * sum
					end
				end
			else
				sum = 1.0 / n
				for i1 in 0 ... @_size+@_max_ch
					if @_pi_w[i1] > 1
						@_ro[i1] = sum
					end
				end
			end
							# 最小値からの差
		elsif method == 1
			min = -1
			n   = 0
			for i1 in 0 ... @_size+@_max_ch
				if @_pi_w[i1] > 1
					n += 1
					if min < 0 or @_pi[i1] < @_pi[min]
						min = i1
					end
				end
			end
			for i1 in 0 ... @_size+@_max_ch
				if @_pi_w[i1] > 1
					@_ro[i1] = @_pi[i1] - @_pi[min]
					if @_ro[i1] < bias
						@_ro[i1] = bias
					end
					sum += @_ro[i1]
				end
			end
			if sum > 1.0e-10
				sum = 1.0 / sum
				for i1 in 0 ... @_size+@_max_ch
					if @_pi_w[i1] > 1
						@_ro[i1] *= sum
					end
				end
			else
				sum = 1.0 / n
				for i1 in 0 ... @_size+@_max_ch
					if @_pi_w[i1] > 1
						@_ro[i1] = sum
					end
				end
			end
							# 線形化
		elsif method == 2
			n = 0
			for i1 in 0 ... @_size+@_max_ch
				if @_pi_w[i1] > 1
					@_ro[i1] = -1.0
					n += 1
				else
					@_ro[i1] = 1.0
				end
			end
			sw  = 0
			sum = bias
			while sw == 0
				min = -1
				for i1 in 0 ... @_size+@_max_ch
					if @_ro[i1] < 0.0 and (min < 0 or @_pi[i1] < @_pi[min])
						min = i1
					end
				end
				if min < 0
					sw = 1
				else
					@_ro[min]  = sum
					sum       += @_step
				end
			end
			sum = 1.0 / (0.5 * (2.0 * bias + step * (n - 1)) * n)
			for i1 in 0 ... @_size+@_max_ch
				if @_pi_w[i1] > 1
					@_ro[i1] *= sum
				end
			end
		end
	
		sum = 0.0
		for i1 in 0 ... @_size+@_max_ch
			if @_pi_w[i1] > 1
				sum         += @_ro[i1]
				@_ro[i1]  = sum
			end
		end
						# 選択
		x  = rand(0)
		sw = 0
		k  = 0
		for i1 in 0 ... @_size+@_max_ch
			if @_pi_w[i1] > 1
				if x <= @_ro[i1]
					sw = 1
					k  = i1
					break
				end
			end
		end
	
		return k
	end
	
	###################
	# 標準的な初期設定
	###################

	def Init_std()
	
				# 初期設定
		for i1 in 0 ... @_size+@_max_ch
			if i1 < @_size
				@_pi_w[i1] = 1   # 適応度の計算前
			else
				@_pi_w[i1] = 0   # 未使用
			end
		end
				# 遺伝子の決定
		for i1 in 0 ... @_size
	
			sw1    = 0
			length = 0

			while sw1 == 0
						# 遺伝子長の決定
				if @_min_len < 0
					length = @_max_len
				else
					length = Integer(rand(0) * (@_max_len - @_min_len + 1) + @_min_len)
					if length > @_max_len
						length = @_max_len
					end
				end
				@_len[i1] = length
						# 遺伝子の決定
				for i2 in 0 ... length
					sw2 = 0
					while sw2 == 0
						lid = Integer(rand(0) * (@_allele_u - @_allele_l + 1) + @_allele_l)
						if lid > @_allele_u
							lid = @_allele_u
						end
						@_ind[i1][i2] = lid
							# 重複遺伝子のチェック
						sw2 = 1
						if @_dup_a == 0
							for i3 in 0 ... i2
								if lid == @_ind[i1][i3]
									sw2 = 0
									break
								end
							end
						end
					end
				end
						# 重複個体のチェック
				sw1 = 1
				if @_dup_s == 0
					for i2 in 0 ... i1
						if @_len[i1] == @_len[i2]
							sw2 = 0
							for i3 in 0 ... @_len[i1]
								if @_ind[i1][i3] != @_ind[i2][i3]
									sw2 = 1
									break
								end
							end
							if sw2 == 0
								sw1 = 0
								break
							end
						end
					end
				end
			end
		end
	end
	
	####################################################
	# 標準的な出力
	#      sw : 出力レベル
	#             =0 : 最終出力だけ
	#             n>0 : n世代毎に出力(負はファイル)
	#      out_m : 出力方法
	#                =0 : すべての個体を出力
	#                =1 : 最大適応度の個体だけを出力
	#      gen : 現在の世代番号
	#      name : 出力ファイル名
	####################################################

	def Out_std(sw, out_m, gen, name)
	
		k  = 0
		pr = -1

		if sw >= 0
			print("   出力先は(0:出力なし,n:画面にn個づつ,-1:ファイル)? ")
			pr = Integer($stdin.gets())
		end
	
		if pr != 0
						# 出力先の決定と評価値の出力
			if pr > 0
				out = $stdout
				$stdin.gets()
			else
				now = String(Time.now)
				out = open(name, "a")
				out.print("***世代 " + String(gen) + " 適応度 max " + String(@_max) + " (" + String(@_max_n) + ") mean " + String(@_mean) + " 時間 " + now + "\n")
						# 詳細出力
			end
			for i1 in 0 ... @_size+@_max_ch
				if (@_pi_w[i1] > 1) and (out_m == 0 or (out_m == 1 and i1 == @_max_n))
					out.print(String(i1) + " allele")
					for i2 in 0 ... @_len[i1]
						out.print(" " + String(@_ind[i1][i2]))
					end
					out.print(" value " + String(@_pi[i1]) + "\n")
					if pr > 0
						k += 1
						if k == pr
							$stdin.gets()
							k = 0
						end
					end
				end
			end
	
			if pr < 0
				out.close()
			end
		end
	end
	
	###################################################################
	# 交叉(親のコピー)
	#      method : =2 有性(2つの親から2つの子供)(default)
	#               =1 1つの親から1つの子供
	#      pair : method=2 の時は親のペア数(default=max_ch/2)
	#             method=1 の時は親の数(=子供の数)
	#      k_method : 選択方法
	#                 =-1 ランダム(default)
	#                 =0 適応度をそのまま使用
	#                 =1 最小値からの差(ただし,α以下の場合はα)
	#                 =2 評価値に順位をつけ,減少率βで線形化
	#      k_bias : α,または,method=2の場合は初期値(default=0)
	#      k_step : β(default=1)
	###################################################################

	def C_copy(method = 2, pair = 0, k_method = -1, k_bias = 0.0, k_step = 1.0)
	
				# 初期設定とデータチェック
		if method != 1
			method = 2
		end
	
		if pair <= 0
			if method == 2
				pair = Integer(@_max_ch / 2)
			else
				pair = @_max_ch
			end
		else
			if method == 2 and 2*pair > @_max_ch or method == 1 and pair > @_max_ch
				print("***error  子供が多すぎる (C_copy)\n")
			end
		end
				# 実行
		for i1 in 0 ... pair
						# 親の選択
			p1 = Select(k_method, k_bias, k_step)
			p2 = p1
			sw = 0
	
			while sw == 0
				p2 = Select(k_method, k_bias, k_step)
				if p1 != p2
					sw = 1
				end
			end
						# コピー
			for i2 in 0 ... method
				p = p2
				if i2 == 0
					p = p1
				end
				k         = Position(-1)
				@_len[k]  = @_len[p]
				@_pi_w[k] = 1
				for i3 in 0 ... @_len[k]
					@_ind[k][i3] = @_ind[p][i3]
				end
			end
		end
	end
	
	###################################################################
	# 交叉(多点交叉)
	#      kosa : 交叉確率
	#      k_point : 交叉点の数(default=1)
	#                (負の時は,1から-k_point間のランダム)
	#      k_vr : =0 両親とも同じ位置で交叉(default) 
	#             =1 両親が異なる位置で交叉(遺伝子長は可変)
	#      k_method : 選択方法
	#                 =-1 ランダム(default) 
	#                 =0 適応度をそのまま使用
	#                 =1 最小値からの差(ただし,α以下の場合はα)
	#                 =2 評価値に順位をつけ,減少率βで線形化
	#      k_bias : α,または,method=2の場合は初期値(default=0)
	#      k_step : β(default=1)
	###################################################################

	def C_point(kosa, k_point = 1, k_vr = 0, k_method = -1, k_bias = 0.0, k_step = 1.0)
	
		mn = 0
				# 初期設定とデータのチェック
		pair = Integer(@_max_ch / 2)
	
		if @_dup_a == 0
			print("***error  交叉方法が不適当 (C_point)\n")
		end
	
		abs_p = k_point.abs()
		if abs_p == 0 or abs_p > @_max_len-1 or (@_min_len > 0 and abs_p > @_min_len-1)
			print("***error  交叉点の数が不適当 (C_point)\n")
		end
	
		if k_vr > 0 and @_min_len < 0
			print("***error  遺伝子長は可変でなければならない (C_point)\n")
		end
				# 交叉
		num = k_point
	
		for i1 in 0 ... pair
						# 交叉しない場合
			if rand(0) > kosa
				C_copy(2, 1)
						# 交叉する場合
			else
							# 親の選択
				p1 = Select(k_method, k_bias, k_step)
				p2 = p1
				sw = 0
				while sw == 0
					p2 = Select(k_method, k_bias, k_step)
					if p1 != p2
						sw = 1
					end
				end
							# 交叉位置の数の決定
				if k_point < 0
					num = Integer(rand(0) * abs_p + 1)
					if num > abs_p
						num = abs_p
					end
				end
							# 交叉位置の決定(点の後ろで交叉)
				for i2 in 0 ... num
								# 親1の交叉位置
					sw = 0
					while sw == 0
						sw            = 1
						@_kou1[i2] = Integer(rand(0) * (@_len[p1] - 1))
						if @_kou1[i2] > @_len[p1]-2
							@_kou1[i2] = @_len[p1] - 2
						end
						if k_vr == 0 and @_kou1[i2] > @_len[p2]-2
							@_kou1[i2] = @_len[p2] - 2
						end
						for i3 in 0 ... i2
							if @_kou1[i3] == @_kou1[i2]
								sw = 0
								break
							end
						end
					end
								# 親2の交叉位置
					if k_vr > 0
						sw = 0
						while sw == 0
							sw            = 1
							@_kou2[i2] = Integer(rand(0) * (@_len[p2] - 1))
							if @_kou2[i2] > @_len[p2]-2
								@_kou2[i2] = @_len[p2] - 2
							end
							for i3 in 0 ... i2
								if @_kou2[i3] == @_kou2[i2]
									sw = 0
									break
								end
							end
						end
					end
				end
							# 交叉の実行
							#   親1のt11からt12を子1のc1へコピー
							#   親2のt21からt22を子2のc2へコピー
							#     次は,
							#   親1のt11からt12を子2のc2へコピー
							#   親2のt21からt22を子1のc1へコピー
							#     ・・・・・
				c1  = 0
				c2  = 0
				t11 = 0
				t21 = 0
								# 遺伝子長
				k1         = Position(-1)
				@_pi_w[k1] = 1
				@_len[k1]  = @_len[p1]
				k2         = Position(-1)
				@_pi_w[k2] = 1
				@_len[k2]  = @_len[p2]
	
				for i2 in 0 ... num+1
								# 次の交叉位置を求める
					if i2 == num            # 最後
						t12 = @_len[p1]
						t22 = @_len[p2]
					else
									# 親1
						t12 = @_max_len
						for i3 in 0 ... num
							if @_kou1[i3] >= 0 and @_kou1[i3] <= t12
								t12 = @_kou1[i3]
								mn  = i3
							end
						end
						@_kou1[mn] = -1
						t12 += 1
									# 親2
						if k_vr == 0
							t22 = t12
						else
							t22 = @_max_len
							for i3 in 0 ... num
								if @_kou2[i3] >= 0 and @_kou2[i3] <= t22
									t22 = @_kou2[i3]
									mn  = i3
								end
							end
							@_kou2[mn] = -1
							t22 += 1
						end
					end
								# 指定箇所のコピー
					for i3 in t11 ... t12
						if i2%2 == 0
							if c1 < @_max_len
								@_ind[k1][c1] = @_ind[p1][i3]
								c1 += 1
							end
						else
							if c2 < @_max_len
								@_ind[k2][c2] = @_ind[p1][i3]
								c2 += 1
							end
						end
					end
	
					for i3 in t21 ... t22
						if i2%2 == 0
							if c2 < @_max_len
								@_ind[k2][c2] = @_ind[p2][i3]
								c2 += 1
							end
						else
							if c1 < @_max_len
								@_ind[k1][c1] = @_ind[p2][i3]
								c1 += 1
							end
						end
					end
								# 交叉位置の移動
					t11 = t12
					t21 = t22
				end
			end
		end
	end
	
	###################################################################
	# 交叉(一様交叉.[0,1]を等確率で発生させ,1であれば,
	#       親1,0であれば親2の遺伝子を子1が受け継ぐ)
	#      kosa : 交叉確率
	#      k_method : 選択方法
	#                 =-1 ランダム(default)
	#                 =0 適応度をそのまま使用
	#                 =1 最小値からの差(ただし,α以下の場合はα)
	#                 =2 評価値に順位をつけ,減少率βで線形化
	#      k_bias : α,または,method=2の場合は初期値(default=0)
	#      k_step : β(default=1)
	###################################################################

	def C_uniform(kosa, k_method = -1, k_bias = 0.0, k_step = 1.0)
	
				# 初期設定とデータのチェック
		pair = Integer(@_max_ch / 2)
	
		if @_dup_a == 0
			print("***error  交叉方法が不適当 (C_uniform)\n")
		end
	
		if @_min_len > 0
			print("***error  遺伝子長は固定長でなければならない (C_uniform)\n")
		end
				# 交叉
		for i1 in 0 ... pair
						# 交叉しない場合
			if rand(0) > kosa
				C_copy(2, 1)
						# 交叉する場合
			else
							# 親の選択
				p1 = Select(k_method, k_bias, k_step)
				p2 = p1
				sw = 0
				while sw == 0
					p2 = Select(k_method, k_bias, k_step)
					if p1 != p2
						sw = 1
					end
				end
							# 遺伝子長
				k1         = Position(-1)
				@_pi_w[k1] = 1
				@_len[k1]  = @_len[p1]
				k2         = Position(-1)
				@_pi_w[k2] = 1
				@_len[k2]  = @_len[p2]
							# 交叉
				for i2 in 0 ... @_len[p1]
					if rand(0) > 0.5
						@_ind[k1][i2] = @_ind[p1][i2]
						@_ind[k2][i2] = @_ind[p2][i2]
					else
						@_ind[k1][i2] = @_ind[p2][i2]
						@_ind[k2][i2] = @_ind[p1][i2]
					end
				end
			end
		end
	end
	
	###################################################################
	# 交叉(平均化交叉.2つの親の平均値を受け継ぐ)
	#      kosa : 交叉確率
	#      k_method : 選択方法
	#                 =-1 ランダム(default)
	#                 =0 適応度をそのまま使用
	#                 =1 最小値からの差(ただし,α以下の場合はα)
	#                 =2 評価値に順位をつけ,減少率βで線形化
	#      k_bias : α,または,method=2の場合は初期値(default=0)
	#      k_step : β(default=1)
	###################################################################

	def C_mean(kosa, k_method = -1, k_bias = 0.0, k_step = 1.0)
	
				# 初期設定とデータのチェック
		if @_min_len > 0
			print("***error  遺伝子長は固定長でなければならない (C_mean)\n")
		end
				# 交叉
		for i1 in 0 ... @_max_ch
						# 交叉しない場合
			if rand(0) > kosa
				C_copy(1, 1)
						# 交叉する場合
			else
							# 親の選択
				p1 = Select(k_method, k_bias, k_step)
				p2 = p1
				sw = 0
				while sw == 0
					p2 = Select(k_method, k_bias, k_step)
					if p1 != p2
						sw = 1
					end
				end
							# 遺伝子長
				k         = Position(-1)
				@_len[k]  = @_len[p1]
				@_pi_w[k] = 1
							# 交叉
				for i2 in 0 ... @_len[k]
					@_ind[k][i2] = Integer((@_ind[p1][i2] + @_ind[p2][i2]) / 2)
				end
			end
		end
	end
	
	###################################################################
	# 交叉(循環交叉.ランダムに1点を選択し,その位置にある遺伝子を
	#       そのまま各子供が選択する.その位置にある親2(1)の遺伝
	#       子を,その遺伝子の親1(2)の場所に,子1(2)が受け継
	#       ぐ(ただし,doubleの場合は,この手続きをのぞく).この手
	#       続きを,すでに受け継いだ遺伝子の位置が選択されるまで繰り
	#       返し,残りの遺伝子については,子1(2)は,親2(1)の
	#       遺伝子をその順番通りに受け継ぐ)
	#         2 4 1 3 6 5    + + 1 + + 5    3 2 1 4 6 5
	#             *       →             →
	#         3 2 5 4 1 6    + + 5 + 1 +    2 4 5 3 1 6
	#      kosa : 交叉確率
	#      k_method : 選択方法
	#                 =-1 ランダム(default)
	#                 =0 適応度をそのまま使用
	#                 =1 最小値からの差(ただし,α以下の場合はα)
	#                 =2 評価値に順位をつけ,減少率βで線形化
	#      k_bias : α,または,method=2の場合は初期値(default=0)
	#      k_step : β(default=1)
	###################################################################
	def C_cycle(kosa, k_method = -1, k_bias = 0.0, k_step = 1.0)
	
				# 初期設定とデータのチェック
		pair = Integer(@_max_ch / 2)
	
		if @_dup_a != 0
			print("***error  交叉方法が不適当 (C_cycle)\n")
		end
	
		if @_min_len > 0
			print("***error  遺伝子長は固定長でなければならない (C_cycle)\n")
		end
				# 交叉
		for i1 in 0 ... pair
						# 交叉しない場合
			if rand(0) > kosa
				C_copy(2, 1)
						# 交叉する場合
			else
							# 親の選択
				p1 = Select(k_method, k_bias, k_step)
				p2 = p1
				sw = 0
				while sw == 0
					p2 = Select(k_method, k_bias, k_step)
					if p1 != p2
						sw = 1
					end
				end
							# 初期設定
				for i2 in 0 ... @_len[p1]
					@_kou1[i2] = 0
					@_kou2[i2] = 0
				end
							# 遺伝子長
				k1         = Position(-1)
				@_pi_w[k1] = 1
				@_len[k1]  = @_len[p1]
				k2         = Position(-1)
				@_pi_w[k2] = 1
				@_len[k2]  = @_len[p2]
							# 交叉
				sw = 0
	
				while sw == 0
					sw = 1
					p  = Integer(rand(0) * @_len[p1])
					if p >= @_len[p1]
						p = @_len[p1] - 1
					end
					if @_kou1[p] == 0 and @_kou2[p] == 0
						@_kou1[p]    = 1
						@_kou2[p]    = 1
						@_ind[k1][p] = @_ind[p1][p]
						@_ind[k2][p] = @_ind[p2][p]
						for i2 in 0 ... @_len[p1]
							if @_ind[p2][p] == @_ind[p1][i2]
								@_ind[k1][i2] = @_ind[p1][i2]
								@_kou1[i2]    = 1
								sw            = 0
								break
							end
						end
						sw = 1
						for i2 in 0 ... @_len[p2]
							if @_ind[p1][p] == @_ind[p2][i2]
								@_ind[k2][i2] = @_ind[p2][i2]
								@_kou2[i2]    = 1
								sw            = 0
								break
							end
						end
					end
				end
	
				sw = 0
				i2 = 0
				i3 = 0
				while sw == 0
					while sw == 0 and i2 < @_len[p1]
						if @_kou1[i2] == 0
							sw = 1
						else
							i2 += 1
						end
					end
					sw = 0
					while sw == 0 and i3 < @_len[p2]
						if @_kou2[i3] == 0
							sw = 1
						else
							i3 += 1
						end
					end
					if i2 < @_len[p1] and i3 < @_len[p2]
						@_ind[k1][i2] = @_ind[p2][i3]
						@_ind[k2][i3] = @_ind[p1][i2]
						sw            = 0
						i2 += 1
						i3 += 1
					else
						sw = 1
					end
				end
			end
		end
	end
	
	###################################################################
	# 交叉(部分的交叉.ランダムに1点を選択し,その位置にある親1と
	#       親2の遺伝子を取り出す.次に,親1と親2の染色体上で,こ
	#       の2つの遺伝子の位置を交換する.この操作を,選択した点よ
	#       り右にあるすべての遺伝子に対して実施する
	#         2 4 1 3 6 5    2 4 5 3 6 1
	#             *       →             → ・・・・・
	#         3 2 5 4 1 6    3 2 1 4 5 6
	#      kosa : 交叉確率
	#      k_method : 選択方法
	#                 =-1 ランダム(default)
	#                 =0 適応度をそのまま使用
	#                 =1 最小値からの差(ただし,α以下の場合はα)
	#                 =2 評価値に順位をつけ,減少率βで線形化
	#      k_bias : α,または,method=2の場合は初期値(default=0)
	#      k_step : β(default=1)
	#******************************************************************/
	def C_part(kosa, k_method = -1, k_bias = 0.0, k_step = 1.0)
	
				# 初期設定とデータのチェック
		pair = Integer(@_max_ch / 2)
	
		if @_dup_a != 0
			print("***error  交叉方法が不適当 (C_part)\n")
		end
	
		if @_min_len > 0
			print("***error  遺伝子長は固定長でなければならない (C_part)\n")
		end
				# 交叉
		for i1 in 0 ... pair
						# 交叉しない場合
			if rand(0) > kosa
				C_copy(2, 1)
						# 交叉する場合
			else
							# 親の選択
				p1 = Select(k_method, k_bias, k_step)
				p2 = p1
				sw = 0
				while sw == 0
					p2 = Select(k_method, k_bias, k_step)
					if p1 != p2
						sw = 1
					end
				end
							# 遺伝子長
				k1         = Position(-1)
				@_pi_w[k1] = 1
				@_len[k1]  = @_len[p1]
				k2         = Position(-1)
				@_pi_w[k2] = 1
				@_len[k2]  = @_len[p2]
							# 交叉
				p = Integer(rand(0) * @_len[p1])
				if p >= @_len[p1]
					p = @_len[p1] - 1
				end
	
				for i2 in 0 ... @_len[p1]
					@_ind[k1][i2] = @_ind[p1][i2]
					@_ind[k2][i2] = @_ind[p2][i2]
				end
	
				for i2 in p ... @_len[p1]
					sw = 0
					lv = @_ind[k1][i2]
					for i3 in 0 ... @_len[p1]
						if @_ind[k2][i2] == @_ind[k1][i3]
							@_ind[k1][i2] = @_ind[k1][i3]
							@_ind[k1][i3] = lv
							sw            = 1
							break
						end
					end
					sw = 0
					for i3 in 0 ... @_len[p1]
						if lv == @_ind[k2][i3]
							@_ind[k2][i3] = @_ind[k2][i2]
							@_ind[k2][i2] = lv
							sw            = 1
							break
						end
					end
				end
			end
		end
	end
	
	###################################################################
	# 交叉(順序交叉.ランダムに切れ目を決定し,子1に対し,切れ目の
	#       左側では,親1の遺伝子をそのまま受け継ぎ,右側では,親1
	#       の遺伝子を親2の遺伝子の出現順序に並べ替える.
	#         2 4 1 3 6 5    2 4 1 3 5 6
	#             *       →
	#         3 2 5 4 1 6    3 2 5 4 1 6
	#      kosa : 交叉確率
	#      k_method : 選択方法
	#                 =-1 ランダム(default)
	#                 =0 適応度をそのまま使用
	#                 =1 最小値からの差(ただし,α以下の場合はα)
	#                 =2 評価値に順位をつけ,減少率βで線形化
	#      k_bias : α,または,method=2の場合は初期値(default=0)
	#      k_step : β(default=1)
	###################################################################
	def C_seq(kosa, k_method = -1, k_bias = 0.0, k_step = 1.0)
	
				# 初期設定とデータのチェック
		pair = Integer(@_max_ch / 2)
	
		if @_dup_a != 0
			print("***error  交叉方法が不適当 (C_seq)")
		end
	
		if @_min_len > 0
			print("***error  遺伝子長は固定長でなければならない (C_seq)")
		end
				# 交叉
		for i1 in 0 ... pair
						# 交叉しない場合
			if rand(0) > kosa
				C_copy(2, 1)
						# 交叉する場合
			else
							# 親の選択
				p1 = Select(k_method, k_bias, k_step)
				p2 = p1
				sw = 0
				while sw == 0
					p2 = Select(k_method, k_bias, k_step)
					if p1 != p2
						sw = 1
					end
				end
							# 遺伝子長
				k1         = Position(-1)
				@_pi_w[k1] = 1
				@_len[k1]  = @_len[p1]
				k2         = Position(-1)
				@_pi_w[k2] = 1
				@_len[k2]  = @_len[p2]
							# 交叉
				p = Integer(rand(0) * (@_len[p1] - 1))
				if p >= @_len[p1]-1
					p = @_len[p1] - 2
				end
	
				for i2 in 0 ... p+1
					@_ind[k1][i2] = @_ind[p1][i2]
					@_ind[k2][i2] = @_ind[p2][i2]
				end
	
				pp = 0
				for i2 in p+1 ... @_len[p1]
					sw = 0
					i3 = pp
					while i3 < @_len[p2] and sw == 0
						i4 = p + 1
						while i4 < @_len[p1] and sw == 0
							if @_ind[p2][i3] == @_ind[p1][i4]
								sw               = 1
								pp               = i3 + 1
								@_ind[k1][i2] = @_ind[p1][i4]
							end
							i4 += 1
						end
						i3 += 1
					end
				end
				pp = 0
				for i2 in p+1 ... @_len[p2]
					sw = 0
					i3 = pp
					while i3 < @_len[p1] and sw == 0
						i4 = p + 1
						while i4 < @_len[p2] and sw == 0
							if @_ind[p1][i3] == @_ind[p2][i4]
								sw               = 1
								pp               = i3 + 1
								@_ind[k2][i2] = @_ind[p2][i4]
							end
							i4 += 1
						end
						i3 += 1
					end
				end
			end
		end
	end
	
	###################################################################
	# 交叉(一様順序交叉.位置の集合をランダムに選択し,一方の親の選
	#       択された位置における遺伝子の順序に従って,他の親の遺伝子
	#       を並べ替える
	#         2 4 1 3 6 5    2 4 1 3 6 5
	#           *   *     →
	#         3 2 5 4 1 6    4 2 5 3 1 6
	#      kosa : 交叉確率
	#      k_method : 選択方法
	#                 =-1 ランダム(default)
	#                 =0 適応度をそのまま使用
	#                 =1 最小値からの差(ただし,α以下の場合はα)
	#                 =2 評価値に順位をつけ,減少率βで線形化
	#      k_bias : α,または,method=2の場合は初期値(default=0)
	#      k_step : β(default=1)
	###################################################################
	
	def C_useq(kosa, k_method = -1, k_bias = 0.0, k_step = 1.0)
	
				# 初期設定とデータのチェック
		pair =Integer(@_max_ch / 2)
	
		if @_dup_a != 0
			print("***error  交叉方法が不適当 (C_useq)\n")
		end
	
		if @_min_len > 0
			print("***error  遺伝子長は固定長でなければならない (C_useq)\n")
		end
				# 交叉
		for i1 in 0 ... pair
						# 交叉しない場合
			if rand(0) > kosa
				C_copy(2, 1)
						# 交叉する場合
			else
							# 親の選択
				p1 = Select(k_method, k_bias, k_step)
				p2 = p1
				sw = 0
				while sw == 0
					p2 = Select(k_method, k_bias, k_step)
					if p1 != p2
						sw = 1
					end
				end
							# 遺伝子長
				k1         = Position(-1)
				@_pi_w[k1] = 1
				@_len[k1]  = @_len[p1]
				k2         = Position(-1)
				@_pi_w[k2] = 1
				@_len[k2]  = @_len[p2]
							# 交叉
				for i2 in 0 ... @_len[p1]
					@_ind[k1][i2] = @_ind[p1][i2]
					@_ind[k2][i2] = @_ind[p2][i2]
					if rand(0) < 0.5
						@_kou1[i2] = 0
					else
						@_kou1[i2] = 1
					end
				end
	
				p = 0
				for i2 in 0 ... @_len[p1]
					if @_kou1[i2] > 0
						sw = 0
						i3 = p
						while i3 < @_len[p2] and sw == 0
							i4 = 0
							while i4 < @_len[p1] and sw == 0
								if @_ind[p2][i3] == @_ind[p1][i4] and @_kou1[i4] > 0
									sw            = 1
									p             = i3 + 1
									@_ind[k1][i2] = @_ind[p1][i4]
								end
								i4 += 1
							end
							i3 += 1
						end
					end
				end
				p = 0
				for i2 in 0 ... @_len[p3]
					if @_kou1[i2] > 0
						sw = 0
						i3 = p
						while i3 < @_len[p1] and sw == 0
							i4 = 0
							while i4 < @_len[p2] and sw == 0
								if @_ind[p1][i3] == @_ind[p2][i4] and @_kou1[i4] > 0
									sw            = 1
									p             = i3 + 1
									@_ind[k2][i2] = @_ind[p2][i4]
								end
								i4 += 1
							end
							i3 += 1
						end
					end
				end
			end
		end
	end
	
	###################################################################
	# 交叉(一様位置交叉.位置の集合をランダムに選択し,一方の親の選
	#       択された位置における遺伝子の位置に,他の親の同じ遺伝子を
	#       配置する.残りの遺伝子は,親と同じ順序に配置する.
	#         2 4 1 3 6 5    + + 5 + 1 +    2 4 5 3 1 6
	#             *   *   →             →
	#         3 2 5 4 1 6    + + 1 + 6 +    3 2 1 5 6 4
	#      kosa : 交叉確率
	#      k_method : 選択方法
	#                 =-1 ランダム(default)
	#                 =0 適応度をそのまま使用
	#                 =1 最小値からの差(ただし,α以下の場合はα)
	#                 =2 評価値に順位をつけ,減少率βで線形化
	#      k_bias : α,または,method=2の場合は初期値(default=0)
	#      k_step : β(default=1)
	###################################################################

	def C_upos(kosa, k_method = -1, k_bias = 0.0, k_step = 1.0)
	
				# 初期設定とデータのチェック
		pair = Integer(@_max_ch / 2)
	
		if @_dup_a != 0
			print("***error  交叉方法が不適当 (C_upos)\n")
		end
	
		if @_min_len > 0
			print("***error  遺伝子長は固定長でなければならない (C_upos)\n")
		end
				# 交叉
		for i1 in 0 ... pair
						# 交叉しない場合
			if rand(0) > kosa
				C_copy(2, 1)
						# 交叉する場合
			else
							# 親の選択
				p1 = Select(k_method, k_bias, k_step)
				p2 = p1
				sw = 0
				while sw == 0
					p2 = Select(k_method, k_bias, k_step)
					if p1 != p2
						sw = 1
					end
				end
							# 遺伝子長
				k1         = Position(-1)
				@_pi_w[k1] = 1
				@_len[k1]  = @_len[p1]
				k2         = Position(-1)
				@_pi_w[k2] = 1
				@_len[k2]  = @_len[p2]
							# 交叉
				for i2 in 0 ... @_len[p1]
					@_kou1[i2] = 1
					if rand(0) < 0.5
						@_kou1[i2] = 1
					end
					if @_kou1[i2] > 0
						@_ind[k1][i2] = @_ind[p2][i2]
						@_ind[k2][i2] = @_ind[p1][i2]
					end
				end
	
				p = 0
				for i2 in 0 ... @_len[p1]
					sw = 0
					for i3 in 0 ... @_len[p1]
						if @_kou1[i3] > 0 and @_ind[p1][i2] == @_ind[k1][i3]
							sw = 1
							break
						end
					end
					if sw == 0
						for i3 in p ... @_len[p1]
							if @_kou1[i3] == 0
								@_ind[k1][i3] = @_ind[p1][i2]
								p             = i3 + 1
								sw            = 1
								break
							end
						end
					end
				end
				p = 0
				for i2 in 0 ... @_len[p2]
					sw = 0
					for i3 in 0 ... @_len[p2]
						if @_kou1[i3] > 0 and @_ind[p2][i2] == @_ind[k2][i3]
							sw = 1
							break
						end
					end
					if sw == 0
						for i3 in p ... @_len[p2]
							if @_kou1[i3] == 0
								@_ind[k2][i3] = @_ind[p2][i2]
								p                = i3 + 1
								sw               = 1
								break
							end
						end
					end
				end
			end
		end
	end
	
	###################################################################
	# 交叉(エッジ組み替え交叉.以下の手順に従って行う.対立遺伝子は
	#       0~(max_len-1)である必要がある)
	#         (0) エッジマップを作成する.エッジマップとは,2つの親
	#             を見て,ノードがどこに接続されているのかを表すもの
	#             であり,例えば,2つの親が,
	#                 [A B C D E F]
	#                 [B D C A E F]
	#             である場合は,
	#                 A B F C E
	#                 B A C D F
	#                 C B D A
	#                 D C E B
	#                 E D F A
	#                 F A E B
	#             となる. 
	#         (1) 両親の2つの出発点の内1つで初期化する.ランダムま
	#             たはステップ(4)の基準に従って選ぶ(現在のノード)
	#         (2) エッジマップから,現在のノードを除く
	#         (3) 現在のノードが接続先のノードを持っていたら,(4)に
	#             進む.さもなければ,(5)に進む
	#         (4) 現在のノードが持っている接続先ノードの内,最も少な
	#             い接続先ノードを持ったノードを選択し(同じ条件の場
	#             合は,ランダム),それを現在のノードとし,(2)に進む
	#         (5) 未接続のノードが残っていればランダムに選択し,(2)に
	#             戻る.さもなければ,終了する
	#      kosa : 交叉確率
	#      k_method : 選択方法
	#                 =-1 ランダム(default)
	#                 =0 適応度をそのまま使用
	#                 =1 最小値からの差(ただし,α以下の場合はα)
	#                 =2 評価値に順位をつけ,減少率βで線形化
	#      k_bias : α,または,method=2の場合は初期値(default=0)
	#      k_step : β(default=1)
	###################################################################

	def C_edge(kosa, k_method = -1, k_bias = 0.0, k_step = 1.0)
	
		e  = Array.new(2)
		k0 = 0
				# 初期設定とデータのチェック
		pair = @_max_ch
	
		if @_dup_a != 0
			print("***error  交叉方法が不適当 (C_edge)\n")
		end
	
		if @_min_len > 0
			print("***error  遺伝子長は固定長でなければならない (C_edge)\n")
		end
				# 交叉
		for i1 in 0 ... pair
						# 交叉しない場合
			if rand(0) > kosa
				C_copy(1, 1)
						# 交叉する場合
			else
							# 親の選択
				p1 = Select(k_method, k_bias, k_step)
				p2 = p1
				sw = 0
				while sw == 0
					p2 = Select(k_method, k_bias, k_step)
					if p1 != p2
						sw = 1
					end
				end
							# 遺伝子長
				k         = Position(-1)
				@_pi_w[k] = 1
				@_len[k]  = @_len[p1]
							# エッジマップの初期化
				for i2 in 0 ... @_len[k]
					@_edge[i2][0] = 0
					for i3 in 1 ... 5
						@_edge[i2][i3] = -1
					end
				end
							# 交叉
								# エッジマップの作成
				for i2 in 0 ... @_len[k]
	
					sw = 0
					for i3 in 0 ... @_len[k]
						if i2 == @_ind[p1][i3]
							sw = 1
							if i3 == 0
								e[0] = @_ind[p1][@_len[k]-1]
								e[1] = @_ind[p1][1]
							else
								if i3 == @_len[k]-1
									e[0] = @_ind[p1][i3-1]
									e[1] = @_ind[p1][0]
								else
									e[0] = @_ind[p1][i3-1]
									e[1] = @_ind[p1][i3+1]
								end
							end
							for i4 in 0 ... 2
								@_edge[i2][0] += 1
								@_edge[i2][@_edge[i2][0]] = e[i4]
							end
							break
						end
					end
	
					sw = 0
					for i3 in 0 ... @_len[k]
						if i2 == @_ind[p2][i3]
							sw = 1
							if i3 == 0
								e[0] = @_ind[p2][@_len[k]-1]
								e[1] = @_ind[p2][1]
							else
								if i3 == @_len[k]-1
									e[0] = @_ind[p2][i3-1]
									e[1] = @_ind[p2][0]
								else
									e[0] = @_ind[p2][i3-1]
									e[1] = @_ind[p2][i3+1]
								end
							end
							for i4 in 0 ... 2
								sw = 1
								for i5 in 1 ... @_edge[i2][0]+1
									if @_edge[i2][i5] == e[i4]
										sw = 2
										break
									end
								end
								if sw == 1
									@_edge[i2][0] += 1
									@_edge[i2][@_edge[i2][0]] = e[i4]
								end
							end
							break
						end
					end
				end
								# 交叉の実行
									# 出発点の決定
				k1 = @_ind[p1][0]
				k2 = @_ind[p2][0]
				if @_edge[k1][0] == @_edge[k2][0]
					kk = k1
					if rand(0) > 0.5
						kk = k2
					end
				else
					kk = k2
					if @_edge[k1][0] < @_edge[k2][0]
						kk = k2
					end
				end
				@_ind[k][0] = kk
				p           = 1
	
				while p < @_len[k]
									# ノードの除去
					for i2 in 0 ... @_len[k]
						sw = 0
						if @_edge[i2][0] > 0
							for i3 in 1 ... 5
								if @_edge[i2][i3] == kk
									sw              = 1
									@_edge[i2][i3]  = -1
									@_edge[i2][0]  -= 1
									break
								end
							end
						end
					end
									# 次の現在ノードの選択
					min = 10
					num = 0
					for i2 in 1 ... 5
						if @_edge[kk][i2] >= 0
							k1 = @_edge[kk][i2]
							if @_edge[k1][0] >= 0 and @_edge[k1][0] < min
								num = 1
								min = @_edge[k1][0]
								k0  = k1
							else
								if @_edge[k1][0] == min
									num += 1
								end
							end
						end
					end
					if num > 1
						k1 = Integer(rand(0) * num) + 1
						if k1 > num
							k1 = num
						end
						k2 = 0
						k0 = -1
						i2 = 1
						while i2 <= 4 and k0 < 0
							if @_edge[kk][i2] >= 0
								if @_edge[@_edge[kk][i2]][0] == min
									k2 += 1
									if k1 == k2
										k0 = @_edge[kk][i2]
									end
								end
							end
							i2 += 1
						end
					else
						if num <= 0
							num = 0
							for i2 in 0 ... @_len[k]
								if i2 != kk and @_edge[i2][0] >= 0
									num += 1
								end
							end
							if num <= 0
								print("***error  invalid data (C_edge)\n")
							else
								k1 = Integer(rand(0) * num) + 1
								if k1 > num
									k1 = num
								end
								k2 = 0
								k0 = -1
								i2 = 0
								while i2 < @_len[k] and k0 < 0
									if i2 != kk and @_edge[i2][0] >= 0
										k2 += 1
										if k1 == k2
											k0 = i2
										end
									end
									i2 += 1
								end
							end
						end
					end
					@_edge[kk][0]  = -1
					@_ind[k][p]    = k0
					kk                = k0
					p                += 1
				end
			end
		end
	end
	
	##############################################################
	# 交叉(サブツアー交叉.2点交叉の拡張である.ただし,相手に
	#       同じ遺伝子のグループがない限り実行されない.たとえば
	#         ***abcd**
	#         *cdab****
	#       のような両親の時実行され,以下の4つの子供が生成され
	#       る)
	#         ***cdab**
	#         *abcd****
	#         ***badc**
	#         *dcba****
	#       最大,4*交叉回数*個体総数*(個体総数-1) 個の子
	#       供が生成される可能性があるので,子供の数としてこの値
	#       以上のデータを入力しておく必要がある.
	#      kosa : 交叉確率
	#      count : 1つのペアーに対する交差回数(default=10)
	##############################################################

	def C_sub(kosa, count = 10)
	
		t22 = 0
				# 初期設定とデータのチェック
		if (4*count*@_size*(@_size-1)) > @_max_ch
			print("***error  子供が多すぎる (C_sub)\n")
		end
				# 交叉
		for i1 in 0 ... @_size-1
						# 親1
			p1 = Position(i1)
	
			if p1 >= 0
	
				for i2 in i1 ... @_size
						# 親2
					p2 = Position(i2)
	
					if p2 >= 0
						# 交叉しない場合
						if rand(0) > kosa
							C_copy(2, 1)
						# 交叉する場合
						else
							# 交叉回数の制御
							for i3 in 0 ... count
								# 交叉位置の決定(点の後ろで交叉)
									# 親1の交叉位置
								t11 = Integer(rand(0) * @_len[p1])
								if t11 > (@_len[p1]-1)
									t11 = @_len[p1] - 1
								end
								sw = 0
								while sw == 0
									t12 = Integer(rand(0) * @_len[p1])
									if t12 > (@_len[p1]-1)
										t12 = @_len[p1] - 1
									end
									if t12 != t11
										sw = 1
									end
								end
								if t11 > t12
									k1  = t11
									t11 = t12
									t12 = k1
								end
									# 親2の交叉位置
								sw  = 0
								t21 = -1
								i4  = 0
								while i4 < @_len[p2] and t21 < 0
									i5 = t11
									while i5 <= t12 and t21 < 0
										if @_ind[p2][i4] == @_ind[p1][i5]
											t21 = i4
										end
										i5 += 1
									end
									i4 += 1
								end
								if t21 >= 0
									t22 = t21 + t12 - t11
									if t22 < @_len[p2]
										sw = 1
										i4 = t21 + 1
										while i4 <= t22 and sw > 0
											sw = 0
											i5 = t11
											while i5 <= t12 and sw == 0
												if @_ind[p2][i4] == @_ind[p1][i5]
													sw = 1
												end
												i5 += 1
											end
											i4 += 1
										end
									end
								end
									# 交叉の実行
								if sw > 0
	
									k1         = Position(-1)
									@_pi_w[k1] = 1
									@_len[k1]  = @_len[p1]
									k2         = Position(-1)
									@_pi_w[k2] = 1
									@_len[k2]  = @_len[p1]
									k3         = Position(-1)
									@_pi_w[k3] = 1
									@_len[k3]  = @_len[p2]
									k4         = Position(-1)
									@_pi_w[k4] = 1
									@_len[k4]  = @_len[p2]
	
									for i4 in 0 ... t11
										@_ind[k1][i4] = @_ind[p1][i4]
										@_ind[k2][i4] = @_ind[p1][i4]
									end
									for i4 in t11 ... t12+1
										@_ind[k1][i4] = @_ind[p2][t21+i4-t11]
										@_ind[k2][i4] = @_ind[p2][t22-i4+t11]
									end
									for i4 in t12+1 ... @_len[p1]
										@_ind[k1][i4] = @_ind[p1][i4]
										@_ind[k2][i4] = @_ind[p1][i4]
									end
									for i4 in 0 ... t21
										@_ind[k3][i4] = @_ind[p2][i4]
										@_ind[k4][i4] = @_ind[p2][i4]
									end
									for i4 in t21 ... t22+1
										@_ind[k3][i4] = @_ind[p1][t11+i4-t21]
										@_ind[k4][i4] = @_ind[p1][t12-i4+t21]
									end
									for i4 in t22+1 ... @_len[p2]
										@_ind[k3][i4] = @_ind[p2][i4]
										@_ind[k4][i4] = @_ind[p2][i4]
									end
								end
							end
						end
					end
				end
			end
		end
	end
	
	#######################################
	# 突然変異(対立遺伝子との置き換え)
	#      pr : 突然変異率
	#######################################

	def M_alle(pr)
	
				# データのチェックと初期設定
		if @_dup_a == 0
			print("***error  突然変異方法が不適当 (M_alle)\n")
		end
				# 実行
		for i1 in 0 ... @_size+@_max_ch
			if @_pi_w[i1] == 1
				for i2 in 0 ... @_len[i1]
					if rand(0) <= pr
						lid = Integer(rand(0) * (@_allele_u - @_allele_l + 1) + @_allele_l)
						if lid > @_allele_u
							lid = @_allele_u
						end
						if lid != @_ind[i1][i2]
							@_ind[i1][i2] = lid
						end
					end
				end
			end
		end
	end

	######################################################################
	# 突然変異(移動.2点を選択し,2番目の遺伝子を1番目の遺伝子の前に
	#           移動する)
	#      pr : 突然変異率
	######################################################################

	def M_move(pr)
	
		for i1 in 0 ... @_size+@_max_ch
	
			if @_pi_w[i1] == 1 and rand(0) <= pr
				# 位置の決定
						# p1
				p1 = Integer(rand(0) * @_len[i1])
				if p1 >= @_len[i1]
					p1 = @_len[i1] - 1
				end
						# p2
				p2 = p1
				sw = 0
				while sw == 0
					p2 = Integer(rand(0) * @_len[i1])
					if p2 >= @_len[i1]
						p2 = @_len[i1] - 1
					end
					if p2 != p1
						sw = 1
					end
				end
				# 実行
				if p2 > p1
					ld = @_ind[i1][p2]
					i2 = p2
					while i2 > p1
						@_ind[i1][i2] = @_ind[i1][i2-1]
						i2 -= -1
					end
					@_ind[i1][p1] = ld
				else
					ld = @_ind[i1][p2]
					for i2 in p2 ... p1-1
						@_ind[i1][i2] = @_ind[i1][i2+1]
					end
					@_ind[i1][p1-1] = ld
				end
			end
		end
	end
	
	########################################################
	# 突然変異(逆位.2点間の遺伝子順序を逆に並べ替える)
	#      pr : 突然変異率
	#      wd : >0 : 幅を固定
	#           =0 : 幅をランダム(default)
	########################################################

	def M_inv(pr, wd = 0)
	
		for i1 in 0 ... @_size+@_max_ch
	
			if @_pi_w[i1] == 1 and rand(0) <= pr
				# 区間の決定
				if wd == 0
					p1 = Integer(rand(0) * @_len[i1])
					if p1 >= @_len[i1]
						p1 = @_len[i1] - 1
					end
					sw = 0
					p2 = p1
					while sw == 0
						p2 = Integer(rand(0) * @_len[i1])
						if p2 >= @_len[i1]
							p2 = @_len[i1] - 1
						end
						if p2 != p1
							sw = 1
						end
					end
					if p1 > p2
						p  = p1
						p1 = p2
						p2 = p
					end
	
				else
					p1 = @_len[i1]
					while p1 > @_len[i1]-2
						p1 = Integer(rand(0) * @_len[i1])
					end
					p2 = p1 + wd - 1
					if p2 >= @_len[i1]
						p2 = @_len[i1] - 1
					end
				end
				# 実行
				sw = 0
				while sw == 0
					lid           = @_ind[i1][p1]
					@_ind[i1][p1] = @_ind[i1][p2]
					@_ind[i1][p2] = lid
					p1 += 1
					p2 -= 1
					if p1 >= p2
						sw = 1
					end
				end
			end
		end
	end
	
	######################################################################
	# 突然変異(スクランブル.2点間の遺伝子順序をランダムに並べ替える)
	#      pr : 突然変異率
	#      wd : >0 : 幅を固定
	#           =0 : 幅をランダム(default)
	######################################################################

	def M_scram(pr, wd = 0)
	
		for i1 in 0 ... @_size+@_max_ch
	
			if @_pi_w[i1] == 1 and rand(0) <= pr
				# 区間の決定
				if wd == 0
					p1 = Integer(rand(0) * @_len[i1])
					if p1 >= @_len[i1]
						p1 = @_len[i1] - 1
					end
					sw = 0
					p2 = p1
					while sw == 0
						p2 = Integer(rand(0) * @_len[i1])
						if p2 >= @_len[i1]
							p2 = @_len[i1] - 1
						end
						if p2 != p1
							sw = 1
						end
					end
					if p1 > p2
						p  = p1
						p1 = p2
						p2 = p
					end
	
				else
					p1 = @_len[i1]
					while p1 > @_len[i1]-2
						p1 = Integer(rand(0) * @_len[i1])
					end
					p2 = p1 + wd - 1
					if p2 >= @_len[i1]
						p2 = @_len[i1] - 1
					end
				end
				# 実行
				for i2 in p1 ... p2+1
					p = Integer(rand(0) * (p2 - p1 + 1) + p1)
					if p > p2
						p = p2
					end
					ld            = @_ind[i1][i2]
					@_ind[i1][i2] = @_ind[i1][p]
					@_ind[i1][p]  = ld
				end
			end
		end
	end
	
	######################################################################
	# 突然変異(転座.2点間の遺伝子を他の位置のものと置き換える.ただし
	#           重複部分はそのままとする)
	#      pr : 突然変異率
	#      wd : >0 : 幅を固定
	#           =0 : 幅をランダム(default)
	######################################################################

	def M_chg(pr, wd = 0)
	
		for i1 in 0 ... @_size+@_max_ch
	
			if @_pi_w[i1] == 1 and rand(0) <= pr
				# 区間等の決定([p1,p2]と[p3,p4]の入れ替え)
						# p1
				p1 = Integer(rand(0) * @_len[i1])
				if p1 >= @_len[i1]
					p1 = @_len[i1] - 1
				end
						# p3
				sw = 0
				p3 = p1
				while sw == 0
					p3 = Integer(rand(0) * @_len[i1])
					if p3 >= @_len[i1]
						p3 = @_len[i1] - 1
					end
					if p3 != p1
						sw = 1
					end
				end
						# 小さい方をp1,p2にする
				if p1 > p3
					p  = p1
					p1 = p3
					p3 = p
				end
						# p4, p2
				p4 = p1 + wd - 1
				if wd == 0
					p4 = Integer(rand(0) * (@_len[i1] - p3)) + p3
				end
				if p4 >= @_len[i1]
					p4 = @_len[i1] - 1
				end
				p2 = p1 + (p4 - p3)
						# 重複部分のチェック
				if p2 >= p3
					p  = p3 - 1
					p3 = p2 + 1
					p2 = p
					p4 = p3 + (p2 - p1)
				end
				# 実行
				p = p3
				for i2 in p1 ... p2+1
					ld             = @_ind[i1][i2]
					@_ind[i1][i2]  = @_ind[i1][p]
					@_ind[i1][p]   = ld
					p              += 1
				end
			end
		end
	end
	
	######################################################################
	# 突然変異(重複.2点間の遺伝子を他の位置にコピーする
	#      pr : 突然変異率
	#      wd : >0 : 幅を固定
	#           =0 : 幅をランダム(deafult)
	######################################################################

	def M_dup(pr, wd = 0)
	
				# データのチェック
		if @_dup_a == 0
			print("***error  突然変異方法が不適当 (M_dup)\n")
		end
				# 実行
		for i1 in 0 ... @_size+@_max_ch
	
			if @_pi_w[i1] == 1 and rand(0) <= pr
						# 区間の決定([p1,p2]を[p3,p4]にコピー)
							# p1
				p1 = Integer(rand(0) * @_len[i1])
				if p1 >= @_len[i1]
					p1 = @_len[i1] - 1
				end
							# p3
				sw = 0
				p3 = p1
				while sw == 0
					p3 = Integer(rand(0) * @_len[i1])
					if p3 >= @_len[i1]
						p3 = @_len[i1] - 1
					end
					if p3 != p1
						sw = 1
					end
				end
							# 区間を決める
				p2 = p1
				p4 = p1
				if p3 > p1
					p4 = p3 + wd - 1
					if wd == 0
						p4 = Integer(rand(0) * (@_len[i1] - p3)) + p3
					end
					if p4 >= @_len[i1]
						p4 = @_len[i1] - 1
					end
					p2 = p1 + (p4 - p3)
				else
					p2 = p1 + wd - 1
					if wd == 0
						p2 = Integer(rand(0) * (@_len[i1] - p1)) + p1
					end
					if p2 >= @_len[i1]
						p2 = @_len[i1] - 1
					end
					p4 = p3 + (p2 - p1)
						# 実行
				end
				p  = p4
				i2 = p2
				while i2 > p1-1
					@_ind[i1][p] = @_ind[i1][i2]
					p  -= 1
					i2 -= 1
				end
			end
		end
	end
	
	######################################################
	# 突然変異(摂動.値をある量だけ変化させる)
	#      pr : 突然変異率
	#      method : =0 正規分布(default)
	#               =1 一様分布
	#      m : 平均または一様分布の下限(default=0.0)
	#      s : 標準偏差または一様分布の上限(default=1.0)
	######################################################

	def M_per(pr, method = 0, m = 0.0, s = 1.0)
	
		wd = 0.0
				# データのチェックと初期設定
		if @_dup_a == 0
			print("***error  突然変異方法が不適当 (M_per)\n")
		end
	
		if method > 0
			wd = s - m
		end
				# 実行
		for i1 in 0 ... @_size+@_max_ch
			if @_pi_w[i1] == 1
				for i2 in 0 ... @_len[i1]
					if rand(0) <= pr
						if method == 0
							w = normalvariate(m, s)
						else
							w = rand(0) * wd
							if rand(0) < 0.5
								w = -w
							end
						end
						x1 = float(@_ind[i1][i2]) + w
						if x1 > @_allele_u
							x1 = @_allele_u
						else
							if x1 < @_allele_l
								x1 = @_allele_l
							end
						end
						@_ind[i1][i2] = Integer(x1)
					end
				end
			end
		end
	end
	
	##############################################
	# 突然変異(挿入.ある長さの遺伝子を挿入する)
	#      pr : 突然変異率
	#      wd : >0 幅を固定
	#           =0 幅をランダム(default)
	##############################################

	def M_ins(pr, wd = 0)
	
				# データのチェック
		if @_dup_a == 0 or @_min_len < 0
			print("***error  突然変異方法が不適当 (M_ins)\n")
		end
				# 実行
		for i1 in 0 ... @_size+@_max_ch
	
			if @_pi_w[i1] == 1 and rand(0) <= pr
						# 挿入位置の決定
				p = Integer(rand(0) * (@_len[i1] + 1))
				if p > @_len[i1]
					p = @_len[i1]
				end
						# 挿入する遺伝子長の決定
				l = wd
				if wd == 0
					l = Integer(rand(0) * (@_max_len - @_len[i1] + 1))
				end
				if l > @_max_len-@_len[i1]
					l = @_max_len - @_len[i1]
				else
					if l <= 0
						l = 1
					end
				end
						# 実行
							# 挿入場所の確保
				if p < @_len[i1]
					i2 = @_len[i1] + l - 1
					while i2 > p-1
						@_ind[i1][i2] = @_ind[i1][i2-l]
						i2 -= 1
					end
				end
							# 挿入場所の遺伝子の決定
				for i2 in p ... p+l
					ld = Integer(rand(0) * (@_allele_u - @_allele_l + 1) + @_allele_l)
					if ld > @_allele_u
						ld = @_allele_u
					end
					@_ind[i1][i2] = ld
				end
	
				@_len[i1]  += l
			end
		end
	end
	
	##############################################
	# 突然変異(削除.ある長さの遺伝子を削除する)
	#      pr : 突然変異率
	#      wd : >0 幅を固定
	#           =0 幅をランダム(default)
	##############################################

	def M_del(pr, wd = 0)
	
				# データのチェック
		if @_dup_a == 0 or @_min_len < 0
			print("***error  突然変異方法が不適当 (M_del)\n")
		end
				# 実行
		for i1 in 0 ... @_size+@_max_ch
	
			if @_pi_w[i1] == 1 and rand(0) <= pr
						# 削除位置の決定
				p = Integer(rand(0) * @_len[i1])
				if p >= @_len[i1]
					p = @_len[i1] - 1
				end
						# 削除する遺伝子長の決定
				max = @_len[i1] - p
				if @_len[i1]-@_min_len < @_len[i1]-p
					max = @_len[i1] - @_min_len
				end
				l = wd
				if wd == 0
					l = Integer(rand(0) * max + 1)
				end
				if l > max
					l = max
				end
						# 実行
				for i2 in 0 ... @_len[i1]-p-l
					@_ind[i1][p+i2] = @_ind[i1][p+i2+l]
				end
	
				@_len[i1]  -= l
			end
		end
	end
	
	######################################################################
	# 淘汰(エリート・ルーレット選択)
	#      elite : エリートで残す個体数(default=0)
	#      s_method : ルーレット板の作成方法(default=1)
	#                   =0 適応度をそのまま使用
	#                   =1 最小値からの差(ただし,α以下の場合はα)
	#                   =2 評価値に順位をつけ,減少率βで線形化
	#      s_bias : α,または,method=2の場合は初期値(default=0)
	#      s_step : β(default=1)
	######################################################################

	def S_roul(elite = 0, s_method = 1, s_bias = 0.0, s_step = 1.0)
	
		count = 0
		k     = 0
		n     = 0
				# 値のチェックと初期設定
		if s_method != 0 and s_method != 2
			s_method = 1
		end
	
		if elite > @_size
			print("***error  エリートで残す数が多すぎる (S_roul)\n")
		end
	
		if s_method == 2 and s_step <= 0.0
			s_step = 1.0
		end
	
		for i1 in 0 ... @_size+@_max_ch
			@_s_w[i1] = 0
		end
				# 重複個体を削除
		if @_dup_s == 0
			for i1 in 0 ... @_size+@_max_ch
				if @_pi_w[i1] > 0
					for i2 in i1+1 ... @_size+@_max_ch
						if @_pi_w[i2] > 0 and @_len[i1] == @_len[i2]
							sw = 0
							for i3 in 0 ... @_len[i1]
								if @_ind[i1][i3] != @_ind[i2][i3]
									sw = 1
									break
								end
							end
							if sw == 0
								@_pi_w[i2] = 0
							end
						end
					end
				end
			end
		end
	
		for i1 in 0 ... @_size+@_max_ch
			if @_pi_w[i1] > 1
				n += 1
			end
		end
	
		if n < 0 or @_dup_s == 0 and n < @_size
			print("***error  残す個体がない (S_roul)\n")
		end
				# 淘汰して残す個体を選ぶ
						# エリートの選択
		sw = 0
	
		while k < elite and k < n and sw == 0
			max = -1
			for i1 in 0 ... @_size+@_max_ch
				if @_pi_w[i1] > 1 and @_s_w[i1] == 0
					if max < 0 or @_pi[i1] > @_pi[max]
						max = i1
					end
				end
			end
			if max < 0
				sw = 1
			else
				@_s_w[max]  = 1
				k          += 1
			end
		end
						# ルーレット選択
		while count < @_size+@_max_ch and k < @_size
			p = Select(s_method, s_bias, s_step)
			if @_dup_s == 0 and @_s_w[p] > 0
				count += 1
			else
				count     = 0
				@_s_w[p] += 1
				k        += 1
			end
		end
							# 選択に失敗した場合の処理
		if @_dup_s == 0 and k < @_size
			i1 = 0
			while i1 < @_size+@_max_ch and k < @_size
				if @_pi_w[i1] > 1 and @_s_w[i1] == 0
					@_s_w[i1]  = 1
					k         += 1
				end
				i1 += 1
			end
		end
							# 複数回選択されたものの処理
		for i1 in 0 ... @_size+@_max_ch
			if @_s_w[i1] == 0
				@_pi_w[i1] = 0
			end
		end
	
		for i1 in 0 ... @_size+@_max_ch
			if @_s_w[i1] > 0
				if @_s_w[i1] > 1
					for i2 in 2 ... @_s_w[i1]+1
						k         = Position(-1)
						@_len[k]  = @_len[i1]
						@_pi_w[k] = 2
						@_pi[k]   = @_pi[i1]
						for i3 in 0 ... @_len[i1]
							@_ind[k][i3] = @_ind[i1][i3]
						end
					end
				end
			end
		end
	end
end
	
####################
# クラスTSPの定義
####################

class TSP < Species

	######################################
	# コンストラクタ
	#      name1 : Species定義ファイル名
	#      name2 : TSP定義ファイル名
	######################################

	def initialize(name1, name2)
	
		super(name1)   # 親のコンストラクタ
						# 基本データの入力
		inn = open(name2, "r")
	
		s = inn.gets().split(" ")
		@_out_lvl = Integer(s[1])   # 出力レベル
		                            #   =0 最終出力だけ
		                            #   n>0 n世代毎に出力(負の時はファイル)
		@_out_m   = Integer(s[3])  # 出力方法
		                           #   =0 すべてを出力
		                           #   =1 最大適応度の個体だけを出力
		s = inn.gets().split(" ")
		@_o_file = s[1]   # 出力ファイル名
		@_out_d  = Integer(s[3])   # 表示間隔

		s = inn.gets().split(" ")
		@_kosa_m   = Integer(s[1])   # 交叉方法
		                             #   =-1 交叉を使用しない
		                             #   =0 親のコピー
		                             #   =1 循環交叉
		                             #   =2 部分的交叉
		                             #   =3 順序交叉
		                             #   =4 一様順序交叉
		                             #   =5 一様位置交叉
		                             #   =6 エッジ組み替え交叉
		                             #   =7 サブツアー交叉
		@_kosa     = Float(s[3])   # 交叉確率
		@_k_point  = Integer(s[5])   # 交差点の数(負の時は,1から-k_point間のランダム)
		@_k_vr     = Integer(s[7])   # =0 両親とも同じ位置で交叉
		                       # =1 両親が異なる位置で交叉(遺伝子長は可変)
		@_k_method = Integer(s[9])   # 交叉の時の親の選択方法
		                             #   =-1 ランダム
		                             #   =0 適応度をそのまま使用
		                             #   =1 最小値からの差(ただし,α以下の場合はα)
		                             #   =2 評価値に順位をつけ,減少率βで線形化
		@_k_bias   = Float(s[11])   # α,または,method=2の場合は初期値
		@_k_step   = Float(s[13])   # β

		s = inn.gets().split(" ")
		@_mute_m = Integer(s[1])   # 突然変異方法
		                           #   =-1 突然変異を使用しない
		                           #   =0 移動
		                           #   =1 逆位
		                           #   =2 スクランブル
		                           #   =3 転座
		@_mute   = Float(s[3])   # 突然変異率
		@_wd     = Integer(s[5])   # 突然変異に使用する部分遺伝子長
		@_m_mean = Float(s[7])   # 摂動の平均値
		@_m_std  = Float(s[9])   # 摂動の標準偏差

		s = inn.gets().split(" ")
		@_elite    = Integer(s[1])   # エリート選択で残す数
		@_s_method = Integer(s[3])   # ルーレット板の作成方法
		                             #   =0 適応度をそのまま使用
		                             #   =1 最小値からの差(ただし,α以下の場合はα)
		                             #   =2 評価値に順位をつけ,減少率βで線形化
		@_s_bias   = Float(s[5])   # α,または,s_method=2の場合は初期値
		@_s_step   = Float(s[7])   # β

		s = inn.gets().split(" ")
		@_n_city  = Integer(s[1])   # 都市の数
		@_max_gen = Integer(s[3])   # 最大世代交代数

		s = inn.gets().split(" ")
		@_kinbo    = Integer(s[1])   # 近傍探索(0:行わない,1:行う)
		@_neib     = Integer(s[3])   # 近傍(2 or 3)

		s = inn.gets().split(" ")
		@_sel = Integer(s[1])   # エッジの選択方法
		                        #   =0 最良のものを選択
		                        #   =1 最初のものを選択
	
		if @_kinbo > 0 and @_neib != 2 and @_neib != 3
			print("***error  近傍の値が不適当\n")
		end
	
		if @_n_city != @_max_len
			print("***error  都市数が不適当\n")
		end
						# 都市の位置データ
		@_city = Array.new(@_n_city)
		for i1 in 0 ... @_n_city
			@_city[i1] = Array.new(2)
			s = inn.gets().split(" ")
			@_city[i1][0] = Integer(s[0])
			@_city[i1][1] = Integer(s[1])
		end
						# 距離テーブル
		@_rg = Array.new(@_n_city)
		for i1 in 0 ... @_max_len
			@_rg[i1] = Array.new(@_n_city)
		end
	
		for i1 in 0 ... @_n_city
			for i2 in i1+1 ... @_n_city
				x            = @_city[i2][0] - @_city[i1][0]
				y            = @_city[i2][1] - @_city[i1][1]
				@_rg[i1][i2] = Math.sqrt(x * x + y * y).round()
			end
		end
	
		for i1 in 1 ... @_n_city
			for i2 in 0 ... i1
				@_rg[i1][i2] = @_rg[i2][i1]
			end
		end
	
		inn.close()
	end
	
	###############
	# 全体の制御
	###############

	def Control()
	
		gen = 1
						# 初期集団の発生
		Init_std()
						# 評価
		if @_kinbo > 0
			Kinbo()
		else
			Adap()
		end
						# 出力
		print("***世代 " + String(gen) + " 適応度 max " + String(@_max) + " (" + String(@_max_n) + ") mean " + String(@_mean) + "\n")
	
		if @_out_lvl.abs() > 0
			Output(gen)
		end
						# 世代交代
		for gen in 2 ... @_max_gen+1
							# 交叉
			if @_kosa_m == 0
				C_copy()   # 親のコピー
			elsif @_kosa_m == 1
				C_cycle(@_kosa)   # 循環交叉
			elsif @_kosa_m == 2
				C_part(@_kosa)   # 部分的交叉
			elsif @_kosa_m == 3
				C_seq(@_kosa)   # 順序交叉
			elsif @_kosa_m == 4
				C_useq(@_kosa)   # 一様順序交叉
			elsif @_kosa_m == 5
				C_upos(@_kosa)   # 一様位置交叉
			elsif @_kosa_m == 6
				C_edge(@_kosa)   # エッジ組み替え交叉
			elsif @_kosa_m == 7
				C_sub(@_kosa, @_k_point)   # サブツアー交叉
			end
							# 突然変異
			if @_mute_m == 0
				M_move(@_mute)   # 移動
			elsif @_mute_m == 1
				M_inv(@_mute)   # 逆位
			elsif @_mute_m == 2
				M_scram(@_mute)   # スクランブル
			elsif @_mute_m == 3
				M_chg(@_mute)   # 転座
			end
							# 適応度
			if @_kinbo > 0
				Kinbo()
			else
				Adap()
			end
							# 淘汰
			S_roul(@_elite)
							# 出力
			if gen%@_out_d == 0
				print("***世代 " + String(gen) + " 適応度 max " + String(@_max) + " (" + String(@_max_n) + ") mean " + String(@_mean) + "\n")
			end
	
			if @_out_lvl.abs() > 0
				if gen%@_out_lvl.abs() == 0
					Output(gen)
				end
			end
		end
	
		gen     -= 1
		k1       = @_out_m
		@_out_m  = 0
		print("***世代 " + String(gen) + " 適応度 max " + String(@_max) + " (" + String(@_max_n) + ") mean " + String(@_mean) + "\n")
		Output(gen)
		@_out_m = k1
	end
	
	##########################
	# 距離の計算
	#      n_c : 都市の数
	#      p : 都市番号
	#      return : 距離(負)
	##########################

	def Kyori(n_c, p)
	
		r  = 0
		n1 = p[0]
	
		for i1 in 1 ... n_c
			n2  = p[i1]
			r  -= @_rg[n1][n2]
			n1  = n2
		end

		n2  = p[0]
		r  -= @_rg[n1][n2]

		return r
	end

	################
	# 適応度の計算
	################

	def Adap()
	
		k       = 0
		@_mean  = 0.0
		@_max   = 0.0
		@_max_n = -1
	
		for i1 in 0 ... @_size+@_max_ch
			if @_pi_w[i1] == 1
				@_pi_w[i1] = 2
				@_pi[i1]   = Kyori(@_len[i1], @_ind[i1])
			end
			if @_pi_w[i1] > 0
				k      += 1
				@_mean += @_pi[i1]
				if @_max_n < 0 or @_pi[i1] > @_max
					@_max   = @_pi[i1]
					@_max_n = i1
				end
			end
		end
	
		if k > 0
			@_mean /= k
		end
	end

	######################################
	# エッジの入れ替え
	#      n_city : 都市の数
	#      seq : 訪問する順番
	#      r_m : 距離の負値
	#      return : =0 改善がなかった
	#               =1 改善があった
	######################################

	def Change(n_city, seq, r_m)
	
		ch  = 0
		sw  = 0
		max = r_m[0]
	
		n3  = Integer(rand(0) * (n_city - 2))
		if n3 > n_city-3
			n3 = n_city - 3
		end
	                         # 2近傍
		i1 = 0
		while i1 <= n_city-3 and ch == 0
	
			if n3 == 0
				n1 = n_city - 2
			else
				n1 = n_city - 1
			end
	
			i2 = n3 + 2
			while i2 <= n1 and ch == 0
	                              # 枝の場所((n3,n3+1), (k1,k2))
				k1 = i2
				if i2 == n_city-1
					k2 = 0
				else
					k2 = i2 + 1
				end
	                              # 枝の入れ替え
				@_kou1[0] = seq[n3]
				k         = 1
				i3        = k1
				while i3 > n3
					@_kou1[k]  = seq[i3]
					k         += 1
					i3        -= 1
				end
	
				nn = k2
				while nn != n3
					@_kou1[k] = seq[nn]
					k  += 1
					nn += 1
					if nn > n_city-1
						nn = 0
					end
				end
	                              # 評価
				r = Kyori(n_city, @_kou1)
	
				if r > max
					max = r
					sw  = 1
					for i3 in 0 ... n_city
						@_kou2[i3] = @_kou1[i3]
					end
					if @_sel > 0
						ch = 1
					end
				end
				i2 += 1
			end
	
			n3 += 1
			if n3 > n_city-3
				n3 = 0
			end
			i1 += 1
		end
	                         # 3近傍
		if @_neib == 3 and ch == 0
	
			i1 = 0
			while i1 <= n_city-3 and ch == 0
	
				n1 = n_city - 2
				n2 = n_city - 1
	
				i2 = n3 + 1
				while i2 <= n1 and ch == 0
	
					i3 = i2 + 1
					while i3 <= n2 and ch == 0
	                              # 枝の場所((n3,n3+1), (i2,i2+1), (k1,k2))
						k1 = i3
						k2 = k1
						if i3 == n_city-1
							k2 = 0
						else
							k2 = i3 + 1
						end
	                              # 枝の入れ替えと評価
	                                   # 入れ替え(その1)
						@_kou1[0] = seq[n3]
						k         = 1
						i4        = i2
						while i4 > n3
							@_kou1[k]  = seq[i4]
							k         += 1
							i4        -= 1
						end
	
						i4 = k1
						while i4 > i2
							@_kou1[k]  = seq[i4]
							k         += 1
							i4        -= 1
						end
	
						nn = k2
						while nn != n3
							@_kou1[k] = seq[nn]
							k  += 1
							nn += 1
							if nn > n_city-1
								nn = 0
							end
						end
	                                   # 評価(その1)
						r = Kyori(n_city, @_kou1)
	
						if r > max
							max = r
							sw  = 1
							for i3 in 0 ... n_city
								@_kou2[i3] = @_kou1[i3]
							end
							if @_sel > 0
								ch = 1
							end
						end
	                                   # 入れ替え(その2)
						@_kou1[0] = seq[n3]
						k         = 1
						i4        = k1
						while i4 > i2
							@_kou1[k]  = seq[i4]
							k         += 1
							i4        -= 1
						end
	
						for i4 in n3+1 ... i2+1
							@_kou1[k]  = seq[i4]
							k            += 1
						end
	
						nn = k2
						while nn != n3
							@_kou1[k] = seq[nn]
							k  += 1
							nn += 1
							if nn > n_city-1
								nn = 0
							end
						end
	                                   # 評価(その2)
						r = Kyori(n_city, @_kou1)
	
						if r > max
							max = r
							sw  = 1
							for i3 in 0 ... n_city
								@_kou2[i3] = @_kou1[i3]
							end
							if @_sel > 0
								ch = 1
							end
						end
	                                   # 入れ替え(その3)
						@_kou1[0] = seq[n3]
						k         = 1
						for i4 in i2+1 ... k1+1
							@_kou1[k]  = seq[i4]
							k         += 1
						end
	
						i4 = i2
						while i4 > n3
							@_kou1[k]  = seq[i4]
							k         += 1
							i4        -= 1
						end
	
						nn = k2
						while nn != n3
							@_kou1[k] = seq[nn]
							k  += 1
							nn += 1
							if nn > n_city-1
								nn = 0
							end
						end
	                                   # 評価(その3)
						r = Kyori(n_city, @_kou1)
	
						if r > max
							max = r
							sw  = 1
							for i3 in 0 ... n_city
								@_kou2[i3] = @_kou1[i3]
							end
							if @_sel > 0
								ch = 1
							end
						end
	                                   # 入れ替え(その4)
						@_kou1[0] = seq[n3]
						k         = 1
						for i4 in i2+1 ... k1+1
							@_kou1[k]  = seq[i4]
							k         += 1
						end
	
						for i4 in n3+1 ... i2+1
							@_kou1[k]  = seq[i4]
							k         += 1
						end
	
						nn = k2
						while nn != n3
							@_kou1[k] = seq[nn]
							k  += 1
							nn += 1
							if nn > n_city-1
								nn = 0
							end
						end
	                                   # 評価(その4)
						r = Kyori(n_city, @_kou1)
	
						if r > max
							max = r
							sw  = 1
							for i3 in 0 ... n_city
								@_kou2[i3] = @_kou1[i3]
							end
							if @_sel > 0
								ch = 1
							end
						end
						i3 += 1
					end
					i2 += 1
				end
	
				n3 += 1
				if n3 > n_city-3
					n3 = 0
				end
				i1 += 1
			end
		end
	                         # 設定
		if sw > 0
			r_m[0] = max
			for i1 in 0 ... n_city
				seq[i1] = @_kou2[i1]
			end
		end
	
		return sw
	end
	
	##############
	# 近傍の探索
	##############

	def Kinbo()
	
		k       = 0
		@_max   = 0.0
		@_max_n = -1
		@_mean  = 0.0
	
		for i1 in 0 ... @_size+@_max_ch
			if @_pi_w[i1] == 1
				@_pi_w[i1] = 2
				sw         = 1
				r          = Kyori(@_len[i1], @_ind[i1])
				while sw > 0
					r  = Array.new(1)
					sw = Change(@_len[i1], @_ind[i1], r)
				end
				@_pi[i1] = r[0]
			end
			if @_pi_w[i1] > 0
				k      += 1
				@_mean += @_pi[i1]
				if @_max_n < 0 or @_pi[i1] > @_max
					@_max   = @_pi[i1]
					@_max_n = i1
				end
			end
		end
	
		if k > 0
			@_mean /= k
		end
	end
	
	#############################
	# 結果の出力
	#      gen : 現在の世代番号
	#############################

	def Output(gen)
	
		k  = 0
		pr = -1

		if @_out_lvl >= 0
			print("   出力先は(0:出力なし,n:画面にn個づつ,-1:ファイル)? ")
			pr = Integer($stdin.gets())
		end
	
		if pr != 0
						# 出力先の決定と評価値の出力
			if pr > 0
				out = $stdout
				$stdin.gets()
			else
				now = String(Time.now)
				out = open(@_o_file, "a")
				out.print("***世代 " + String(gen) + " 適応度 max " + String(@_max) + " (" + String(@_max_n) + ") mean " + String(@_mean) + " 時間 " + now + "\n")
			end
						# 巡回順序の出力
			if @_out_m == 0
				for i1 in 0 ... @_len[@_max_n]
					n = @_ind[@_max_n][i1]
					out.print(String(n) + " " + String(@_city[n][0]) + " " + String(@_city[n][1]) + "\n")
					if pr > 0
						k += 1
						if k == pr
							$stdin.gets()
							k = 0
						end
					end
				end
			end
	
			if pr < 0
				out.close()
			end
		end
	end
end

				# 入力ミス
if ARGV[0] == nil
	print("***error  ファイル名を入力して下さい\n")
				# 入力OK
else
					# データの数と入力データファイル名の入力
	line   = gets()
	n      = Integer(line)   # データの数
	i_file1 = Array.new(n)
	i_file2 = Array.new(n)

	for i1 in 0 ... n
		line        = gets()
		a           = line.split(" ")
		i_file1[i1] = a[0]
		i_file2[i1] = a[1]
	end
					# 実行(乱数の初期値を変える)
	for i1 in 0 ... n

		print("\n+++++ケース " + String(i1+1) + "+++++\n")
		srand(1000 * i1 + 1234567);

		tsp = TSP.new(i_file1[i1], i_file2[i1])

		tsp.Control()
	end
end

=begin
----------------ケーススタディデータ(data_ct.txt)------
3
data1_t.txt data2_t.txt
data1_t.txt data2_t.txt
data1_t.txt data2_t.txt

---------------Species記述データ(data1_t.txt)---------
対立遺伝子上限 9 対立遺伝子下限 0
最大遺伝子長 10 最小遺伝子長(負の時は,最大遺伝子長で固定) -1
遺伝子の重複 0 個体の重複(同じ染色体の個体) 0
集団サイズ 10 子供 10

---------------TSP記述データ(data2_t.txt)--------
出力レベル(負はファイル) 10 出力方法(0:適応度+順番,1:適応度) 0
出力ファイル名 out1.txt 表示間隔 10
交叉方法 1 交叉確率 1.0 点 5 位置 0 方法 1 バイアス 0 ステップ 1
突然変異方法 1 突然変異率 0.03 幅 1 平均 0.0 標準偏差 1.0
エリート 2 方法 1 バイアス 0 ステップ 1
都市数 10 最大世代交代数 2000
近傍探索(0:行わない,1:行う) 0 近傍(2or3) 2
選択方法(0:最良,1:最初) 1
-58 37
55 -19
6 -79
27 -30
44 -94
33 -58
-94 87
-9 3
33 69
43 -57
=end