<?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;
}
?>