Bidirectional Associative Memory This program is copyright © 1996 by the author. It is made available as is, and no warranty about the program, its performance, or its conformity to any specification - is given or implied. It may be used, modified, and distributed freely for private and commercial purposes, as long as the original author is credited as part of the final work. Bidirectional Associative Memory Simulator /**************************************************************************** ** Network: ================================ Bidirectional Associative Memory ================================ Application: Heteroassociative Memory Association of Names and Phone Numbers Author: Date: Karsten Kutza 24.1.96 Reference: B. Kosko Bidirectional Associative Memories IEEE Transactions on Systems, Man, and Cybernetics, 18, pp. 49-60, 1988 ***************************************************************************** */ /**************************************************************************** ** D E C L A R A T I O N S ***************************************************************************** */ #include <stdlib.h> #include <stdio.h> typedef int typedef char BOOL; CHAR; typedef int INT; #define #define #define #define #define 0 1 ! && || FALSE TRUE NOT AND OR #define LO #define HI -1 +1 #define BINARY(x) #define BIPOLAR(x) ((x)==LO ? FALSE : TRUE) ((x)==FALSE ? LO : HI) typedef struct { */ INT */ INT* */ INT** */ } LAYER; typedef struct { */ LAYER* */ LAYER* */ } NET; /* A LAYER OF A NET: Units; /* - number of units in this layer Output; /* - output of ith unit Weight; /* - connection weights to ith unit /* A NET: X; /* - X layer Y; /* - Y layer /**************************************************************************** ** 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); } BOOL RandomEqualBOOL() { return rand() % 2; } /**************************************************************************** ** 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 #define IN_CHARS #define OUT_CHARS 3 5 7 #define BITS_PER_CHAR 6 #define FIRST_CHAR ' ' #define N #define M (IN_CHARS * BITS_PER_CHAR) (OUT_CHARS * BITS_PER_CHAR) CHAR Names [NUM_DATA][IN_CHARS] = { "TINA ", "ANTJE", "LISA " }; CHAR Names_[NUM_DATA][IN_CHARS] = { "TINE ", "ANNJE", "RITA " }; CHAR Phones[NUM_DATA][OUT_CHARS] = { "6843726", "8034673", "7260915" }; INT INT INT Input [NUM_DATA][N]; Input_[NUM_DATA][N]; Output[NUM_DATA][M]; FILE* f; void InitializeApplication(NET* Net) { INT n,i,j,a,a_; for (n=0; n<NUM_DATA; n++) { for (i=0; i<IN_CHARS; i++) { a = Names [n][i] - FIRST_CHAR; a_ = Names_[n][i] - FIRST_CHAR; for (j=0; j<BITS_PER_CHAR; j++) { Input [n][i*BITS_PER_CHAR+j] = BIPOLAR(a % 2); Input_[n][i*BITS_PER_CHAR+j] = BIPOLAR(a_ % 2); a /= 2; a_ /= 2; } } for (i=0; i<OUT_CHARS; i++) { a = Phones[n][i] - FIRST_CHAR; for (j=0; j<BITS_PER_CHAR; j++) { Output[n][i*BITS_PER_CHAR+j] = BIPOLAR(a % 2); a /= 2; } } } f = fopen("BAM.txt", "w"); } void WriteLayer(LAYER* Layer) { INT i,j,a,p; for (i=0; i<(Layer->Units / BITS_PER_CHAR); i++) { a = 0; p = 1; for (j=0; j<BITS_PER_CHAR; j++) { a += BINARY(Layer->Output[i*BITS_PER_CHAR+j]) * p; p *= 2; } fprintf(f, "%c", a + FIRST_CHAR); } } 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->X = (LAYER*) malloc(sizeof(LAYER)); Net->Y = (LAYER*) malloc(sizeof(LAYER)); Net->X->Units = N; Net->X->Output = (INT*) calloc(N, sizeof(INT)); Net->X->Weight = (INT**) calloc(N, sizeof(INT*)); Net->Y->Units = M; Net->Y->Output = (INT*) calloc(M, sizeof(INT)); Net->Y->Weight = (INT**) calloc(M, sizeof(INT*)); for (i=0; i<N; i++) Net->X->Weight[i] } for (i=0; i<M; i++) Net->Y->Weight[i] } } { = (INT*) calloc(M, sizeof(INT)); { = (INT*) calloc(N, sizeof(INT)); void CalculateWeights(NET* Net) { INT i,j,n; INT Weight; for (i=0; i<Net->X->Units; i++) { for (j=0; j<Net->Y->Units; j++) { Weight = 0; for (n=0; n<NUM_DATA; n++) { Weight += Input[n][i] * Output[n][j]; } Net->X->Weight[i][j] = Weight; Net->Y->Weight[j][i] = Weight; } } } void SetInput(LAYER* Layer, INT* Input) { INT i; for (i=0; i<Layer->Units; i++) { Layer->Output[i] = Input[i]; } WriteLayer(Layer); } void SetRandom(LAYER* Layer) { INT i; for (i=0; i<Layer->Units; i++) { Layer->Output[i] = BIPOLAR(RandomEqualBOOL()); } WriteLayer(Layer); } void GetOutput(LAYER* Layer, INT* Output) { INT i; for (i=0; i<Layer->Units; i++) { Output[i] = Layer->Output[i]; } WriteLayer(Layer); } /**************************************************************************** ** P R O P A G A T I N G S I G N A L S ***************************************************************************** */ BOOL PropagateLayer(LAYER* From, LAYER* To) { INT i,j; INT Sum, Out; BOOL Stable; Stable = TRUE; for (i=0; i<To->Units; i++) { Sum = 0; for (j=0; j<From->Units; j++) { Sum += To->Weight[i][j] * From->Output[j]; } if (Sum != 0) { if (Sum < 0) Out = LO; if (Sum > 0) Out = HI; if (Out != To->Output[i]) { Stable = FALSE; To->Output[i] = Out; } } } return Stable; } void PropagateNet(LAYER* From, LAYER* To) { BOOL Stable1, Stable2; do { Stable1 = PropagateLayer(From, To); Stable2 = PropagateLayer(To, From); } while (NOT (Stable1 AND Stable2)); } /**************************************************************************** ** S I M U L A T I N G T H E N E T ***************************************************************************** */ void SimulateNet(LAYER* From, LAYER* To, INT* Pattern, INT* Input, INT* Output) { SetInput(From, Pattern); fprintf(f, " -> "); SetRandom(To); fprintf(f, " | "); PropagateNet(From, To); GetOutput(From, Input); fprintf(f, " -> "); GetOutput(To, Output); fprintf(f, "\n\n"); } /**************************************************************************** ** M A I N ***************************************************************************** */ void main() { NET Net; INT n; INT I[N], O[M]; InitializeRandoms(); GenerateNetwork(&Net); InitializeApplication(&Net); CalculateWeights(&Net); for (n=0; n<NUM_DATA; n++) { SimulateNet(Net.X, Net.Y, Input[n], I, O); } for (n=0; n<NUM_DATA; n++) { SimulateNet(Net.Y, Net.X, Output[n], O, I); } for (n=0; n<NUM_DATA; n++) { SimulateNet(Net.X, Net.Y, Input_[n], I, O); } FinalizeApplication(&Net); } Simulator Output for the Heteroassociative Memory Application TINA -> P:*[HBQ | TINA ANTJE -> !_+87&9 | ANTJE -> 8034673 LISA -> )@;ZV)- | LISA 6843726 -> SP4^L | 6843726 -> TINA 8034673 -> ^;GI# | 8034673 -> ANTJE 7260915 -> A-/%1 | 7260915 -> LISA TINE -> CW48F ^ | TINA ANNJE -> @ZB%8Q! | ANTJE -> 8034673 RITA | DIVA -> H0(@=^/ -> 6843726 -> 7260915 -> 6843726 -> 6060737