/*********************************************************** OUTSTAR Simulator )Maureen Caudill Adaptics 16776 Bernardo Center Drive Suite 110 B San Diego, CA 92128 (617) 451-3752 July, 1988 Written in Lightspeed C (v. 2.15) on Macintosh Version 1.0 This outstar learns to reproduce a specified pattern on a grid of border neurodes. The pattern to be learned is read from an external text file called "pattern" -------------------------------------------------------------------------------- OPERATION OF THIS SIMULATOR Read AI Expert Article, November, 1988 for discussion of Grossberg Learning, Activation Equations and Instar/Outstar. This simulator models a biological system. The outstar neurode stimulates each of a 7x10 grid of neurodes at the same time as an external pattern stimulates the grid. The initial weight connections between the outstar and the grid neurodes are randomly set between -0.5 and +0.5. The initial activity in the grid is also randomly set to activity between 0.0 and 0.5. To run the simulator, you need to have a pattern file which contains the pattern you want the grid to learn to reproduce when stimulated by the outstar. The program begins by initializing the weights, activations, reading the data file and so on. Then the values of the Grossberg learning/activation constants are checked, with default values assumed initially. I suggest that you leave these values as they are until you are sure you understand the learning laws. The menu gives you four choices. 1. Train the network for some specified number of time units. 2. Allow the activation in the grid to decay for some number of time units 3. Test the network by having the outstar stimulate the grid for some number of time units. -1. Reset the network (and possibly change the network constants) to either quit or start over. When asked to enter the number of time units (for 1 or 2 or 3), remember that a negative number will only display the grid activation after that number of time units has passed, while a positive number displays the grid activation after each time unit. The proper operation of the simulator is as follows: train the network for some number of time periods. Remember that the transmission constant t0 determines how many time units must pass before the grid even sees the outstar's stimulus (the external pattern is applied immediately). Thus, if the t0 constant is 3, you should do NOTHING in less than 4 time units (3 to travel, and 1 to have an effect on the grid). allow the grid activation levels to decay to zero. No weight changes occur during this time (why?), so you are effectively just "clearing the slate". test the network (again for t0+1 time units). If the performance is inadequate, train again for additional time periods, then allow decay, then test. Have fun! ----------------------------------------------------------------------------------------- -------------------------------------------------------------------------------- STRUCTURE OF THIS FILE include files constant definitions general global storage Grossberg activation/learning constant storage (global) QQ Major functions QQ initialize();; initialize network operations train();; train the grid for a specified time decay();; allow grid activation to decay a specified time test();; test the grid for a specified time QQ Utility functions QQ compute_activation();; compute current activation for a grid neurode change_weight();; modify weight of a grid neurode read_pattern() ;; read pattern from data file parseline() ;; parse one line of data from file randomize_wts();; randomize weights on grid neurodes randomize_activity();; randomize activity of grid neurodes set_constants();; set Grossberg equation constants show_constants();; show current values of learning/activity constants show_wts();; print current weights on grid neurodes displaygrid();; print the current grid activation print_menu();; print menu of operator choices (train, test, decay, quit) QQ Main control function QQ main();; main control function ----------------------------------------------------------------------------------- ****************************************************************************************/ include include #defineROWSIZE7 defineCOLSIZE10 defineSTRINGSIZE80 defineQUIT-1 defineSTIMMASK1 defineACTIVATION 1 defineLEARNING2 defineDISPLAYON1 defineDISPLAYOFF2 defineSTIM1 defineNOSTIM0 /************* General Global Storage ***************************************************/ oublegridwts[ROWSIZE][COLSIZE]; /* this stores only the weights from the single outstar neurode to the grid of rim neurodes. */ ntpattern[ROWSIZE][COLSIZE]; /*this contains the pattern to be impressed on the grid of rim neurodes */ oubleactivity[ROWSIZE][COLSIZE]; /*this contains the current activation levels of each grid neurode */ ntcurtime;/* current time (in integral units) */ oubleoutstar;/* activation level of outstar */ har*inpath = "pattern";/* file containing pattern to be learned */ nsigned intoutstar_save;/*saves history of outstar's output */ /*****************************************************************************************/ /************* Grossberg Activation Constants (set by user or default values) ************/ oubleA = 0.9;/* activation decay constant */ oubleT = 0.0;/* threshold */ ntt0 = 1;/* transmission time between neurodes */ oubleF = 0.01;/* forgetting constant for long term memory */ oubleG = 0.2;/* learning constant for Hebbian learning term */ /************************************************************* initialize() initializes the system by: 1. reading in the pattern file 2.randomizing the weights 3.setting the current time to 0 4.establishing the activation/learning constants *************************************************************/ nitialize() read_pattern();/* read in training pattern from file */ randomize_wts();/* randomize weights to grid neurodes from outstar */ randomize_activity();/* randomize activity of grid neurodes */ show_wts();/* display resulting grid neurode weights */ curtime = 0;/* reset current time to 0 */ displaygrid(curtime);/* display the initial activity of the grid */ set_constants();/* set the constants to user specified values */ return; ************************************************************* train(duration) trains the outstar and grid for "duration" timeunits. weights are modified during this training period After each synchronous update of the grid, the activations are displayed. If training time is negative, only the grid status after all "duration" time units will be displayed. *************************************************************/ rain() intduration, displayflag; intstoptime; inti,j; intstim_grid, stim_outstar; /* ask how many time units to train */ printf("\n How many time units do you want the network to train? "); printf("\n (Integer value < 32767, negative suppresses all but final display) "); scanf("%d", &duration); displayflag = DISPLAYON; if (duration<0) { duration = -duration; displayflag = DISPLAYOFF; } stoptime = curtime+duration; for ( ; curtime> t0;/* right shift by t0 time units to allow for transmission time from outstar */ outstim = status & STIMMASK; change += gridwts[row][col]*outstim - T; } activity[row][col] += change;/* new activity = old plus incremental change */ return; /************************************************************************************** change_weight(row,col,out_on) modify the weight of the specified grid neurode synapse Parameter "out_on" is a flag indicating whether or not the outstar is currently stimulating the grid. Note that differential equation is calculated as an incremental difference equation. ***************************************************************************************/ hange_weight(row,col,out_on) ntrow,col, out_on; doublechange;/* the incremental change to this weight */ unsigned intstatus;/* local copy of global outstar output history */ intoutstim;/* effective stimulus from outstar at this time */ change = -F * activity[row][col]; if (out_on == STIM) { status = outstar_save;/* Be sure not to change the global version */ status = status >> t0;/* right shift by t0 time units to allow for transmission time from outstar */ outstim = status & STIMMASK; change += G * activity[row][col] * (outstim - T); } gridwts[row][col] += change; return; /******************************************************************* read_pattern() Read in the input data file and store the patterns in in_pats and out_pats. The format for the data file is as follows: line# data expected ----- ----------------------------- 1In-X-size,in-y-size 21st X row of 1st pattern 3..following rows of 1st pattern etc. Each row of data is separated by commas or spaces. The data is expected to be ascii text corresponding to either a +1 or a 0. Sample input for a pattern file (The comments to the right may NOT be in the file unless more sophisticated parsing of the input is done.): 5,7 input is 5x7 grid 0,1,1,1,0 beginning of pattern for "O" 1,0,0,0,1 1,0,0,0,1 1,0,0,0,1 1,0,0,0,1 1,0,0,0,0 0,1,1,1,0 Clearly, this simple scheme can be expanded or enhanced any way you like. Returns -1 if any file error occurred, otherwise 0. *******************************************************************/ ead_pattern() FILE*infile; intxinsize,yinsize; intrownum, numcols,x; intvalue, vals_read, status; charinstring[STRINGSIZE]; printf("\n Opening and retrieving data from file."); infile = fopen(inpath, "r"); if (infile == NULL) { printf("\n error in opening file!"); return -1 ; } vals_read =fscanf(infile,"%d,%d",&xinsize,&yinsize); if (vals_read != 2) { printf("\n Should read 2 items in line one; did read %d",vals_read); return -1; } if ((xinsize != ROWSIZE) || (yinsize != COLSIZE)) { printf("\n\n ERROR: Pattern file is invalid!"); printf("\n Pattern is a %d by %d grid instead of %d by %d", xinsize, yinsize, ROWSIZE, COLSIZE); return -1; } numcols = ROWSIZE; for (rownum = 0; rownum, "," 0,1 puts appropriate values in pattern array "", or "," is ignored Notice that this is an extremely primitive parsing routine. This can (and should) be improved or modified as desired. Return: -1 if error, 0 else. *******************************************************************/ arseline(string,numele,ygrid) harstring[]; ntnumele,ygrid; intvalue; intcharnum, ele; charch; charnum = 0; value = 0; ele = 0; while ((ele < numele) && (value == 0)) { if (charnum == STRINGSIZE) /* made it to the end without filling all element entries */ value = -1; else {/*This routine does not care if digits are separated or not. each instance of a 0 or 1 will be taken as an element entry in the pattern. */ ch = string[charnum]; switch (ch) { case '0' : /* each "0" will be treated as a grid entry */ pattern[ele][ygrid] = 0; ele++; break; case '1' : /* each "1" will be treated as a grid entry */ pattern[ele][ygrid] = 1; ele++; break; default : /* all other characters are ignored. */ break; } charnum++; } } return value; /******************************************************************* randomize_wts() Intialize the weights in the grid neurodes to random values between -0.25..+0.25 *******************************************************************/ andomize_wts() inti,j; doublevalue; printf("\n Please enter a random number seed (1..32767): "); scanf("%d", &i); srand(i); for(i=0; i= 0.17) && (value < 0.35)) printf(" . "); if ((value >= 0.35) && (value < 0.50)) printf(" _ "); if ((value >= 0.50) && (value < 0.67)) printf(" o "); if ((value >= 0.67) && (value < 0.83)) printf(" O "); if (value >= 0.83) printf(" % "); } printf(" "); for (i=0; i