<?php /*********************************/ /* Hopfieldネットワーク( TSP ) */ /* Coded by Y.Suganuma) */ /*********************************/ $n = 4; $A = 10.0; $B = 10.0; $C = 10.0; $D = 2.0; $d = array(4); for ($i1 = 0; $i1 < 4; $i1++) $d[$i1] = array(4); // 距離 $r = sqrt(2.0); for ($i1 = 0; $i1 < $n; $i1++) { for ($i2 = 0; $i2 < $n; $i2++) { if ($i1 == $i2) $d[$i1][$i2] = 0.0; else $d[$i1][$i2] = 1.0; } } $d[0][2] = $r; $d[1][3] = $r; $d[2][0] = $r; $d[3][1] = $r; // 初期状態 mt_srand(); $u = array(16); for ($i1 = 0; $i1 < $n; $i1++) { for ($i2 = 0; $i2 < $n; $i2++) $u[$i1*$n+$i2] = 0.1 * (mt_rand() / mt_getrandmax()) - 0.05; } printf("初期状態(出力):\n"); for ($i1 = 0; $i1 < $n; $i1++) { for ($i2 = 0; $i2 < $n; $i2++) printf("%6.3f", out($u[$i1*$n+$i2])); printf("\n"); } // 更新 $time = 0.0; $dx = array(16); $g = array(4); for ($i1 = 0; $i1 < 4; $i1++) $g[$i1] = array(16); for ($i1 = 0; $i1 < 100; $i1++) $time = rkg($time, 1, $u, $dx, $g, $n*$n, "snx"); printf("最終状態(出力):\n"); for ($i1 = 0; $i1 < $n; $i1++) { for ($i2 = 0; $i2 < $n; $i2++) printf("%6.3f", out($u[$i1*$n+$i2])); printf("\n"); } /******************/ /* ユニットの出力 */ /******************/ function out($x) { return 0.5 * (1.0 + tanh($x)); // return 1.0 / (1.0 + exp(-$x)); } /****************/ /* 微係数の計算 */ /****************/ function snx($time, $u, &$du) { global $n, $A, $B, $C, $D, $d; for ($x = 0; $x < $n; $x++) { for ($i = 0; $i < $n; $i++) { $k = $n * $x + $i; $du[$k] = 0.0; for ($j = 0; $j < $n; $j++) { if ($j != $i) $du[$k] -= $A * out($u[$n*$x+$j]); } for ($y = 0; $y < $n; $y++) { if ($y != $x) $du[$k] -= $B * out($u[$n*$y+$i]); } $N = 0.0; for ($xx = 0; $xx < $n; $xx++) { for ($ii = 0; $ii < $n; $ii++) $N += out($u[$n*$xx+$ii]); } $du[$k] -= $C * ($N - $n); for ($y = 0; $y < $n; $y++) { $m1 = ($i + 1) % $n; $m2 = $i - 1; if ($m2 < 0) $m2 = $n - 1; $du[$k] -= $D * $d[$x][$y] * (out($u[$n*$y+$m1]) + out($u[$n*$y+$m2])); } } } } /*******************************************/ /* ルンゲ・クッタ法 dx/dt=f(t,x) */ /* time : 現在の時間 */ /* h : 時間刻み幅 */ /* x : 現在の状態 */ /* dx : 微係数(f(t,x):snxで計算する)*/ /* g : 作業域(g[4][n]) */ /* n : 微分方程式の次数 */ /* sub : 微係数を計算する関数の名前 */ /* return : time+h */ /*******************************************/ function rkg($time, $h, &$x, $dx, $g, $n, $sub) { $h2 = 0.5 * $h; $sub($time, $x, $dx); for ($i1 = 0; $i1 < $n; $i1++) $g[0][$i1] = $h * $dx[$i1]; $time += $h2; for ($i1 = 0; $i1 < $n; $i1++) $g[1][$i1] = $x[$i1] + 0.5 * $g[0][$i1]; $sub($time, $g[1], $dx); for ($i1 = 0; $i1 < $n; $i1++) $g[1][$i1] = $h * $dx[$i1]; for ($i1 = 0; $i1 < $n; $i1++) $g[2][$i1] = $x[$i1] + 0.5 * $g[1][$i1]; $sub($time, $g[2], $dx); for ($i1 = 0; $i1 < $n; $i1++) $g[2][$i1] = $h * $dx[$i1]; $time += $h2; for ($i1 = 0; $i1 < $n; $i1++) $g[3][$i1] = $x[$i1] + $g[2][$i1]; $sub($time, $g[3], $dx); for ($i1 = 0; $i1 < $n; $i1++) $g[3][$i1] = $h * $dx[$i1]; for ($i1 = 0; $i1 < $n; $i1++) $x[$i1] = $x[$i1] + ($g[0][$i1] + 2.0 * $g[1][$i1] + 2.0 * $g[2][$i1] + $g[3][$i1]) / 6.0; return $time; } ?>