#include <math.h>
#include <stdlib.h>

/* 連続値ホップフィールドモデルの諸定数 */
#define TAU		1
#define DELTA_T		0.02
#define MU0		0.1
#define f(u)		(1/(1+exp(-2*u/MU0)))

/* 問題の定義 */
#define MAX_WEIGHT	14
int a[]={	/* 品物の重量 */
	3, 5, 4, 7, 2, 4
};
int c[]={	/* 品物の価値 */
	10, 13, 10, 16, 2, 3
};
/* 解=1 0 1 1 0 0 */
		/* 品物の数 */
#define N	(sizeof(a)/sizeof(a[0]))

/* エネルギー関数のための係数 */
#define A		0.3

/* ニューロンの定義 */
typedef struct {
	double w[N];		/* 結合係数 */
	double theta;		/* 閾値 */
	double u;		/* 内部状態 */
	double x;		/* 出力 */
} NeuronRec;

NeuronRec neuron[N];

#define rnd()	((double)rand()/RAND_MAX)
		/* [0, 1] の乱数 */

/* エネルギー関数 */
double Energy()
{
	register int i, j;
	double E;

	E=0.0;
	for(i=0; i<N; i++) {
		for(j=0; j<i; j++)
			E+=-neuron[i].w[j]*neuron[i].x*neuron[j].x;
		E+=neuron[i].theta*neuron[i].x;
	}
	/* 簡単のため,積分項を無視 */
	return(E);
}

/* Hopfield ネットワークの定義 */
Initialize()
{
	register int i, j;

	for(i=0; i<N; i++) {
		neuron[i].w[i]=0.0;
		for(j=0; j<i; j++)
			neuron[i].w[j]=neuron[j].w[i]=-2*A*a[i]*a[j];
		neuron[i].theta=-A*MAX_WEIGHT*a[i]-c[i];
	}
}

main()
{
	register int i, j, t;
	int changed;
	double x, du;

	/* 結合荷重と閾値の設定 */
	Initialize();

	/* ネットワークの初期状態の設定 */
	for(i=0; i<N; i++)
		neuron[i].u=rnd();
	for(t=0; ; t++) {
		changed=0;
		/* 出力の計算 */
		for(i=0; i<N; i++) {
			x=f(neuron[i].u);
			if(x!=neuron[i].x) {
				neuron[i].x=x;
				changed=1;
			}
		}

		/* 出力の表示 */
		printf("%3d: ", t);
		for(i=0; i<N; i++)
			printf("%lf ", neuron[i].x);
		printf(" => %lf\n", Energy());

		if(!changed) break;

		/* 状態の計算 */
		for(i=0; i<N; i++) {
			du=-neuron[i].u/TAU;
			for(j=0; j<N; j++)
				du+=neuron[i].w[j]*neuron[j].x;
			du-=neuron[i].theta;
			neuron[i].u+=du*DELTA_T;
		}
	}
}