/****************************************************************************** ============== Network: Hopfield Model ============== Application: Autoassociative Memory Associative Recall of Images Description: The Hopfield model is used as an autoassociative memory to store and recall a set of bitmap images. Images are stored by calculating a corresponding weight matrix. Thereafter, starting from an arbitrary configuration, the memory will settle on exactly that stored image, which is nearest to the starting configuration in terms of Hamming distance. Thus given an incomplete or corrupted version of a stored image, the network is able to recall the corresponding original image. Author: Karsten Kutza Date: 30.1.96 Reference: J.J. Hopfield Neural Networks and Physical Systems with Emergent Collective Computational Abilities Proceedings of the National Academy of Sciences, 79, pp. 2554-2558, 1982 ******************************************************************************/ /****************************************************************************** D E C L A R A T I O N S ******************************************************************************/ #include #include typedef int BOOL; typedef char CHAR; typedef int INT; #define FALSE 0 #define TRUE 1 #define NOT ! #define AND && #define OR || #define LO -1 #define HI +1 #define BINARY(x) ((x)==LO ? FALSE : TRUE) #define BIPOLAR(x) ((x)==FALSE ? LO : HI) typedef struct { /* A NET: */ INT Units; /* - number of units in this net */ INT* Output; /* - output of ith unit */ INT* Threshold; /* - threshold of ith unit */ INT** Weight; /* - connection weights to ith unit */ } NET; /****************************************************************************** R A N D O M S D R A W N F R O M D I S T R I B U T I O N S ******************************************************************************/ void InitializeRandoms() { srand(4711); } INT RandomEqualINT(INT Low, INT High) { return rand() % (High-Low+1) + Low; } /****************************************************************************** A P P L I C A T I O N - S P E C I F I C C O D E ******************************************************************************/ #define NUM_DATA 5 #define X 10 #define Y 10 #define N (X * Y) CHAR Pattern[NUM_DATA][Y][X] = { { "O O O O O ", " O O O O O", "O O O O O ", " O O O O O", "O O O O O ", " O O O O O", "O O O O O ", " O O O O O", "O O O O O ", " O O O O O" }, { "OO OO OO", "OO OO OO", " OO OO ", " OO OO ", "OO OO OO", "OO OO OO", " OO OO ", " OO OO ", "OO OO OO", "OO OO OO" }, { "OOOOO ", "OOOOO ", "OOOOO ", "OOOOO ", "OOOOO ", " OOOOO", " OOOOO", " OOOOO", " OOOOO", " OOOOO" }, { "O O O O", " O O O ", " O O O ", "O O O O", " O O O ", " O O O ", "O O O O", " O O O ", " O O O ", "O O O O" }, { "OOOOOOOOOO", "O O", "O OOOOOO O", "O O O O", "O O OO O O", "O O OO O O", "O O O O", "O OOOOOO O", "O O", "OOOOOOOOOO" } }; CHAR Pattern_[NUM_DATA][Y][X] = { { " ", " ", " ", " ", " ", " O O O O O", "O O O O O ", " O O O O O", "O O O O O ", " O O O O O" }, { "OOO O O", " O OOO OO", " O O OO O", " OOO O ", "OO O OOO", " O OOO O", "O OO O O", " O OOO ", "OO OOO O ", " O O OOO" }, { "OOOOO ", "O O OOO ", "O O OOO ", "O O OOO ", "OOOOO ", " OOOOO", " OOO O O", " OOO O O", " OOO O O", " OOOOO" }, { "O OOOO O", "OO OOOO ", "OOO OOOO ", "OOOO OOOO", " OOOO OOO", " OOOO OO", "O OOOO O", "OO OOOO ", "OOO OOOO ", "OOOO OOOO" }, { "OOOOOOOOOO", "O O", "O O", "O O", "O OO O", "O OO O", "O O", "O O", "O O", "OOOOOOOOOO" } }; INT Input [NUM_DATA][N]; INT Input_[NUM_DATA][N]; FILE* f; void InitializeApplication(NET* Net) { INT n,i,j; for (n=0; nOutput[i*X+j]) ? 'O' : ' '); } fprintf(f, "\n"); } fprintf(f, "\n"); } void FinalizeApplication(NET* Net) { fclose(f); } /****************************************************************************** I N I T I A L I Z A T I O N ******************************************************************************/ void GenerateNetwork(NET* Net) { INT i; Net->Units = N; Net->Output = (INT*) calloc(N, sizeof(INT)); Net->Threshold = (INT*) calloc(N, sizeof(INT)); Net->Weight = (INT**) calloc(N, sizeof(INT*)); for (i=0; iThreshold[i] = 0; Net->Weight[i] = (INT*) calloc(N, sizeof(INT)); } } void CalculateWeights(NET* Net) { INT i,j,n; INT Weight; for (i=0; iUnits; i++) { for (j=0; jUnits; j++) { Weight = 0; if (i!=j) { for (n=0; nWeight[i][j] = Weight; } } } void SetInput(NET* Net, INT* Input) { INT i; for (i=0; iUnits; i++) { Net->Output[i] = Input[i]; } WriteNet(Net); } void GetOutput(NET* Net, INT* Output) { INT i; for (i=0; iUnits; i++) { Output[i] = Net->Output[i]; } WriteNet(Net); } /****************************************************************************** P R O P A G A T I N G S I G N A L S ******************************************************************************/ BOOL PropagateUnit(NET* Net, INT i) { INT j; INT Sum, Out; BOOL Changed; Changed = FALSE; Sum = 0; for (j=0; jUnits; j++) { Sum += Net->Weight[i][j] * Net->Output[j]; } if (Sum != Net->Threshold[i]) { if (Sum < Net->Threshold[i]) Out = LO; if (Sum > Net->Threshold[i]) Out = HI; if (Out != Net->Output[i]) { Changed = TRUE; Net->Output[i] = Out; } } return Changed; } void PropagateNet(NET* Net) { INT Iteration, IterationOfLastChange; Iteration = 0; IterationOfLastChange = 0; do { Iteration++; if (PropagateUnit(Net, RandomEqualINT(0, Net->Units-1))) IterationOfLastChange = Iteration; } while (Iteration-IterationOfLastChange < 10*Net->Units); } /****************************************************************************** S I M U L A T I N G T H E N E T ******************************************************************************/ void SimulateNet(NET* Net, INT* Input) { INT Output[N]; SetInput(Net, Input); PropagateNet(Net); GetOutput(Net, Output); } /****************************************************************************** M A I N ******************************************************************************/ void main() { NET Net; INT n; InitializeRandoms(); GenerateNetwork(&Net); InitializeApplication(&Net); CalculateWeights(&Net); for (n=0; n