Hopfieldネットワーク( TSP )

##################################
# Hopfieldネットワーク( TSP )
#      Coded by Y.Suganuma
##################################

##################
# ユニットの出力
##################
def out(x)
	return 0.5 * (1.0 + Math.tanh(x))
#	return 1.0 / (1.0 + Math.exp(-x))
end

#***************/
# 微係数の計算 */
#***************/
snx = Proc.new { |time, u, du|
	for x in 0 ... $n
		for i in 0 ... $n
			k     = $n * x + i
			du[k] = 0.0
			for j in 0 ... $n
				if j != i
					du[k] -= $aa * out(u[$n*x+j])
				end
			end
			for y in 0 ... $n
				if y != x
					du[k] -= $bb * out(u[$n*y+i])
				end
			end
			nn = 0.0
			for xx in 0 ... $n
				for ii in 0 ... $n
					nn += out(u[$n*xx+ii])
				end
			end
			du[k] -= $cc * (nn - $n)
			for y in 0 ... $n
				m1 = (i + 1) % $n
				m2 = i - 1
				if m2 < 0
					m2 = $n - 1
				end
				du[k] -= $dd * $d[x][y] * (out(u[$n*y+m1]) + out(u[$n*y+m2]))
			end
		end
	end
}

#******************************************/
# ルンゲ・クッタ法  dx/dt=f(t,x)          */
#      time : 現在の時間                  */
#      h : 時間刻み幅                     */
#      x : 現在の状態                     */
#      dx : 微係数(f(t,x):snxで計算する)*/
#      g : 作業域(g[4][n])              */
#      n : 微分方程式の次数               */
#      snx : 微係数を計算する関数の名前   */
#      return : time+h                    */
#******************************************/
def rkg(time, h, x, dx, g, n, &sub)

	h2 = 0.5 * h

	sub.call(time, x, dx)
	for i1 in 0 ... n
		g[0][i1] = h * dx[i1]
	end

	time += h2
	for i1 in 0 ... n
		g[1][i1] = x[i1] + 0.5 * g[0][i1]
	end
	sub.call(time, g[1], dx)
	for i1 in 0 ... n
		g[1][i1] = h * dx[i1]
	end

	for i1 in 0 ... n
		g[2][i1] = x[i1] + 0.5 * g[1][i1]
	end
	sub.call(time, g[2], dx)
	for i1 in 0 ... n
		g[2][i1] = h * dx[i1]
	end

	time += h2
	for i1 in 0 ... n
		g[3][i1] = x[i1] + g[2][i1]
	end
	sub.call(time, g[3], dx)
	for i1 in 0 ... n
		g[3][i1] = h * dx[i1]
	end

	for i1 in 0 ... n
		x[i1] = x[i1] + (g[0][i1] + 2.0 * g[1][i1] + 2.0 * g[2][i1] + g[3][i1]) / 6.0
	end

	return time
end

$n  = 4
$nn = $n * $n
$aa = 10.0
$bb = 10.0
$cc = 10.0
$dd = 2.0
$d  = Array.new($n)
for i1 in 0 ... $n
	$d[i1] = Array.new($n)
end
					# 距離
r = Math.sqrt(2.0)
for i1 in 0 ... $n
	for i2 in 0 ... $n
		if i1 == i2
			$d[i1][i2] = 0.0
		else
			$d[i1][i2] = 1.0
		end
	end
end
$d[0][2] = r
$d[1][3] = r
$d[2][0] = r
$d[3][1] = r
					# 初期状態
srand()
u = Array.new($n)
for i1 in 0 ... $n
	u[i1] = Array.new($n)
	for i2 in 0 ... $n
		u[i1][i2] = 0.1 * rand(0) - 0.05
	end
end

print("初期状態(出力):\n")
for i1 in 0 ... $n
	for i2 in 0 ... $n
		print(" " + String(out(u[i1][i2])))
	end
	print("\n")
end
					# 更新
time = 0.0
dx   = Array.new(16)
g    = Array.new(4)
for i1 in 0 ... 4
	g[i1] = Array.new(16)
end
k  = 0
uu = Array.new(16)
for i1 in 0 ... 4
	for i2 in 0 ... 4
		uu[k] = u[i1][i2]
		k    += 1
	end
end
for i1 in 0 ... 100
	time = rkg(time, 1, uu, dx, g, $n*$n, &snx)
end

print("最終状態(出力):\n")
k = 0
for i1 in 0 ... $n
	for i2 in 0 ... $n
		print(" " + String(out(uu[k])))
		k += 1
	end
	print("\n")
end