Main Page   Namespace List   Class Hierarchy   Compound List   File List   Namespace Members   Compound Members   File Members  

kernel.c

Go to the documentation of this file.
00001 
00207 #include <math.h>
00208 #include <time.h>
00209 
00210 #include "ind_types.h"
00211 #include "ipc.h"
00212 #include "cmdparam.h"
00213 #include "binarysave.h"
00214 #include "vgen.h"
00215 #ifndef NO_INPUTS
00216 #include "inputs.h"  /* Only used in load_current() and cmd_training() */
00217 #endif
00218 #ifndef NO_IO
00219 #include "file_io.h" /* Only used in load_current(), save_current(), and cmd_training() */
00220 #endif
00221 #include "globals.h"
00222 #include "kernel.h"
00223 #include "kernelwrapper.h"
00224 #include "stringutils.h"
00225 #include "lissom.h"
00226 
00227 
00228 
00229 /******************************************************************************/
00230 /* Defines and typedefs                                                       */
00231 /******************************************************************************/
00232 
00245 #define ACTLIST_START(actlist) 1
00246 #define ACTLIST_COUNT(actlist) ((actlist)[0])
00247 typedef int actlist[NMAX+1];
00248 
00250 #ifndef NO_BINARY
00251 #define BINARY_WEIGHTS_FILE
00252 #endif
00253 
00254 /* 12-09-95 Added by J.A.B. -- Reload from file immediately after save.
00255    Allows ASCII saving in middle of training by replacing the weights
00256    that were destroyed, or can be used for debugging.
00257 */
00258 /* #define RELOAD_AFTER_WEIGHT_SAVE */
00259 
00271 /* #define VERIFY_WEIGHT_SAVES */
00273 #define VERIFY_WEIGHT_SAVES_ERROR_LIMIT 10
00274 
00275 
00276 
00277 /******************************************************************************/
00278 /* Global variables                                                           */
00279 /******************************************************************************/
00280 
00281 
00282 /* Global parameters (values are only examples); see also globals.c */
00283 double alpha_exc=0.002;
00284 double alpha_inh=0.0002;
00285 double alpha_input=0.0007;
00286 double beta=0.7;
00287 double delta=0.1;
00288 int    display=0;
00289 int    dynamics=0;
00290 double exc_death=0;
00291 double inh_death=0.00001;
00292 double lat_exc_randomness=1.0;
00293 double lat_inh_randomness=1.0;
00294 double noise=0.0;
00295 int    preset_aff_wts=True;
00296 double preset_sigma_aff=Uninitialized;
00297 double preset_sigma_lat=Uninitialized;
00298 double preset_sigma_exc=Uninitialized;
00299 double preset_sigma_inh=Uninitialized;
00300 double randomness=0;
00301 int    seed=87654321;
00302 int    smooth_circular_outlines=False;
00303 double smooth_circular_radius_trim=-0.25;
00304 int    tend=MAXITERATION;
00305 int    essential_training_hooks_only=False;
00309 double accumulate_sum[NMAX];            
00310 actlist activity_list[NROWS];           
00311 int    activity_marker[NMAX][NMAX];     
00312 double aff_norm_sum[MAX_NUM_EYES*RNMAX*RNMAX]; 
00313 double afferent_sum[MAX_NUM_EYES*RNMAX*RNMAX]; 
00314 int    exc_connections_killed=False;    
00315 int    inh_connections_killed=False;    
00316 double gather_activity[NMAX][NMAX+1];   
00317 double map_activity[NMAX][NMAX];        
00318 actlist prev_activity_list[NMAX];       
00319 double resp_to_inp[NMAX][NMAX];         
00320 int    RN_sq;                           
00321 double temp_sum[MAX_NUM_EYES*RNMAX*RNMAX];
00324 /* Only allocate wts if actually using them, since the array is generally huge */
00325 #ifndef NO_WEIGHTS
00326 Wts    wts[NROWS][NMAX];                
00327 #endif
00328 
00330 #ifdef VERIFY_WEIGHT_SAVES 
00331 Wts    Orig_wts[NROWS][NMAX];
00332 Neuron Orig_map[NMAX][NMAX];
00333 #endif
00334 
00335 
00336 
00337 /******************************************************************************/
00338 /* Prototypes for private functions                                           */
00339 /******************************************************************************/
00340 
00341 int    binary_search(const int list[], int lower, int upper, int value);
00342 void   clear_weights(void);
00343 void   crop_actlist(const actlist, int lowval, int highval, int *lowidx, int *highidx);
00344 double dist_lat_wt(double value, double amt_of_randomness);
00345 double lat_resp(int ui, int uj, int radius, int array_width, l_weight *weights, int weight_idx_bound);
00346 double lat_resp_rad1(int ui, int uj, int radius, int array_width, int array_width_2, l_weight *weights, int weight_idx_bound);
00347 void   modify_lat_wts(void);
00348 void   modify_latwt_loop(int i, int j, int radius, int array_width, l_weight *weights, int weight_idx_bound, double alpha);
00349 void   modify_latwt_loop_killed(int i, int j, int radius, int array_width, l_weight *weights, int weight_idx_bound, double alpha);
00350 void   modify_latwt_loop_rad1(int ui, int uj, int radius, int array_width, int array_width_2, l_weight *weights, int weight_idx_bound, double alpha);
00351 void   modify_weights(void);
00352 void   normalize_afferent_wts(int lowk, int highk, int lowl, int highl, int row, int j, double length);
00353 void   normalize_lat_wts(int i, int j, int radius, int array_width, l_weight *weights);
00354 double prune_circular_aff_weights(int ui, int uj, int radius, 
00355                                   a_weight weights[MAX_NUM_EYES][WTMAX][WTMAX],
00356                                   double length);
00357 void   prune_circular_lat_weights(int ui, int uj, int radius_sq, int array_width, l_weight *weights);
00358 void   receptor_normalize(void); 
00359 void   reduce_lateral_radius(int ui, int uj, int old_radius, int new_radius, int array_width, l_weight *weights);
00360 void   set_markers(int radius); 
00361 void   setup_lateral_weights(int ui, int uj, int radius,
00362                              int array_width, l_weight *weights,
00363                              int preset, double sigma, double randomness_scale,
00364                              int* con_killed_flag);
00365 double sigmoid(double activity, double sigdelta, double sigbeta);
00366 void   verify_actlist(actlist list);
00367 void   verify_actlist_array(actlist lists[],int num);
00368 void   verify_saved_lateral_weights( int i, int j, int radius, int array_width, l_weight *old_weights, l_weight *new_weights, double tolerance, const char *description);
00369 void   verify_saved_weights( double tolerance );
00370 
00371 CMD_DECLARE(init_network);
00372 CMD_DECLARE(kill_connections);
00373 CMD_DECLARE(step);
00374 CMD_DECLARE(testing);
00375 CMD_DECLARE(training);
00376 CMD_DECLARE(uninit_network);
00377 
00378 
00379 /******************************************************************************/
00380 /* Initialization hook                                                        */
00381 /******************************************************************************/
00382 
00383 void  kernel_init_hook( void )
00384 {
00385   CMD_DOC(kill_connections,"init_network",0, "%s [<inh_death> [<exc_death>]]",
00386           "Prunes lateral connections at or below below the specified levels.\n"
00387           "The levels default to the global values of those parameters.");
00388   
00389   CMD_DOC(init_network,"uninit_network",0,"%s [<skip_weight_init>]",
00390           "Initializes network with the current parameters, suitable for\n"
00391           "beginning training anew.  A command file <filebase>.init.param\n"
00392           "is created with the current values of parameters, suitable for\n"
00393           "recreating the starting state later.  A single cycle of testing\n"
00394           "is done, iterating t to 1, in order to verify that everything is\n"
00395           "working properly.  This command is a prerequisite for most other\n"
00396           "commands, and will be called automatically the first time one of\n"
00397           "those commands is executed.  For debugging and internal purposes,\n"
00398           "a True argument may be supplied to skip the weight initialization.");
00399   
00400   CMD_DOC(step,"init_network",0,"%s [<training_iterations>]",
00401           "Same as training except that it interprets the parameter as a\n"
00402           "value relative to the current iteration (default==1), rather\n"
00403           "than an absolute iteration number, and always displays result (as\n"
00404           "if display==1).  Example: \"step\" just trains for one iteration\n"
00405           "and calls plot_activity.  Typically used at the command prompt for\n"
00406           "debugging or exploration, rather than in a command file.");
00407   
00408   CMD_DOC(testing,"init_network",0,"%s [<stop_iteration>]",
00409           "Same as training except that learning is turned off temporarily.\n"
00410           "The iteration counter is still advanced.");
00411   
00412   CMD_DOC(training,"init_network",0,"%s [<stop_iteration>]",
00413           "Trains the network for the current iteration, then repeats training\n"
00414           "until the iteration counter (t) has reached the <stop_iteration>\n"
00415           "(which defaults to tend).  Sometimes it is appropriate to supply a\n"
00416           "specific iteration (e.g.  `training 1000' trains until iteration 1000);\n"
00417           "other times it's more useful to supply an offset relative to the current\n"
00418           "iteration (e.g. `training t+1000' trains for 1001 iterations more).  After\n"
00419           "training, the global parameter t is one greater than the iteration\n"
00420           "specified.");
00421             
00422   CMD_DOC(uninit_network,NULL,0,"%s",
00423           "Marks network uninitialized so that network architecture parameters\n"
00424           "can be changed.  All weight values and training iteration hook\n"
00425           "definitions will be lost, and the iteration counter will be reset to\n"
00426           "zero.  However, other parameters keep their existing values, which can\n"
00427           "have surprising consequences.  When in doubt, it may be safest to quit\n"
00428           "the program and restart if changing the underlying architecture.");
00429   
00430 
00431   
00432   PARAM_L(PARAM_DOUBLE,alpha_exc,0,
00433           "Learning rate for excitatory lateral connections.");
00434   
00435   PARAM_L(PARAM_DOUBLE,alpha_inh,0,
00436           "Learning rate for inhibitory lateral connections.");
00437   
00438   PARAM_L(PARAM_DOUBLE,alpha_input,0,
00439           "Learning rate for afferent connections.");
00440   
00441   PARAM_N(PARAM_DOUBLE,beta,
00442           "Upper threshold of sigmoid-like activation function.");
00443   
00444   PARAM_N(PARAM_DOUBLE,delta,
00445           "Lower threshold of sigmoid-like activation function.");
00446   
00447   PARAM_L(PARAM_INT,display,0,
00448           "Plot network activation, etc. every (display)th training or testing\n"
00449           "iteration.  If display==0, never do it; if display==1, do it every\n"
00450           "iteration, if display==2, do it every other iteration, etc.");
00451   
00452   PARAM_I(PARAM_INT,   dynamics,0,1,
00453           "Learning dynamics:\n"
00454           "  0 = discrete   (learn after each presentation, i.e. when settling completes),\n"
00455           "  1 = continuous (learn after each settling step.)");
00456   
00457   PARAM_I(PARAM_BOOL,  essential_training_hooks_only,False,True,
00458           "If this is true, inessential hooks such as plotting and analysis will be\n"
00459           "ignored during training and initialization.  (Whether or not a given command\n"
00460           "is ignored depends upon whether it was defined as a `catchup' command or not;\n"
00461           "see cmdparam.c.)  This defaults to true for an interactive session to\n"
00462           "facilitate exploration using a saved batch session; this avoids having too\n"
00463           "many images displayed automatically.");
00464   params_define_default_expr("essential_training_hooks_only","interactive");
00465   
00466   PARAM_L(PARAM_DOUBLE,exc_death,0,
00467           "Maximum value of excitatory lateral connection weights to kill when pruning.");
00468   
00469   PARAM_L(PARAM_DOUBLE,inh_death,0,
00470           "Maximum value of inhibitory lateral connection weights to kill when pruning. ");
00471   
00472   PARAM_L(PARAM_DOUBLE,lat_exc_randomness,0,
00473           "Randomness radius of lateral excitatory connections.");
00474   
00475   PARAM_L(PARAM_DOUBLE,lat_inh_randomness,0,
00476           "Randomness radius of lateral inhibitory connections.");
00477   
00478   PARAM_I(PARAM_DOUBLE,noise,0,1,
00479           "Intrinsic noise factor of the neuron.");
00480   
00481   PARAM_I(PARAM_BOOL,  preset_aff_wts,False,True,
00482           "Whether or not to use preset afferent weights."); 
00483   SETFN_DEFINE(preset_aff_wts,fixed_arch_param_setfn);
00484 
00485   PARAM_L(PARAM_DOUBLE,preset_sigma_aff,0,
00486           "Variance (sigma) of gaussian to preset afferent weights.  It defaults to\n"
00487           "0.9*rf_radius, which makes it nearly fill up the available weight area.");
00488   params_define_default_expr("preset_sigma_aff","0.9*rf_radius");
00489 
00490   PARAM_L(PARAM_DOUBLE,preset_sigma_lat,Uninitialized,
00491           "If this parameter is set, the default values for preset_sigma_exc and\n"
00492           "preset_sigma_inh are calculated from it as follows:\n\n"
00493           
00494           "   preset_sigma_exc = preset_sigma_lat\n"
00495           "   preset_sigma_inh = preset_sigma_lat*MIN(1,sqrt(inh_rad))\n\n"
00496           
00497           "This formula and the preset_sigma_lat parameter are used for backwards\n"
00498           "compatibility with old parameter files.  The normal default values for\n"
00499           "the two parameters listed are probably more appropriate, so it is better\n"
00500           "to avoid setting this parameter.");
00501 
00502   PARAM_L(PARAM_DOUBLE,preset_sigma_exc,Uninitialized,
00503           "Variance (sigma) of gaussian to preset lateral excitatory weights.  Unless\n"
00504           "preset_sigma_lat is set, it defaults to 0.9*exc_rad, which makes it nearly\n"
00505           "fill up the available weight area.");
00506 
00507   PARAM_L(PARAM_DOUBLE,preset_sigma_inh,Uninitialized,
00508           "Variance (sigma) of gaussian to preset lateral inhibitory weights.    Unless\n"
00509           "preset_sigma_lat is set, it defaults to 0.9*inh_rad, which makes it nearly\n"
00510           "fill up the available weight area.");
00511 
00512   PARAM_I(PARAM_DOUBLE,randomness,0,1,
00513           "Amount of randomness of placement of receptive field centers for each neuron:\n"
00514           "0 = no randomness, 1 = offset by RN/2 max.  The code hasn't been verified for\n"
00515           "cases where the randomness is set high enough to have centers chosen more than\n"
00516           "rf_radius units off the retina, and init_weights() will probably need\n"
00517           "modification to handle that case properly.");
00518   
00519   PARAM_N(PARAM_INT,   seed,
00520           "Seed for random number generator used to generate initial weights, etc.  See\n"
00521           "also inputs_seed if applicable.");
00522   SETFN_DEFINE(seed,fixed_arch_param_setfn);
00523   
00524   PARAM_I(PARAM_BOOL,  smooth_circular_outlines,False,True,
00525           "If true, smoothes the edges of circular weights when they are initialized or\n"
00526           "when a radius is reduced by multiplying them by a Gaussian which starts at\n"
00527           "radius+smooth_circular_radius_trim and has a sigma of (circular_radius_trim-\n"
00528           "smooth_circular_radius_trim)/2."); 
00529   SETFN_DEFINE(smooth_circular_outlines,fixed_arch_param_setfn);
00530 
00531   PARAM_N(PARAM_DOUBLE,smooth_circular_radius_trim,
00532           "When smooth_circular_outlines is True, this quantity is added to the\n"
00533           "appropriate radius (rf_radius, inh_rad, or exc_rad) to create a\n"
00534           "floating-point radius at which to start smoothing the outline.  It\n"
00535           "should presumably be smaller than circular_radius_trim, and may be slightly\n"
00536           "negative.");
00537  
00538   PARAM_I(PARAM_INT,   tend,0,MAXITERATION,
00539           "Upper bound for training iterations.  If no command file is specified,\n"
00540           "the last iteration trained will be tend. If a command file is specified,\n"
00541           "the last iteration trained will be the smaller of tend or the last\n"
00542           "training iteration requested in the command file.");
00543 }
00544 
00545 
00546 
00547 
00548 /******************************************************************************/
00549 /* Commands (see CMD_DOC calls for documentation)                             */
00550 /******************************************************************************/
00551 
00553 cmdstat cmd_training( CMD_ARGS )
00554 {
00555   int training_stop=MAXITERATION;
00556   time_t last_msg_time = time(NULL);
00557   
00558   /* Determine stopping iteration */
00559   if (argc>0){
00560     if (argv[0][0] == '+')
00561       training_stop = iteration + cmdi(&(argv[0][1]));
00562     else
00563       training_stop = cmdi(argv[0]);
00564   }
00565   if (training_stop > tend) training_stop = tend;
00566 
00567   if (learning)
00568     ipc_notify(IPC_ONE,IPC_STD,"Training until iteration %d", training_stop);
00569   else if (iteration!=0) /* Zeroth iteration is for housekeeping */
00570     ipc_notify(IPC_ONE,IPC_STD,"Testing until iteration %d", training_stop);
00571 
00572 
00573   /* Main iteration loop */
00574   for(iteration=startt; iteration <= training_stop; iteration++) {
00575     ipc_barrier(); 
00576 
00577     if (PROGRESS_REPORT_NEEDED(last_msg_time)) {
00578       last_msg_time = time(NULL);
00579       ipc_notify(IPC_ONE,IPC_STD,"%s has reached iteration %06d, %.24s",
00580                  (learning ? "Training" : "Testing"),iteration,ctime(&last_msg_time));
00581     }
00582 
00583     /* Run any hooks needed before input is presented. */
00584     hooklists_run_list(before_input,iteration,essential_training_hooks_only);
00585     
00586 #ifndef NO_INPUTS
00587 
00588     inputs->next();
00589 #ifdef PRINT_TIME_PER_ITERATION
00590     clock_t time_before_iteration = clock();
00591 #endif
00592     inputs->activate(learning);
00593     //present_inputs(learning);
00594 #ifdef PRINT_TIME_PER_ITERATION
00595     ipc_log(IPC_ONE,"Iteration %06d took %04d milliseconds",
00596             iteration,(int)((clock()-time_before_iteration)*1000.0/CLOCKS_PER_SEC));
00597 #endif
00598  
00599 #endif
00600     
00601     hooklists_run_list(after_learning,iteration,essential_training_hooks_only);
00602 #ifndef NO_IO
00603     if (display && iteration%display==0)
00604       cmd_plot_activity(0,NULL);
00605 #endif
00606   }
00607   startt = iteration; /* Set the startt to the last iteration. VERY IMPORTANT!! */
00608   iteration--; /* Make the declared iteration be the one last finished */
00609 
00610   return CMD_NO_ERROR;
00611 }
00612 
00613 
00614 
00615 cmdstat cmd_testing( CMD_ARGS )
00616 {
00617   const int orig_learning = learning;
00618   cmdstat status;
00619   
00620   learning = False;
00621   status   = cmd_training(argc,argv);
00622   learning = orig_learning;
00623   
00624   return status;
00625 }
00626 
00627 
00628 
00629 cmdstat cmd_step( CMD_ARGS )
00630 {
00631   const int orig_display = display;  
00632   const int iterations   = ((argc>0)? cmdi(argv[0]) : 1);
00633   char argstring[CMD_MAX_LINE_LENGTH];
00634   const char *args[1];
00635   cmdstat status;
00636 
00637   snprintf(argstring,  CMD_MAX_LINE_LENGTH-1, "%d", iteration+iterations);
00638   args[0]=argstring;
00639   
00640   display=1;
00641   status = cmd_training(1,args);
00642   display=orig_display;
00643   
00644   return status;
00645 }
00646 
00647 
00648 
00649 /******************************************************************************/
00650 /* InputVectorWrapper wrappers                                                */
00651 /******************************************************************************/
00652 
00653 
00654 
00655 InputVectorWrapper::InputVectorWrapper(string name_i, int e)
00656   : InternalNeuralRegion(name_i,RN,RN), eye(e), input(0) { }
00657   
00658 
00659 void InputVectorWrapper::add_input(const string&,const ActivityMatrix& input_region, WeightFunction&, Length size_scale)
00660 {
00661   assert(input==0);                       /* Accepts only one input */
00662   assert(int(input_region.nrows())==RN);  /* Size of input must match existing size */
00663   assert(int(input_region.ncols())==RN);  /* Size of input must match existing size */
00664   (void)size_scale;                       /* Parameter used only with assertions */
00665   assert(size_scale==1.0);
00666   input=&input_region;
00667 }
00668 
00669 
00670 InputVectorWrapper::Dimensions InputVectorWrapper::input_dimensions(WeightFunction&, Length size_scale)
00671 {
00672   (void)size_scale;                       /* Parameter used only with assertions */
00673   assert (size_scale==1.0);
00674   return Dimensions(Subscript(RN),Subscript(RN));
00675 }
00676 
00677 
00678 const InputVectorWrapper::WeightMatrix InputVectorWrapper::get_weights(const string& name, int, int) const
00679 {
00680   /* This region just copies its input to its output, so the weights are trivial */
00681   if (name=="Afferent") {
00682     WeightMatrix w(1,1); w[0][0] = 1;
00683     return w;
00684   }
00685   
00686   return WeightMatrix();
00687 }
00688 
00689 
00690 void InputVectorWrapper::activate(bool, bool)
00691 {
00692   /* Swaps the index order to match that assumed by ppm_draw.c */
00693   assert (input->nrows() == output.nrows() && input->ncols() == output.ncols());
00694   for (Subscript i=0; i<input->nrows(); i++)
00695     for (Subscript j=0; j<input->ncols(); j++)
00696       input_vectors[INP_INDEX(eye,j,i)]=(*input)[i][j];
00697 }
00698 
00699 
00700 
00701 
00702 /******************************************************************************/
00703 /* CortexMapWrapper                                                           */
00704 /******************************************************************************/
00705 
00706 
00707 // Real constructor will need to take height, width
00708 CortexMapWrapper::CortexMapWrapper(string name_i)
00709   : InternalNeuralRegion(name_i,N,N) {  }
00710 
00711 
00712 void CortexMapWrapper::activate(bool learn, bool)
00713 {
00714   present_inputs(learn);
00715   
00716   /* Copy the activity to our local matrix to allow clean plotters to be developed */
00717   /* Swaps the index order to match that assumed by ppm_draw.c */
00718   for (Subscript i=0; i<output.nrows(); i++)
00719     for (Subscript j=0; j<output.ncols(); j++)
00720       output[i][j] = ::prev_map_activity[j][i];
00721   //mat::gnuplot(output, name());
00722 }
00723   
00724 
00725 
00726 void CortexMapWrapper::add_input(const string&,const ActivityMatrix& input_region, WeightFunction&, Length size_scale)
00727 {
00728   assert(int(input_region.nrows())==RN);  /* Size of input must match existing size */
00729   assert(int(input_region.ncols())==RN);  /* Size of input must match existing size */
00730   (void)input_region;                     /* Parameter used only with assertions */
00731   (void)size_scale;                       /* Parameter used only with assertions */
00732   assert(int(size_scale*RN)==N);          /* Scale must match existing scale */
00733 }
00734 
00735 
00736 CortexMapWrapper::Dimensions CortexMapWrapper::input_dimensions(WeightFunction&, Length size_scale)
00737 {
00738   (void)size_scale;                       /* Parameter used only with assertions */
00739   assert (size_scale==1.0);
00740   return Dimensions(Subscript(RN),Subscript(RN));
00741 }
00742 
00743 
00744 const CortexMapWrapper::WeightMatrix CortexMapWrapper::get_weights(const string& name, int ui, int uj) const
00745 {
00746   assert (ROWISLOCAL(ui)); /* Assume the wts are local to this processor */
00747   
00748   /* Select appropriate set of weights to copy */
00749   if (String::non_numeric_basename_matches<string>(name,"Afferent")) {
00750     const string s  = String::numeric_extension<string>(name);
00751     const int eye   = (s == "" ? 0 : String::numeric_extension<int>(name));
00752     
00753     assert (eye<num_eyes);
00754 
00755     const int lowk  = MAX(cortex_map[ui][uj].centerx-rf_radius,0   );
00756     const int highk = MIN(cortex_map[ui][uj].centerx+rf_radius,RN-1);
00757     const int lowl  = MAX(cortex_map[ui][uj].centery-rf_radius,0   );
00758     const int highl = MIN(cortex_map[ui][uj].centery+rf_radius,RN-1);
00759     
00760     WeightMatrix w(highl-lowl+1,highk-lowk+1);
00761     
00762     for (int k=lowk; k <=highk; k++)
00763       for (int l=lowl; l<=highl; l++)
00764         w[l-lowl][k-lowk] = cortex_map[ui][uj].weights[eye][k-lowk][l-lowl];
00765     
00766     return w;
00767   }
00768   else if (name == "LateralExcitatory") {
00769     const int lowi  = MAX(ui-exc_rad,0);
00770     const int highi = MIN(ui+exc_rad,N-1);
00771     const int lowj  = MAX(uj-exc_rad,0);
00772     const int highj = MIN(uj+exc_rad,N-1);
00773     
00774     WeightMatrix w(highj-lowj+1,highi-lowi+1);
00775     
00776     for (int i=lowi; i<=highi; i++)
00777       for (int j=lowj; j<=highj; j++)
00778         w[j-lowj][i-lowi] = cortex_map[ui][uj].lat_exc_wts[LAT_INDEX(ui,uj,i,j,exc_rad,exc_array_width)]; 
00779     
00780     return w;
00781   }
00782   else if (name == "LateralInhibitory") {
00783     const int lowi  = MAX(ui-inh_rad,0);
00784     const int highi = MIN(ui+inh_rad,N-1);
00785     const int lowj  = MAX(uj-inh_rad,0);
00786     const int highj = MIN(uj+inh_rad,N-1);
00787     
00788     WeightMatrix w(highj-lowj+1,highi-lowi+1);
00789     
00790     for (int i=lowi; i<=highi; i++)
00791       for (int j=lowj; j<=highj; j++)
00792         w[j-lowj][i-lowi] = cortex_map[ui][uj].lat_inh_wts[LAT_INDEX(ui,uj,i,j,inh_rad,inh_array_width)];
00793         
00794     return w;
00795   }
00796 
00797   /* Unknown set of weights */
00798   return WeightMatrix();
00799 }
00800 
00801 
00802 
00803 /******************************************************************************/
00804 /* Core routines                                                              */
00805 /******************************************************************************/
00806 
00827 void present_inputs(int learn)
00828 {
00829   int i,pe,j,count;
00830   static int iteration_of_last_presentation=Uninitialized;
00831   
00832   if (iteration!=iteration_of_last_presentation) {
00833     iteration_of_last_presentation=iteration;
00834     presentation=0;
00835   }
00836   else
00837     presentation++;
00838 
00839   settle_responses(learn);        /* Settle activity into bubbles */
00840   
00841   for(pe=0; pe< NPEs; pe++)       /* Collect map_activity from each processor */
00842     for(i=0; i<nrows; i++)
00843       ipc_get_to(prev_map_activity[ARBITRARY_MAPROW(i,pe)],
00844                  map_activity[ARBITRARY_MAPROW(i,pe)],IPC_DOUBLE,N,pe);
00845   
00846   /* gather_activity is indexed from [1..count] like the activity list */
00847   for (i=0; i<N; i++)
00848     if ((count=ACTLIST_COUNT(prev_activity_list[i])) > 0)
00849       for (j=ACTLIST_START(prev_activity_list); j<=count; j++)
00850         gather_activity[i][j]=prev_map_activity[i][prev_activity_list[i][j]];
00851   
00852   /* Optimized not to modify weights if learning rate is zero */
00853   if (learn && dynamics==0){      /* Otherwise, modify at every step */
00854     if (alpha_input!=0)
00855       modify_weights();
00856     if (alpha_exc!=0 || alpha_inh!=0)
00857       modify_lat_wts();
00858   }
00859 
00860   if (presentation>0)
00861     hooklists_run_list(after_presentation,iteration,essential_training_hooks_only);
00862 }
00863 
00864 
00865 
00867 void settle_responses(int learn)
00868 {
00869   int ts;
00870 
00871   response_to_input();
00872   initialize_markers();
00873   initialize_actlists();
00874 
00875   ipc_barrier(); /* To make sure dynamics = 0 init has taken place */
00876 
00877   for(ts=1; ts<=tsettle; ts++){ /* Let network settle into an activity bubble */
00878     compute_responses(ts);  /* Add up input and lateral activations        */
00879     ipc_barrier();          /* To ensure all activations have been computed  */
00880     
00881     if (learn && dynamics==1) { /* If continuous dynamics, modify at each step   */
00882       if (alpha_input!=0)  
00883         modify_weights();
00884       
00885       if (alpha_exc!=0 || alpha_inh!=0){
00886         modify_lat_wts(); 
00887         ipc_barrier();      /* To ensure all wts have been modified */
00888       }
00889     }
00890   }
00891 }
00892 
00893 
00894 
00896 void response_to_input(void)
00897 {
00898   int i,j,k,l,index0,index1=0;
00899   
00900   for(i=0; i<nrows; i++){
00901     const int row = MAPROW(i);                      /* calculate row index  */
00902     for(j=0; j<N; j++)                              /* Init all activations */
00903       { 
00904         const int lowk   = MAX(cortex_map[row][j].centerx-rf_radius,0   );
00905         const int highk  = MIN(cortex_map[row][j].centerx+rf_radius,RN-1);
00906         const int lowl   = MAX(cortex_map[row][j].centery-rf_radius,0   );
00907         const int highl  = MIN(cortex_map[row][j].centery+rf_radius,RN-1);
00908         double resp =0;
00909         double resp1=0;
00910         
00911         /* Blank out previous activity in network if appropriate. */
00912         if (dynamics==0) prev_map_activity[row][j] = map_activity[row][j] =0.0;
00913         
00914         /* This is a time-critical loop; make sure that the compiler unrolls it */
00915         for (k=lowk; k <=highk; k++){
00916           index0 = INP_INDEX(0,k,lowl);
00917           assert (index0 >= INP_INDEX(0,0,0));
00918           assert (index0 <  INP_INDEX(1,0,0));
00919 
00920 #ifndef NUM_EYES_IS_CONSTANT
00921           /* Canonical but slower version of algorithm: */
00922           for (l=lowl; l<=highl; l++,index0++,index1++){
00923             int eye;
00924             for (eye=0; eye<num_eyes; eye++)
00925               resp  += input_vectors[INP_INDEX_OTHER_EYE(eye,index0)] *
00926                 cortex_map[row][j].weights[eye][k-lowk][l-lowl];
00927           }
00928           
00929 
00930 #else /* num_eyes is constant */
00931 #if   (num_eyes>1)
00932           index1 = INP_INDEX_OTHER_EYE(1,index0);
00933           assert (index1 >= INP_INDEX(1,0,0));
00934           assert (index1 <  INP_INDEX(2,0,0));
00935 #endif
00936           /*
00937             This is an extremely time-critical loop, so it has been optimized
00938             by unrolling the inner loop by hand for the typical case of
00939             num_eyes==1 and num_eyes==2.
00940           */
00941           for (l=lowl; l<=highl; l++,index0++,index1++){
00942             resp  += input_vectors[index0] * cortex_map[row][j].weights[0][k-lowk][l-lowl];
00943 #if   (num_eyes>1)
00944             resp1 += input_vectors[index1] * cortex_map[row][j].weights[1][k-lowk][l-lowl];
00945 #endif
00946 #if   (num_eyes>2)
00947             {
00948               int eye;
00949               for (eye=2; eye<num_eyes; eye++)
00950                 resp  += input_vectors[INP_INDEX_OTHER_EYE(eye,index0)] *
00951                   cortex_map[row][j].weights[eye][k-lowk][l-lowl];
00952             }
00953 #endif    
00954           }
00955 #endif /* num_eyes is constant */
00956         }
00957         resp_to_inp[row][j] = resp + resp1;
00958       }
00959   }
00960 }
00961 
00962 
00963 
00965 void compute_responses(int ts)
00966 {
00967   int i,pe,j,row,count; double resp;
00968  
00969   if ((ts==1) && (dynamics==0)){ /* Don't add lateral interaction for first */
00970     for(i=0; i<nrows; i++){  /* Add up input and lateral activations. */
00971       row = MAPROW(i);
00972       for(j=0; j<N; j++)
00973         {
00974           resp = resp_to_inp[row][j];
00975           if (noise > 0.0)   /* If neuron is noisy, add some zero mean noise */
00976             resp += noise * (shuffled_rand()-0.5);
00977           map_activity[row][j] = init_activity[row][j] = sigmoid(resp,delta,beta);
00978           if (map_activity[row][j] > 0.0)         
00979             activity_list[i][++ACTLIST_COUNT(activity_list[i])] = j;
00980         }
00981       assert(ACTLIST_COUNT(activity_list[i]) >= 0); assert(ACTLIST_COUNT(activity_list[i]) <= N);
00982     }
00983     ipc_barrier(); /* a barrier before ipc_put is essential to avoid races */
00984     for(i=0; i<nrows; i++){  /* Store all the activity lists */
00985       row = MAPROW(i);
00986       for (pe=0; pe < NPEs; pe++)    /* Store activity list to all processors */
00987         ipc_put_to(&(prev_activity_list[row][0]), &(activity_list[i][0]),
00988                    IPC_INT,ACTLIST_COUNT(activity_list[i])+1,pe);
00989       ACTLIST_COUNT(activity_list[i]) = 0;
00990     }
00991     return;
00992   }
00993   /*============================= OTHERWISE ============================= */
00994   /* Copy the the activity from the previous settling iteration.
00995    * This is used to compute the responses in the next iteration.
00996    */
00997   for(pe=0; pe< NPEs; pe++)          /* From each processor     */
00998     for (i=0; i<nrows; i++){          /* Fetch each row to my PE */
00999       row = ARBITRARY_MAPROW(i,pe);
01000       ipc_get_to(prev_map_activity[row],map_activity[row],IPC_DOUBLE,N,pe);
01001     }
01002 
01003   /* Set markers after two (heuristic) iterations are complete */
01004   if (ts==3){
01005     if (exc_rad > 1) set_markers(exc_rad);
01006     else set_markers(2);
01007   }
01008   /* Gather the activity from each row to the gather_activity array. This
01009    * increases cache_locality and helps increase performance in the unrolled 
01010    * loop. gather_activity is indexed from [1..count] like the activity list *
01011    */
01012   for (i=0; i<N; i++)
01013     if ((count=ACTLIST_COUNT(prev_activity_list[i])) > 0)
01014       for (j=ACTLIST_START(prev_activity_list); j<=count; j++)
01015         gather_activity[i][j]=prev_map_activity[i][prev_activity_list[i][j]];
01016 
01017   for(i=0; i<nrows; i++){  /* Add up input and lateral activations. */
01018     row = MAPROW(i);
01019     for(j=0; j<N; j++){
01020       
01021       if (activity_marker[row][j]){ /* Activity exists in neighborhood*/
01022         resp = resp_to_inp[row][j];
01023     
01024         if (noise > 0.0)   /* If neuron is noisy, add some zero mean noise */
01025           resp += noise * (shuffled_rand()-0.5);
01026 
01027         if (exc_rad <= 1)/*   Use optimized version of the lat_resp function*/
01028           resp += gammaexc * lat_resp_rad1(row, j, exc_rad, exc_array_width, exc_array_width_2,
01029                                            cortex_map[row][j].lat_exc_wts, lat_exc_dimension);
01030 
01031         else
01032           resp += gammaexc * lat_resp(row, j, exc_rad, exc_array_width, 
01033                                       cortex_map[row][j].lat_exc_wts, lat_exc_dimension);
01034     
01035         /* Add inhibition only if activity is already greater than zero */
01036         if ( sigmoid(resp, delta, beta) >0.0 )
01037           map_activity[row][j] = sigmoid((resp-gammainh*lat_resp(row,j,inh_rad,
01038                                      inh_array_width,cortex_map[row][j].lat_inh_wts, lat_inh_dimension)),
01039                                          delta, beta);
01040         if (map_activity[row][j] > 0.0)   
01041           activity_list[i][++ACTLIST_COUNT(activity_list[i])] = j;
01042         
01043       }
01044       else map_activity[row][j]=0.0;
01045     }
01046   }
01047 
01048   ipc_barrier(); /* a barrier before ipc_put is essential to avoid races */
01049   for(i=0; i<nrows; i++){  /* Store all the activity lists */
01050     row = MAPROW(i);
01051     for (pe=0; pe < NPEs; pe++)   /* Store activity list to all processors */
01052       ipc_put_to(&(prev_activity_list[row][0]), &(activity_list[i][0]),
01053                  IPC_INT,ACTLIST_COUNT(activity_list[i])+1,pe);
01054     ACTLIST_COUNT(activity_list[i]) = 0;
01055   }
01056 }
01057 
01058 
01059 
01065 int binary_search(const int list[], int lower, int upper, int value)
01066 {
01067   /* Don't bother to search if entirely outside the range */
01068   if (value <= list[lower]) return lower;    /* value lower than entire range */
01069   if (value >  list[upper]) return upper+1;  /* value higher than entire range */
01070 
01071   /* Binary search within range */
01072   while(lower < upper) {
01073     const int middle = (lower+upper) >> 1;  /* same as divide by 2 */
01074     const int compare_to = list[middle];
01075     if      (value > compare_to) lower = middle + 1;
01076     else if (value < compare_to) upper = middle;
01077     else return(middle);   /* value has been found at index middle */
01078   }
01079   return(lower); /* value not found, but is in range */
01080 }
01081 
01082 
01083 
01090 void crop_actlist(const actlist list, int lowval, int highval, int *lowidx, int *highidx)
01091 {
01092   (*lowidx )=ACTLIST_START(list);
01093   (*highidx)=ACTLIST_COUNT(list);
01094   
01095   if (lowval == 0)
01096     (*lowidx) = 1;
01097   else
01098     (*lowidx) = binary_search(list,(*lowidx),(*highidx),lowval);
01099 
01100   if (highval==(N-1))
01101     (*highidx) = ACTLIST_COUNT(list); 
01102   else {
01103     (*highidx) = binary_search(list,(*lowidx),(*highidx),highval);
01104 
01105     if ((*highidx) > ACTLIST_COUNT(list) || (list[(*highidx)]> highval))
01106       (*highidx)--;
01107   }
01108 }
01109 
01110 
01111 
01116 /*
01117 void crop_actlist_orig(const actlist list, int lowval, int highval, int *lowidx, int *highidx)
01118 {
01119   (*lowidx )=ACTLIST_START(list);
01120   (*highidx)=ACTLIST_COUNT(list);
01121 
01122   while ((*highidx) >= (*lowidx)  &&  list[(*lowidx )] < lowval ) (*lowidx )++;
01123   while ((*highidx) >= (*lowidx)  &&  list[(*highidx)] > highval) (*highidx)--;
01124 } 
01125 */
01126 
01127 
01128 
01130 void verify_actlist(actlist list)
01131 {
01132   int i;
01133   int count=ACTLIST_COUNT(list);
01134 
01135   if (count <0 || count > NMAX) {
01136     ipc_notify(IPC_ALL,IPC_ERROR,"List has invalid count (%d)",count);
01137     return;
01138   }
01139   for (i=ACTLIST_START(list); i<count; i++)
01140     if (list[i]>= list[i+1]) {
01141       ipc_notify(IPC_ALL,IPC_ERROR,"List is not in proper order -- for %d elements, list[%d]=%d > list[%d]=%d",
01142                 count,i,list[i],i+1,list[i+1]);
01143       return;
01144     }
01145   return;
01146 }
01147 
01148 
01150 void verify_actlist_array(actlist lists[],int num)
01151 {
01152   int i;
01153   for (i=0; i<num; i++)
01154     verify_actlist(lists[i]);
01155 }
01156 
01157 
01158 
01160 void initialize_actlists( void )
01161 {
01162   int i;
01163   for(i=0; i<nrows; i++) {
01164     ACTLIST_COUNT(prev_activity_list[MAPROW(i)]) = 0;
01165     ACTLIST_COUNT(activity_list[i]) = 0;
01166   }
01167 }
01168 
01169 
01170 
01173 void initialize_markers( void )
01174 {
01175   int i,j;
01176 
01177   for(i=0; i<nrows; i++){
01178     const int row = MAPROW(i);
01179     for(j=0; j<N; j++)  
01180       activity_marker[row][j] = True;
01181   }
01182 }
01183 
01184 
01185 
01191 void set_markers(int radius)
01192 {
01193   int i,j,k,l;
01194 
01195   for(i=0; i<nrows; i++){
01196     const int row   = MAPROW(i);                      
01197     const int lowk  = MAX(row-radius,0);
01198     const int highk = MIN(row+radius,N-1);
01199 
01200     for(j=0; j<N; j++){
01201       const int lowl  = MAX(j-radius,0);
01202       const int highl = MIN(j+radius,N-1);
01203       double marker_resp = 0.0;
01204 
01205       for(k=lowk; k<= highk; k++)
01206         for(l=lowl; l<=highl; l++)
01207           marker_resp += prev_map_activity[k][l];
01208       
01209       if (marker_resp > ALIVE_MINIMUM) activity_marker[row][j] = True;
01210       else activity_marker[row][j] = False;
01211     }
01212   }
01213 }
01214 
01215 
01216 
01221 double lat_resp(int ui, int uj, int radius, int array_width, l_weight *weights, int weight_idx_bound)
01222 {
01223   int i, j;
01224   double resp=0;
01225   
01226   const int lowi  = MAX(ui-radius,0); 
01227   const int highi = MIN(ui+radius,N-1);
01228   
01229   (void)weight_idx_bound; /* Parameter used only with assertions */
01230   
01231   for(i=lowi; i<=highi; i++)
01232     if (ACTLIST_COUNT(prev_activity_list[i]) > 0){
01233         const int lowj  = MAX(uj-radius,0); 
01234         const int highj = MIN(uj+radius,N-1); 
01235         const int partial_idx = PARTIAL_LAT_INDEX(ui,uj,i,radius,array_width); 
01236         int high_idx, low_idx;
01237         
01238         crop_actlist(prev_activity_list[i],lowj,highj,&low_idx,&high_idx);
01239         assert (high_idx <= ACTLIST_COUNT(prev_activity_list[i]));
01240  
01241         /* This is a time-critical loop; make sure that the compiler unrolls it */
01242         for(j=low_idx; j <= high_idx; j++){
01243           const int idx = FULL_LAT_INDEX(partial_idx,prev_activity_list[i][j]);
01244           assert (prev_activity_list[i][j] >= lowj);
01245           assert (prev_activity_list[i][j] <= highj);
01246           assert (idx >= 0); assert (idx <= weight_idx_bound);
01247           
01248           resp += gather_activity[i][j] * weights[idx];
01249         }
01250     }
01251   return(resp);
01252 }
01253 
01254 
01255 
01257 double lat_resp_rad1(int ui, int uj, int radius, int array_width, int array_width_2, l_weight *weights, int weight_idx_bound)
01258 {
01259   double resp, resp1, resp2;
01260 
01261   /* This parameter is for error checking and consistency with
01262      modify_latwt_loop; it is currently unused */
01263   (void)weight_idx_bound;
01264   
01265   if (radius==0){
01266     resp = prev_map_activity[ui][uj]; /* Weights are 1.0 */
01267     return(resp);
01268   }
01269   resp = resp1 = resp2=0.0;
01270   if ((ui > 0) && (ui < N-1))    /* Case where 'ui' is away from border      */
01271     {
01272       if ((uj >0) && (uj < N-1)) /* Case where 'uj' is also away from border */
01273         {
01274           /* FULL_LAT_INDEX need not be called when either argument is 0 */
01275           resp   = prev_map_activity[ui-1][uj-1] * weights[                             0 ];
01276           resp1  = prev_map_activity[ui-1][uj  ] * weights[                             1 ];
01277           resp2  = prev_map_activity[ui-1][uj+1] * weights[                             2 ];
01278 
01279           resp  += prev_map_activity[ui  ][uj-1] * weights[               array_width     ];
01280           resp1 += prev_map_activity[ui  ][uj  ] * weights[FULL_LAT_INDEX(array_width,  1)];
01281           resp2 += prev_map_activity[ui  ][uj+1] * weights[FULL_LAT_INDEX(array_width,  2)];
01282 
01283           resp  += prev_map_activity[ui+1][uj-1] * weights[               array_width_2   ];
01284           resp1 += prev_map_activity[ui+1][uj  ] * weights[FULL_LAT_INDEX(array_width_2,1)];
01285           resp2 += prev_map_activity[ui+1][uj+1] * weights[FULL_LAT_INDEX(array_width_2,2)];
01286         }
01287       else{                     /*  'uj' is at some border */
01288         const int lowj  = MAX(uj-1,0);
01289         const int highj = MIN(uj+1,N-1);
01290         const int partial_index0 =               - uj + 1;
01291         const int partial_index1 = array_width   - uj + 1; 
01292         const int partial_index2 = array_width_2 - uj + 1;
01293         int j;
01294         
01295         for(j=lowj; j<=highj; j++){
01296           resp  += prev_map_activity[ui-1][j] * weights[FULL_LAT_INDEX(partial_index0,j)];
01297           resp1 += prev_map_activity[ui  ][j] * weights[FULL_LAT_INDEX(partial_index1,j)];
01298           resp2 += prev_map_activity[ui+1][j] * weights[FULL_LAT_INDEX(partial_index2,j)];
01299         }
01300       }
01301       resp += resp1 + resp2;
01302     }
01303   else if (ui > 0){            /* Case where 'ui' is at top border (N-1)     */
01304     const int lowj  = MAX(uj-1,0);
01305     const int highj = MIN(uj+1,N-1);
01306     const int partial_index0 = -uj + 1;
01307     const int partial_index1 = array_width - uj + 1;
01308     int j;
01309       
01310     for(j=lowj; j<=highj; j++){
01311       resp += prev_map_activity[ui-1][j] * weights[FULL_LAT_INDEX(partial_index0,j)];
01312       resp1+= prev_map_activity[ui  ][j] * weights[FULL_LAT_INDEX(partial_index1,j)];
01313     }
01314     resp += resp1;
01315   }
01316   else{                        /* Case where 'ui' is at bottom border (0)    */
01317     const int lowj  = MAX(uj-1,0);
01318     const int highj = MIN(uj+1,N-1);
01319     const int partial_index0 = array_width   - uj + 1;
01320     const int partial_index1 = array_width_2 - uj + 1;
01321     int j;
01322       
01323     for(j=lowj; j<=highj; j++){
01324       resp += prev_map_activity[ui  ][j] * weights[FULL_LAT_INDEX(partial_index0,j)];
01325       resp1+= prev_map_activity[ui+1][j] * weights[FULL_LAT_INDEX(partial_index1,j)];
01326     }
01327     resp += resp1;
01328   }
01329   return(resp);
01330 }
01331 
01332 
01333 
01338 void modify_weights(void) 
01339 {                         
01340   int i,j,k,l,eye;
01341   
01342   if (normalize_aff)    /* If afferents from each receptor are normalized */
01343     for(i=0; i<RN; i++)
01344       for(j=0; j<RN; j++)
01345         for (eye=0; eye<num_eyes; eye++)
01346           afferent_sum[INP_INDEX(eye,i,j)] = 0.0;
01347   
01348   for(i=0; i<nrows; i++){
01349     const int row = MAPROW(i);
01350     
01351     for(j=0; j<N; j++)    /* Only wts of active neurons need to be modified */
01352       if (normalize_aff || (prev_map_activity[row][j] > 0.0)){
01353         
01354         /* The weights must be modified only within the receptive field. */
01355         const int lowk   = MAX(cortex_map[row][j].centerx-rf_radius,0   );
01356         const int highk  = MIN(cortex_map[row][j].centerx+rf_radius,RN-1);
01357         const int lowl   = MAX(cortex_map[row][j].centery-rf_radius,0   );
01358         const int highl  = MIN(cortex_map[row][j].centery+rf_radius,RN-1);
01359         
01360         if (prev_map_activity[row][j] > 0.0){
01361           
01362           double deltaw = alpha_input * prev_map_activity[row][j]; 
01363           double length = 0.0;
01364 
01365           for (eye=0; eye<num_eyes; eye++)        
01366             for (k=lowk; k<=highk; k++){
01367               int idx = INP_INDEX(eye,k,lowl);
01368               assert (idx >= INP_INDEX(eye,0,0)); 
01369               
01370               for (l=lowl; l<=highl; l++,idx++) {
01371                 a_weight* const wtptr = &(cortex_map[row][j].weights[eye][k-lowk][l-lowl]);
01372                 assert (idx < INP_INDEX(eye+1,0,0));
01373 
01374                 if (*wtptr > -DEATH_FLAG) {
01375                   const double load = input_vectors[idx];
01376                   
01377                   if ( load > 0.0){
01378                     const double delt = load * deltaw;
01379                     *wtptr += delt;
01380                     length += delt;
01381                   }
01382                 }
01383               }
01384             }
01385           
01386           if (! normalize_aff) /* Do only if receptor_normalize is not called */
01387             normalize_afferent_wts(lowk,highk,lowl,highl,row,j,1.0/(1.0+length));
01388         }
01389         
01390         if (normalize_aff) /* Do this whether map activity is >0 or not */
01391           for (k=lowk; k<=highk; k++)
01392             for (l=lowl; l<=highl; l++)
01393               for (eye=0; eye<num_eyes; eye++) {
01394                 assert (INP_INDEX(eye,k,l) >= INP_INDEX(eye,  0,0));
01395                 assert (INP_INDEX(eye,k,l) <  INP_INDEX(eye+1,0,0));
01396                 
01397                 afferent_sum[INP_INDEX(eye,k,l)] += cortex_map[row][j].weights[eye][k-lowk][l-lowl];
01398               }
01399       }
01400   }
01401   
01402   if (normalize_aff) receptor_normalize();
01403 }
01404 
01405 
01406 
01408 void receptor_normalize(void)
01409 {
01410   double result;
01411   int i,j,k,l,pe,eye;
01412 
01413   for(k=0; k<RN; k++)  /* Store local data in temp array */
01414     for(l=0; l<RN; l++)
01415       for (eye=0; eye<num_eyes; eye++)
01416         temp_sum[INP_INDEX(eye,k,l)] = afferent_sum[INP_INDEX(eye,k,l)];
01417 
01418   ipc_barrier();
01419 
01420   for(pe=0; pe<NPEs; pe++)
01421     if (!PEISME(pe)){
01422       ipc_get_to(aff_norm_sum, afferent_sum, IPC_DOUBLE,num_eyes*RN*RN,pe);
01423       
01424       for(k=0; k<RN; k++)
01425         for(l=0; l<RN; l++)
01426           for (eye=0; eye<num_eyes; eye++)
01427             temp_sum[INP_INDEX(eye,k,l)] += aff_norm_sum[INP_INDEX(eye,k,l)];
01428     }
01429   
01430   ipc_barrier(); /* To ensure that afferent_sum is not changed before fetched */
01431 
01432   for(k=0; k<RN; k++)
01433     for (l=0; l<RN; l++)
01434       for (eye=0; eye<num_eyes; eye++)
01435         afferent_sum[INP_INDEX(eye,k,l)] = 1.0/temp_sum[INP_INDEX(eye,k,l)];
01436   
01437   for(i=0; i<nrows; i++){
01438     const int row = MAPROW(i);
01439     for(j=0; j<N; j++){
01440       const int lowk   = MAX(cortex_map[row][j].centerx-rf_radius,0   );
01441       const int highk  = MIN(cortex_map[row][j].centerx+rf_radius,RN-1);
01442       const int lowl   = MAX(cortex_map[row][j].centery-rf_radius,0   );
01443       const int highl  = MIN(cortex_map[row][j].centery+rf_radius,RN-1);
01444       double length = 0.0;
01445 
01446       /* This is a time-critical loop; make sure that the compiler unrolls it */
01447       for (k=lowk; k<=highk; k++)
01448         for (l=lowl; l<=highl; l++)
01449           for (eye=0; eye<num_eyes; eye++){
01450             a_weight* const wtptr = &(cortex_map[row][j].weights[eye][k-lowk][l-lowl]);
01451             assert (INP_INDEX(eye,k,l) >= INP_INDEX(eye,  0,0));
01452             assert (INP_INDEX(eye,k,l) <  INP_INDEX(eye+1,0,0));
01453             
01454             result  = (*wtptr) * afferent_sum[INP_INDEX(eye,k,l)];
01455             length += result;
01456             
01457             *wtptr = result;
01458           }
01459       
01460       normalize_afferent_wts(lowk,highk,lowl,highl,row,j,1.0/length);
01461     }
01462   }
01463 }
01464 
01465 
01466 
01467 void normalize_afferent_wts(int lowk, int highk, int lowl, int highl, int row, int j, double length)
01468 {
01469   int k,l,eye;
01470 
01471   /* This is a time-critical loop; make sure that the compiler unrolls it */
01472   for (k=lowk; k<=highk; k++)
01473     for (l=lowl; l<=highl; l++)
01474       for (eye=0; eye<num_eyes; eye++) {
01475         a_weight* const wtptr = &(cortex_map[row][j].weights[eye][k-lowk][l-lowl]);
01476         if (*wtptr > -DEATH_FLAG)
01477           *wtptr *= length;
01478       }
01479 }
01480 
01481 
01482 
01488 void modify_lat_wts(void)
01489 {
01490   int i,j;
01491 
01492   for(i=0; i<nrows; i++){
01493     const int row = MAPROW(i);
01494 
01495     for(j=0; j<N; j++)     /* Modify only neurons with nonzero activity */
01496       if (prev_map_activity[row][j] > 0.0){
01497         
01498         if (exc_rad==1 && !exc_connections_killed)
01499           modify_latwt_loop_rad1(row,j,exc_rad, exc_array_width, exc_array_width_2,
01500                                  cortex_map[row][j].lat_exc_wts, lat_exc_dimension, alpha_exc);
01501         else 
01502           modify_latwt_loop(     row,j, exc_rad, exc_array_width,
01503                                  cortex_map[row][j].lat_exc_wts, lat_exc_dimension, alpha_exc);
01504         
01505         modify_latwt_loop(       row,j, inh_rad, inh_array_width,
01506                                  cortex_map[row][j].lat_inh_wts, lat_inh_dimension, alpha_inh);
01507       }
01508   }
01509 }
01510 
01511 
01512 
01514 void modify_latwt_loop(int i, int j, int radius, int array_width, l_weight *weights, int weight_idx_bound, double alpha)
01515 {
01516   int k,m;
01517   const int lowk  = MAX(i-radius,0  );
01518   const int highk = MIN(i+radius,N-1);
01519   const int lowl  = MAX(j-radius,0  );
01520   const int highl = MIN(j+radius,N-1);
01521   const double loop_const=alpha * prev_map_activity[i][j];
01522   double new_length=0;
01523 
01524   (void)weight_idx_bound; /* Parameter used only with assertions */
01525 
01526   for (k=lowk; k<=highk; k++)
01527     if ( ACTLIST_COUNT(prev_activity_list[k]) > 0) {
01528       const int partial_idx = PARTIAL_LAT_INDEX(i,j,k,radius,array_width);
01529       int low_idx, high_idx;
01530       crop_actlist(prev_activity_list[k],lowl,highl,&low_idx,&high_idx);
01531 
01532       /* This is a time-critical loop; make sure that the compiler unrolls it */
01533       for (m=low_idx; m <= high_idx; m++) {
01534         const int l   = prev_activity_list[k][m];
01535         const int idx = FULL_LAT_INDEX(partial_idx,l);
01536         assert (l >= lowl); assert (l <= highl);
01537         assert (idx >= 0);  assert (idx <= weight_idx_bound);
01538 
01539         if ( (weights[idx]) > -DEATH_FLAG){
01540           const double delt = gather_activity[k][m] * loop_const;
01541           new_length   += delt;
01542           weights[idx] += delt;
01543         }
01544       }
01545     }
01546   new_length = 1.0/(1.0+new_length);
01547 
01548   for (k=lowk; k<=highk; k++) {
01549     int idx = LAT_INDEX(i,j,k,lowl,radius,array_width);
01550     int l;
01551     assert (idx >= 0);
01552 
01553     /* This is a time-critical loop; make sure that the compiler unrolls it */
01554     for (l=lowl; l<=highl; l++,idx++) {
01555       assert (idx <= weight_idx_bound);
01556       if (weights[idx] > -DEATH_FLAG)
01557         weights[idx] *= new_length;
01558     }
01559   }
01560 }
01561 
01562 
01563 
01567 void modify_latwt_loop_rad1(int ui, int uj, int radius, int array_width, int array_width_2, l_weight *weights, int weight_idx_bound, double alpha)
01568 {
01569   int j;
01570   double length=0;
01571   double delta0=0;
01572   double delta1=0;
01573   double delta2=0;
01574   double delta3=0;
01575   const double loop_constant = alpha * prev_map_activity[ui][uj];
01576   
01577   /* These parameters are for error checking and consistency with
01578      modify_latwt_loop; they are currently unused */
01579   (void)radius;
01580   (void)weight_idx_bound;
01581   
01582   if ((ui > 0) && (ui < N-1))    /* Case where 'ui' is away from border      */
01583     {
01584       if ((uj >0) && (uj < N-1)) /* Case where 'uj' is also away from border */
01585         {
01586           /* FULL_LAT_INDEX need not be called when either argument is 0 */
01587           delta0 = prev_map_activity[ui-1][uj-1] * loop_constant; weights[                           0   ] += delta0; 
01588           delta1 = prev_map_activity[ui-1][uj  ] * loop_constant; weights[                           1   ] += delta1;
01589           delta2 = prev_map_activity[ui-1][uj+1] * loop_constant; weights[                           2   ] += delta2;
01590           length = delta0 + delta1 + delta2;
01591 
01592           delta3 = prev_map_activity[ui  ][uj-1] * loop_constant; weights[               array_width     ]+= delta3; 
01593           delta0 = prev_map_activity[ui  ][uj  ] * loop_constant; weights[FULL_LAT_INDEX(array_width,1)  ]+= delta0; 
01594           delta1 = prev_map_activity[ui  ][uj+1] * loop_constant; weights[FULL_LAT_INDEX(array_width,2)  ]+= delta1;
01595           length += delta3 + delta0 + delta1;
01596 
01597           delta2 = prev_map_activity[ui+1][uj-1] * loop_constant; weights[               array_width_2   ]+= delta2;
01598           delta3 = prev_map_activity[ui+1][uj  ] * loop_constant; weights[FULL_LAT_INDEX(array_width_2,1)]+= delta3;
01599           delta0 = prev_map_activity[ui+1][uj+1] * loop_constant; weights[FULL_LAT_INDEX(array_width_2,2)]+= delta0;
01600           length = 1.0/(1.0+length + delta2 + delta3 + delta0);
01601 
01602           for(j=0; j<3; j++){
01603             weights[                             j ] *= length;
01604             weights[FULL_LAT_INDEX(array_width  ,j)] *= length;
01605             weights[FULL_LAT_INDEX(array_width_2,j)] *= length;
01606           }
01607         }
01608       else{                     /*  'uj' is at some border */
01609         const int lowj  = MAX(uj-1,0); 
01610         const int highj = MIN(uj+1,N-1);
01611         const int index0 =               -uj+1;
01612         const int index1 = array_width   -uj+1; 
01613         const int index2 = array_width_2 -uj+1;
01614 
01615         for(j=lowj; j<=highj; j++){
01616           delta0 = prev_map_activity[ui-1][j] * loop_constant; weights[FULL_LAT_INDEX(index0,j)] += delta0; 
01617           delta1 = prev_map_activity[ui  ][j] * loop_constant; weights[FULL_LAT_INDEX(index1,j)] += delta1; 
01618           delta2 = prev_map_activity[ui+1][j] * loop_constant; weights[FULL_LAT_INDEX(index2,j)] += delta2; 
01619           length += delta0 + delta1 + delta2; 
01620         }
01621         length = 1.0/(1.0+length);
01622         for(j=lowj; j<=highj; j++){
01623           weights[FULL_LAT_INDEX(index0,j)] *= length;
01624           weights[FULL_LAT_INDEX(index1,j)] *= length;
01625           weights[FULL_LAT_INDEX(index2,j)] *= length;
01626         }
01627       }
01628     }
01629   else if (ui > 0){            /* Case where 'ui' is at top border (N-1)     */
01630     const int lowj  = MAX(uj-1,0); 
01631     const int highj = MIN(uj+1,N-1);
01632     const int index0 = -uj + 1;
01633     const int index1 = array_width - uj + 1;
01634 
01635     for(j=lowj; j<=highj; j++){
01636       delta0 = prev_map_activity[ui-1][j] * loop_constant; weights[FULL_LAT_INDEX(index0,j)] += delta0; length += delta0; 
01637       delta1 = prev_map_activity[ui  ][j] * loop_constant; weights[FULL_LAT_INDEX(index1,j)] += delta1; length += delta1;
01638     }
01639     length = 1.0/(1.0+length);
01640     for(j=lowj; j<=highj; j++){
01641       weights[FULL_LAT_INDEX(index0,j)] *= length;
01642       weights[FULL_LAT_INDEX(index1,j)] *= length;
01643     }
01644   }
01645   else{                        /* Case where 'ui' is at bottom border (0)    */
01646     const int lowj  = MAX(uj-1,0); 
01647     const int highj = MIN(uj+1,N-1);
01648     const int index1 = array_width   -uj+1;
01649     const int index2 = array_width_2 -uj+1;
01650 
01651     for(j=lowj; j<=highj; j++){
01652       delta0 = prev_map_activity[ui  ][j] * loop_constant; weights[FULL_LAT_INDEX(index1,j)] += delta0; length += delta0;
01653       delta1+= prev_map_activity[ui+1][j] * loop_constant; weights[FULL_LAT_INDEX(index2,j)] += delta1; length += delta1;
01654     }
01655     length = 1.0/(1.0+length);
01656     for(j=lowj; j<=highj; j++){
01657       weights[FULL_LAT_INDEX(index1,j)] *= length;
01658       weights[FULL_LAT_INDEX(index2,j)] *= length;
01659     }
01660   }  
01661 }
01662 
01663 
01664 
01669 void normalize_lat_wts(int i, int j, int radius, int array_width, l_weight *weights)
01670 {
01671   int k,l;
01672   const int lowk   = MAX(i-radius,0  );
01673   const int highk  = MIN(i+radius,N-1);
01674   const int lowl   = MAX(j-radius,0  );
01675   const int highl  = MIN(j+radius,N-1);
01676   double length = 0;
01677 
01678   for(k=lowk; k<= highk; k++){
01679     int idx = LAT_INDEX(i,j,k,lowl,radius,array_width);    
01680     assert (idx >= 0);
01681     
01682     /* This is a time-critical loop; make sure that the compiler unrolls it */
01683     for (l=lowl; l <=highl; l++,idx++) {
01684       /* assert (idx <= weight_idx_bound); */
01685       length += weights[idx];
01686     }
01687   }
01688   length = 1.0/length;
01689   
01690   for(k=lowk; k<= highk; k++){
01691     int idx = LAT_INDEX(i,j,k,lowl,radius,array_width);    
01692     assert (idx >= 0);
01693     
01694     /* This is a time-critical loop; make sure that the compiler unrolls it */
01695     for (l=lowl; l <=highl; l++,idx++){
01696       /* assert (idx <= weight_idx_bound); */
01697       weights[idx] *= length;
01698     }
01699   }
01700 }
01701 
01702 
01703 
01708 double sigmoid(double activity, double sigdelta, double sigbeta) /* Linear approx of sigmoid */
01709                                       /* Lower & upper thresholds */    
01710 {
01711 #ifdef DEBUG_SIGMOID
01712   ipc_notify(IPC_ALL,IPC_VERBOSE,"activity=%.6f; sigdelta=%.6f, sigbeta=%.6f",
01713              (double)activity,(double)sigdelta,(double)sigbeta);
01714 #endif
01715   if      (activity < sigdelta) return(0.0);
01716   else if (activity > sigbeta)  return(1.0);
01717   else return( (activity-sigdelta)/(sigbeta-sigdelta) );
01718 }
01719 
01720 
01721 
01722 /******************************************************************************/
01723 /* Other routines                                                             */
01724 /******************************************************************************/
01725 
01727 double network_size_megabytes( void )
01728 {
01729   int memsize = (N*N * ( (2*rf_radius +1)*(2*rf_radius +1)*sizeof(a_weight)*num_eyes +
01730                          (2*exc_rad   +1)*(2*exc_rad   +1)*sizeof(l_weight) +
01731                          (2*inh_rad   +1)*(2*inh_rad   +1)*sizeof(l_weight) ))/NPEs;
01732   
01733   return memsize/1024.0/1024.0;
01734 }
01735 
01736 
01738 int network_size_connections( void )
01739 {
01740   return        N*N * ( (2*rf_radius +1)*(2*rf_radius +1)*num_eyes +
01741                         (2*exc_rad   +1)*(2*exc_rad   +1) +
01742                         (2*inh_rad   +1)*(2*inh_rad   +1) );
01743 }
01744 
01745 
01746 
01747 cmdstat cmd_init_network( CMD_ARGS )
01748 {
01749   const int skip_weight_init = (argc>0 ? cmdi(argv[0]) : False);
01750   int i,j;
01751   
01752   /* Reset master defaults for parameters and variables */
01753   exc_connections_killed = False;
01754   inh_connections_killed = False;
01755   startt=0; 
01756   iteration=0;
01757   nrows=N/NPEs;
01758 
01759   /* Quietly generate default values for unset parameters */
01760   {
01761     int oldval=cmdparam_changes_verbose;
01762     cmdparam_changes_verbose=False;
01763     params_update_all_default_values();
01764     cmdparam_changes_verbose=oldval;
01765   }
01766   
01767   /* Check parameters against compilation limits, etc. */
01768   if (params_check_all() != 0) {
01769     if (interactive) {
01770       ipc_notify(IPC_ONE,IPC_WARNING, "init_network failed due to parameter problem; fix message(s) above and try again");
01771       return CMD_PARAMETER_ERROR;
01772     }
01773     else
01774       ipc_exit(IPC_EXIT_PARAM_VALUE_ERROR, "Parameter problem (see message(s) above)");
01775   }
01776 
01777   ipc_notify(IPC_ONE,IPC_STD,
01778              "Initializing %d-connection (%dMB%s) network (see %s.init.param for parameters)",
01779              network_size_connections(),(int)network_size_megabytes()+1,
01780              (NPEs>1 ? "/PE" : ""),filebase);
01781   
01782   /* Initialize activity in the map */
01783   for(i=0; i< N; i++)   
01784     for(j=0; j< N; j++)         
01785         prev_map_activity[i][j]=map_activity[i][j]=0.0;
01786 
01787   /* The array widths set below don't change even if exc_radius is decreased. */
01788   rf_radius_sq      = (rf_radius+circular_radius_trim)*(rf_radius+circular_radius_trim);
01789   exc_array_width   = 2*exc_rad + 1;
01790   exc_array_width_2 = 2*exc_array_width;
01791   lat_exc_dimension = exc_array_width * exc_array_width;
01792   inh_array_width   = 2*inh_rad + 1;
01793   lat_inh_dimension = inh_array_width * inh_array_width;
01794   input_dimension   = num_eyes*(2*rf_radius+1)*(2*rf_radius+1);
01795   RN_sq             = RN*RN;
01796 
01797   if (!skip_weight_init)
01798     init_weights();
01799 
01800   /* Exercise drand48() differently on each PE to help ensure that
01801      noise is uncorrelated */
01802   shuffled_rand_reset(seed);
01803   for(i=0; i < 500+MyPE; i++)
01804     drand48();              
01805 
01806 #ifndef NO_INPUTS
01807   inputs->init();
01808 #endif
01809   
01810   /* One PE prints out final values of starting params, for reference */
01811   if (AMPARENTPE) {
01812     char buf[MAXFILENAMELENGTH];
01813     sprintf( buf,"%s.init.param",filebase);
01814     cmdparam_save_current_state(buf);
01815   }
01816   /* Now that a listing is on file, report changes to params */
01817   cmdparam_changes_verbose = True; 
01818 
01819   /* Declare initialization officially complete */
01820   network_initialized = True;
01821   cmddefs_declare_prereq_status( "init_network", CMD_NO_ERROR );
01822  
01823   /* Iteration 0 is used to make sure everything is initialized properly */
01824   cmddefs_exec_str("testing 0");
01825 
01826   /* Erase effect of running the test iteration */
01827 #ifndef NO_INPUTS
01828   inputs->reset();
01829 #endif
01830   
01831   return CMD_NO_ERROR;
01832 }
01833 
01834 
01835 
01837 cmdstat cmd_uninit_network( CMD_ARGS )
01838 {
01839   (void)argc; /* Unused */
01840   (void)argv; /* Unused */
01841   
01842   network_initialized = False;
01843   cmddefs_declare_prereq_status( "init_network", CMD_NEVER_CALLED );
01844   iteration=startt=0;
01845   presentation=0;
01846   nrows=N/NPEs;
01847   
01848   /* Clear out all training hooks defined */
01849   hooklists_empty_list(before_input);
01850   hooklists_empty_list(after_presentation);
01851   hooklists_empty_list(after_learning);
01852   
01853   /* Warn about this weird case; may or may not be a problem */
01854   if (NROWS*NPES != NMAX)
01855     ipc_notify(IPC_ONE,IPC_WARNING,"Maximum cortex size is NOT square:  N(%d) x NROWS*NPES(%d)", 
01856                (int)N, (int)(NROWS*NPES));
01857 
01858 #ifndef NO_INPUTS
01859   inputs->uninit();
01860 #endif
01861   
01862 #ifndef NO_WEIGHTS
01863   {
01864     int i,j;
01865     
01866     /* Copy addresses into map structure */
01867     for (i=0; i<nrows; i++)
01868       for (j=0; j<N; j++){               
01869         
01870         cortex_map[MAPROW(i)][j].lat_exc_wts = wts[i][j].lat_exc_wts;
01871         cortex_map[MAPROW(i)][j].lat_inh_wts = wts[i][j].lat_inh_wts;
01872         cortex_map[MAPROW(i)][j].weights     = wts[i][j].weights    ;
01873         
01874 #ifdef VERIFY_WEIGHT_SAVES
01875         /* Copy addresses into duplicate map structure */
01876         Orig_map[MAPROW(i)][j].lat_exc_wts = Orig_wts[i][j].lat_exc_wts;
01877         Orig_map[MAPROW(i)][j].lat_inh_wts = Orig_wts[i][j].lat_inh_wts;
01878         Orig_map[MAPROW(i)][j].weights     = Orig_wts[i][j].weights    ;
01879 #endif
01880       }
01881   }
01882 #endif
01883 
01884   return CMD_NO_ERROR;
01885 }
01886 
01887 
01888 
01890 void clear_weights(void)
01891 {
01892   int local_row, j, k, eye, x, y;
01893 
01894   for(local_row=0; local_row<nrows; local_row++){
01895     const int map_row = MAPROW(local_row);
01896 
01897     for(j=0; j<N; j++) {
01898       cortex_map[map_row][j].centerx = 0;
01899       cortex_map[map_row][j].centery = 0;
01900       for(k=0; k<lat_exc_dimension; k++)
01901         cortex_map[map_row][j].lat_exc_wts[k]   = -DEATH_FLAG;
01902       for(k=0; k<lat_inh_dimension; k++)
01903         cortex_map[map_row][j].lat_inh_wts[k]   = -DEATH_FLAG; 
01904       for(eye=0; eye<num_eyes; eye++)
01905         for(x=0; x<WTMAX; x++)
01906           for(y=0; y<WTMAX; y++)
01907             cortex_map[map_row][j].weights[eye][x][y] = -DEATH_FLAG;  
01908     }
01909   }
01910 }
01911 
01912 
01913 
01924 void init_weights(void)
01925 {
01926   int i,j,k,l, eye; 
01927   double length=0.0;
01928   int lowk, highk, lowl, highl;
01929 
01930  const double preset_sigma_e =
01931    (preset_sigma_exc  != Uninitialized ? preset_sigma_exc : 
01932     (preset_sigma_lat != Uninitialized ? preset_sigma_lat :
01933      0.9*exc_rad));
01934 
01935  const double preset_sigma_i =
01936    (preset_sigma_inh  != Uninitialized ? preset_sigma_inh : 
01937     (preset_sigma_lat != Uninitialized ? preset_sigma_lat*MIN(1,sqrt(inh_rad)) :
01938      0.9*inh_rad));
01939 
01940   /* Ensure that all weights are known. */
01941   clear_weights();
01942 
01943   for(i=0; i<nrows; i++){
01944     const int row = MAPROW(i);
01945     /* To make weights generated independent of NPEs */
01946     shuffled_rand_reset(seed+123456+row);
01947     for(j=0; j<N; j++) {
01948         
01949       /*
01950         Choose receptive field center with a random degree of scatter. 
01951         The row_offset ensures that 0 <= cx,cy <= (RN-1).
01952         
01953         Originally row_offset was always 0.9999, which works properly
01954         only for N>RN; 0.5 was added for the N<RN case but may
01955         actually work in every case.  It would take some alegebra or
01956         extensive testing to verify that supposition for different
01957         values of randomness. -- J.A.B.
01958       */
01959       const double cortical_image_width = RN - 2*retina_edge_buffer;
01960       double row_offset = (N>=cortical_image_width ? 0.9999 : 0.5);
01961 
01962       const double cx = retina_edge_buffer + cortical_image_width *
01963         ((row+row_offset)/(double)N + randomness*(2.0*shuffled_rand()-1.0));
01964       
01965       const double cy = retina_edge_buffer + cortical_image_width *
01966         ((  j+row_offset)/(double)N + randomness*(2.0*shuffled_rand()-1.0));
01967 
01968       cortex_map[row][j].centerx = (int)floor(cx);
01969       cortex_map[row][j].centery = (int)floor(cy);
01970 
01971       lowk  = MAX(cortex_map[row][j].centerx-rf_radius,0   );
01972       highk = MIN(cortex_map[row][j].centerx+rf_radius,RN-1);
01973       lowl  = MAX(cortex_map[row][j].centery-rf_radius,0   );
01974       highl = MIN(cortex_map[row][j].centery+rf_radius,RN-1);
01975 
01976       /* Distribute weights in the receptive field randomly. If preset weights is
01977        * turned on, preset the weights to gaussians of given sigma. 
01978        * The afferent receptive fields were initialized to circular fields by
01979        * killing all the connections that fall outside a circle of radius
01980        * rf_radius.
01981        */
01982       length = 0.0;
01983       if (preset_aff_wts){                        /* Initialize to gaussian */
01984         for (k=lowk; k <=highk; k++) 
01985           for (l=lowl; l<=highl; l++){
01986             double value;
01987             double xsq = 0.5+abs(cortex_map[row][j].centerx-k); 
01988             double ysq = 0.5+abs(cortex_map[row][j].centery-l); 
01989             xsq *= xsq;
01990             ysq *= ysq;
01991             value = exp(-((xsq+ysq)/(preset_sigma_aff * preset_sigma_aff)));
01992             for (eye=0; eye<num_eyes; eye++)        
01993               cortex_map[row][j].weights[eye][k-lowk][l-lowl] = value;
01994             length += num_eyes * value;
01995           }
01996       }
01997 
01998       else{                                       /* Initialize randomly    */
01999         for (k=lowk; k <=highk; k++) 
02000           for (l=lowl; l<=highl; l++){
02001             double value = shuffled_rand();
02002             for (eye=0; eye<num_eyes; eye++)        
02003               cortex_map[row][j].weights[eye][k-lowk][l-lowl] = value;
02004             length += num_eyes * value;
02005           }
02006       }
02007 
02008       /* Initialize all connections outside the circle to negative, if appropriate */
02009       if (circular_aff_wts)
02010         length = prune_circular_aff_weights(cortex_map[row][j].centerx,cortex_map[row][j].centery,
02011                                             rf_radius, cortex_map[row][j].weights, length);
02012 
02013       /* Normalize */
02014       length = 1.0/length;
02015       for (k=lowk; k <=highk; k++) 
02016         for (l=lowl; l<=highl; l++)
02017           if (!circular_aff_wts || WITHIN_RADIUS(k-cortex_map[row][j].centerx,l-cortex_map[row][j].centery,rf_radius_sq))
02018             for (eye=0; eye<num_eyes; eye++) 
02019               cortex_map[row][j].weights[eye][k-lowk][l-lowl] *= length;
02020 
02021       /* Set up both sets of lateral weights */
02022       setup_lateral_weights(row,j, exc_rad, exc_array_width,cortex_map[row][j].lat_exc_wts,
02023                             preset_lat_wts, preset_sigma_e, lat_exc_randomness,
02024                             &exc_connections_killed);
02025       setup_lateral_weights(row,j, inh_rad, inh_array_width,cortex_map[row][j].lat_inh_wts,
02026                             preset_lat_wts, preset_sigma_i, lat_inh_randomness,
02027                             &inh_connections_killed);
02028     }
02029   }
02030 }
02031 
02032 
02033 
02035 void setup_latw(void)
02036 {
02037  int i,j;
02038 
02039  if (preset_sigma_exc==Uninitialized || preset_sigma_inh==Uninitialized) {
02040    ipc_notify(IPC_ONE,IPC_ERROR,
02041               "Must set preset_sigma_exc and preset_sigma_inh to use setup_latw()");
02042    return;
02043  }
02044  
02045  for(i=0; i<nrows; i++) {
02046    const int row    = MAPROW(i);
02047    for(j=0; j<N; j++) {
02048      setup_lateral_weights(row,j, exc_rad, exc_array_width,cortex_map[row][j].lat_exc_wts,
02049                            preset_lat_wts, preset_sigma_exc, lat_exc_randomness,
02050                            &exc_connections_killed);
02051      setup_lateral_weights(row,j, inh_rad, inh_array_width,cortex_map[row][j].lat_inh_wts,
02052                            preset_lat_wts, preset_sigma_inh, lat_inh_randomness,
02053                            &inh_connections_killed);
02054    }
02055  }
02056 }
02057 
02058 
02059 
02068 void setup_lateral_weights(int ui, int uj, int radius,
02069                            int array_width, l_weight *weights,
02070                            int preset, double sigma, double amt_of_randomness,
02071                            int* con_killed_flag)
02072 {
02073   int k,l;
02074   
02075   const int lowk  = MAX(ui-radius,0);
02076   const int highk = MIN(ui+radius,N);
02077   const int lowl  = MAX(uj-radius,0);
02078   const int highl = MIN(uj+radius,N);
02079   
02080   const int max_num_connections = (highk-lowk+1)*(highl-lowl+1);
02081   const double mean_wt = 1.0/max_num_connections;
02082   
02083   if (preset)
02084     for(k=lowk; k<=highk; k++)        
02085       for(l=lowl; l<=highl; l++){
02086         double xsq = (double)(k-ui); 
02087         double ysq = (double)(l-uj);
02088         xsq *= xsq;
02089         ysq *= ysq;
02090         weights[LAT_INDEX(ui,uj,k,l,radius,array_width)] = 
02091           mean_wt * exp( -((xsq+ysq)/(sigma*sigma)));
02092       }
02093   else /* Init weights randomly */
02094     for(k=lowk; k<=highk; k++)        
02095       for(l=lowl; l<=highl; l++)
02096         weights[LAT_INDEX(ui,uj,k,l,radius,array_width)] = 
02097           dist_lat_wt(mean_wt,amt_of_randomness);
02098   
02099   if (circular_lat_wts) {
02100     prune_circular_lat_weights(ui,uj,radius, array_width, weights);
02101     *con_killed_flag=True;
02102   }
02103   
02104   normalize_lat_wts(ui,uj,radius,array_width,weights);
02105 }
02106 
02107 
02108 
02110 void prune_circular_lat_weights(int ui, int uj, int radius, 
02111                                 int array_width, l_weight *weights)
02112 {
02113   const double radius_float    = radius+circular_radius_trim;
02114   const double radius_sq       = radius_float*radius_float;
02115   const double smooth_start    = radius+smooth_circular_radius_trim;
02116   const double smooth_start_sq = smooth_start*smooth_start;
02117   const double smooth_rad      = (radius_float-smooth_start)/2;
02118   const double smooth_rad_sq   = smooth_rad*smooth_rad;
02119     
02120   const int lowk  = MAX(ui-radius,0);
02121   const int highk = MIN(ui+radius,N);
02122   const int lowl  = MAX(uj-radius,0);
02123   const int highl = MIN(uj+radius,N);
02124 
02125   int k,l;
02126   
02127   for (k=lowk; k <=highk; k++)
02128     for (l=lowl; l<=highl; l++) {
02129       const double xdist    = k-ui;
02130       const double ydist    = l-uj;
02131       const double xdist_sq = xdist*xdist;
02132       const double ydist_sq = ydist*ydist;
02133       const double rdist_sq = xdist_sq+ydist_sq;
02134       
02135       if (radius>1 && !WITHIN_RADIUS_SQ(xdist_sq,ydist_sq,radius_sq))
02136         weights[LAT_INDEX(ui,uj,k,l,radius,array_width)] = -DEATH_FLAG;
02137       
02138       else if (smooth_circular_outlines && (rdist_sq >= smooth_start_sq)) {
02139         double dist_sq = sqrt(rdist_sq)-smooth_start;
02140         dist_sq*=dist_sq;
02141         
02142         weights[LAT_INDEX(ui,uj,k,l,radius,array_width)] = 
02143           weights[LAT_INDEX(ui,uj,k,l,radius,array_width)] *
02144           exp( -(dist_sq/smooth_rad_sq) );
02145       }
02146     }
02147 }
02148 
02149 
02150 
02152 double prune_circular_aff_weights(int ui, int uj, int radius, 
02153                                   a_weight weights[MAX_NUM_EYES][WTMAX][WTMAX],
02154                                   double length)
02155 {
02156   const double radius_float    = radius+circular_radius_trim;
02157   const double radius_sq       = radius_float*radius_float;
02158   const double smooth_start    = radius+smooth_circular_radius_trim;
02159   const double smooth_start_sq = smooth_start*smooth_start;
02160   const double smooth_rad      = (radius_float-smooth_start)/2;
02161   const double smooth_rad_sq   = smooth_rad*smooth_rad;
02162     
02163   const int lowk  = MAX(ui-radius,0);
02164   const int highk = MIN(ui+radius,RN);
02165   const int lowl  = MAX(uj-radius,0);
02166   const int highl = MIN(uj+radius,RN);
02167 
02168   int k,l;
02169   
02170   for (k=lowk; k <=highk; k++)
02171     for (l=lowl; l<=highl; l++) {
02172       const double xdist    = k-ui;
02173       const double ydist    = l-uj;
02174       const double xdist_sq = xdist*xdist;
02175       const double ydist_sq = ydist*ydist;
02176       const double rdist_sq = xdist_sq+ydist_sq;
02177       
02178       int eye;
02179       
02180       if (radius>1 && !WITHIN_RADIUS_SQ(xdist_sq,ydist_sq,radius_sq))
02181         for (eye=0; eye<num_eyes; eye++) {
02182           /* Kill connection */
02183           length -= weights[eye][k-lowk][l-lowl];
02184           weights[eye][k-lowk][l-lowl] = -DEATH_FLAG;
02185         }
02186       
02187       else if (smooth_circular_outlines && (rdist_sq >= smooth_start_sq)) {
02188         for (eye=0; eye<num_eyes; eye++) {
02189           double dist_sq = sqrt(rdist_sq)-smooth_start;
02190           a_weight init_weight = weights[eye][k-lowk][l-lowl];
02191           dist_sq*=dist_sq;
02192           
02193           weights[eye][k-lowk][l-lowl] = 
02194             init_weight * exp( -(dist_sq/smooth_rad_sq) );
02195           length += weights[eye][k-lowk][l-lowl]-init_weight;
02196         }
02197       }
02198     }
02199 
02200   return length;
02201 }
02202 
02203 
02204 
02209 double dist_lat_wt(double value, double amt_of_randomness)
02210 /* Randomness is in range 0-1 */
02211 {
02212   double low, add;
02213 
02214   low = value * (1.0 - amt_of_randomness)  ;
02215   add = 2*value*amt_of_randomness*drand48();
02216 
02217   return(low+add);
02218 }
02219 
02220 
02221 
02227 cmdstat cmd_kill_connections( CMD_ARGS )
02228 {
02229   int i,j,k;
02230   int living_inh_connections = 0;
02231   int dead_inh_connections   = 0;
02232   int killed_inh_connections = 0;
02233   //int theoretical_total_inh_connections  = nrows*N*lat_inh_dimension;
02234 
02235   double i_death = (argc>0 ? cmdf(argv[0]) : inh_death);
02236   double e_death = (argc>1 ? cmdf(argv[1]) : exc_death);
02237 
02238   if (e_death > 0)  exc_connections_killed = True;
02239   if (i_death > 0)  inh_connections_killed = True;
02240 
02241   for (i=0; i<nrows; i++){                       /* For each row in the PE   */
02242     const int row = MAPROW(i);
02243     for(j=0;j<N; j++)                            /* For each column          */
02244       {
02245         for(k=0; k<lat_exc_dimension; k++)
02246           if (cortex_map[row][j].lat_exc_wts[k] < e_death) 
02247             cortex_map[row][j].lat_exc_wts[k] = -DEATH_FLAG;
02248 
02249         for(k=0; k<lat_inh_dimension; k++)
02250           if (cortex_map[row][j].lat_inh_wts[k] < i_death) {
02251             dead_inh_connections++;
02252             /* count this connection as killed if it was live before */
02253             if (cortex_map[row][j].lat_inh_wts[k] > 0) killed_inh_connections++;
02254             /* kill it */
02255             cortex_map[row][j].lat_inh_wts[k] = -DEATH_FLAG;
02256           }
02257           else living_inh_connections++;
02258       }
02259   }
02260   ipc_pe_msg_delay(1.0);
02261   int total_inh_connections = living_inh_connections + dead_inh_connections;
02262   ipc_notify(IPC_ALL,IPC_STD,"Killed %g%% (%d/%d) of the inhibitory connections, leaving %d",
02263              (double)(100*((float)killed_inh_connections)/total_inh_connections),
02264              killed_inh_connections, total_inh_connections, living_inh_connections);
02265 
02266   return CMD_NO_ERROR;
02267 }
02268 
02269 
02270 
02272 int change_lateral_exc_radius(int old_radius, int new_radius)
02273 {
02274   int i,j;
02275   
02276   /* Rearrange and renormalize lateral weights, if needed */
02277   if (new_radius > old_radius) {
02278     ipc_notify(IPC_ONE,IPC_ERROR,"Increasing excitatory radius is not supported");
02279     new_radius=old_radius;
02280   }
02281   
02282   else if (new_radius < old_radius)
02283     for (i=0; i<nrows; i++) {
02284       const int row = MAPROW(i);
02285       for (j=0; j<N; j++)
02286         reduce_lateral_radius(row,j,old_radius,new_radius,exc_array_width,cortex_map[row][j].lat_exc_wts);
02287     }
02288   
02289   return new_radius;
02290 }
02291 
02292 
02302 void reduce_lateral_radius(int ui, int uj, int old_radius, int new_radius, int array_width, l_weight *weights)    
02303 {
02304   int k,l;
02305   const int lowk  = MAX(ui-new_radius,0  );
02306   const int highk = MIN(ui+new_radius,N-1);
02307   const int lowl  = MAX(uj-new_radius,0  );
02308   const int highl = MIN(uj+new_radius,N-1);
02309         
02310   for(k=lowk; k<= highk; k++){
02311     const int partial_index_new = PARTIAL_LAT_INDEX(ui,uj,k,new_radius,array_width);
02312     const int partial_index_old = PARTIAL_LAT_INDEX(ui,uj,k,old_radius,array_width);
02313     
02314     for(l=lowl; l<=highl; l++)
02315       weights[FULL_LAT_INDEX(partial_index_new,l)] = 
02316         weights[FULL_LAT_INDEX(partial_index_old,l)];
02317   }
02318 
02319   if (circular_lat_wts)
02320     prune_circular_lat_weights(ui,uj,new_radius, array_width, weights);
02321       
02322   /* Renormalize the copied weights */
02323   normalize_lat_wts(ui,uj,new_radius,array_width,weights);
02324 }
02325 
02326 
02327 
02336 void collect_activation_data(int dest_pe)
02337 {
02338   int i,pe;
02339   ipc_barrier(); /* Ensure that data is ready to copy */
02340 
02341   /* Currently collects initial activity from each processor */
02342 
02343   if (dest_pe==Uninitialized)
02344     for(pe=0; pe<NPEs; pe++) {
02345       if (!PEISME(pe))
02346         for(i=0; i<nrows; i++)  {
02347           ipc_put(init_activity[MAPROW(i)], IPC_DOUBLE, N, pe);
02348           /* ipc_pe_msg_delay(1.0);
02349           ipc_notify(IPC_ALL,IPC_STD,"Copying data from row %d to PE%d",MAPROW(i),pe); */
02350         }
02351     }
02352   
02353   else if (!PEISME(dest_pe))
02354     for(i=0; i<nrows; i++)  
02355       ipc_put(init_activity[MAPROW(i)], IPC_DOUBLE, N, dest_pe);
02356   
02357   ipc_barrier(); /* Ensure that data has arrived */
02358 } 
02359 
02360 
02361 
02367 int save_current(const char *filename)
02368 {
02369 #ifdef NO_IO
02370   (void)filename;
02371 #else
02372   
02373   FILE *fp=NULL;
02374   char buf[50]; 
02375 
02376 #ifdef VERIFY_WEIGHT_SAVES 
02377   {
02378     int row, i, j, k;
02379     for(i=0; i<nrows; i++){
02380       row = MAPROW(i);
02381       for(j=0; j<N; j++) {
02382 
02383         /* Copy weights from original arrays */
02384         Orig_map[row][j].centerx = cortex_map[row][j].centerx;
02385         Orig_map[row][j].centery = cortex_map[row][j].centery;
02386         for(k=0; k<lat_exc_dimension; k++)
02387           Orig_map[row][j].lat_exc_wts[k] = cortex_map[row][j].lat_exc_wts[k];
02388         for(k=0; k<lat_inh_dimension; k++)
02389           Orig_map[row][j].lat_inh_wts[k] = cortex_map[row][j].lat_inh_wts[k]; 
02390         for(k=0; k<input_dimension; k++)
02391           Orig_map[row][j].weights[0][0][k] = cortex_map[row][j].weights[0][0][k]; 
02392       }
02393     }
02394   }
02395   verify_saved_weights(0.0);
02396 #endif
02397 
02398   /* The last PE is in charge of writing to the file */
02399   if (AMYOUNGESTPE) {
02400     if (!filename) {
02401       /* Assume standard name */
02402       sprintf( buf, "%s.%06d.wts", filebase, iteration );
02403       filename=buf;
02404     }
02405 
02406     if ((fp=fopen(filename, "w+"))==NULL){
02407       ipc_abort(IPC_EXIT_FILE_PROBLEM,"Weights file %s couldn't be opened for saving", buf);
02408     }
02409 
02410     ipc_notify(IPC_ALL,IPC_STD,"Saving weights to file %s",filename);
02411   }
02412 
02413   
02414 #ifdef BINARY_WEIGHTS_FILE
02415   
02416   /* All PEs process the data */
02417   binaryWeightsFileWrite(fp);
02418   
02419 #else
02420   
02421   /* Only the last PE does the write */
02422   if (AMYOUNGESTPE && fp!=NULL){
02423     if (fprintf(fp,"%d %d\n", t, N)==EOF)
02424       ipc_notify(IPC_ALL,IPC_ERROR,"Error appending to file");
02425     weights_IO(WRITE,fp);
02426   }
02427 
02428 #endif
02429 
02430   if (fp!=NULL)
02431     fclose(fp);
02432   
02433   /* Allows saving in middle of training by reloading the weights destroyed by saving */
02434 #ifdef RELOAD_AFTER_WEIGHT_SAVE
02435   ipc_barrier();
02436   clear_weights(); /* Just to be sure it's working */
02437   if ( load_current(t,NULL) != CMD_NO_ERROR && !interactive)
02438     ipc_exit(IPC_EXIT_FILE_PROBLEM,"Problem with weights file");
02439 #endif
02440 
02441 #endif
02442 
02443   return(1);
02444 }  
02445 
02446 
02447 
02453 int load_current(int load_snap, const char *filename)
02454                 
02455 {
02456   int status=CMD_NO_ERROR;
02457 #ifdef NO_IO
02458   (void)load_snap;
02459   (void)filename;
02460 #else
02461   char buf[50];
02462   FILE *fp=NULL;
02463 
02464   if (AMPARENTPE){ /* Parent does the file reading and input generation */
02465     if (!filename) {
02466       /* Assume standard name */
02467       sprintf(buf, "%s.%06d.wts", filebase, load_snap);
02468       filename=buf;
02469     }
02470 
02471     if ((fp=fopen(filename, "r" ))==NULL) {
02472       /* Could add synchronization mechanism for NPES>1 instead of aborting */
02473       if (!interactive || NPEs>1) 
02474         ipc_abort(IPC_EXIT_FILE_PROBLEM,"Wt file %s couldn't be opened", buf);
02475       else {
02476         ipc_notify(IPC_ONE,IPC_ERROR,"Wt file %s couldn't be opened", buf);
02477         return CMD_FILE_ERROR;
02478       }
02479     }
02480   }
02481   
02482   /* Call init_network with non-essential hooks disabled and weight init skipped */
02483   if (!network_initialized) {
02484     int global_essential_training_hooks_only=essential_training_hooks_only;
02485     essential_training_hooks_only=True;
02486     cmddefs_exec_str("init_network True");
02487     essential_training_hooks_only=global_essential_training_hooks_only;
02488   }
02489   
02490   if (AMPARENTPE)
02491     ipc_notify(IPC_ALL,IPC_STD,"Advancing to iteration %d", load_snap);
02492 
02493   
02494   /* Make sure parameters have advanced to this iteration */
02495   advance_iteration_counter(iteration,load_snap);
02496 
02497   /* Ensure that all weights are re-initialized before loading because
02498      some, e.g. killed inhibitory weights, are not initialized during
02499      the reload */
02500   clear_weights();
02501   
02502   /* Read & distribute the network to all PEs     */
02503 #ifdef BINARY_WEIGHTS_FILE
02504     if(binaryWeightsFileRead(fp))
02505       status=CMD_FILE_ERROR;
02506 #else
02507 
02508     /* Parent does the file reading */
02509     if (AMPARENTPE) {
02510       int anint,junk;
02511       
02512       fscanf(fp,"%d %d",&anint, &junk)  ;    /* read the t of the snapshot      */
02513       t = anint;
02514       if (t != load_snap) {
02515         ipc_notify(IPC_ALL,IPC_ERROR,"Wt file %s doesn't have proper t", buf);
02516         status=CMD_FILE_ERROR;
02517       }
02518     }
02519     weights_IO(READ,fp);
02520 
02521 #endif
02522 
02523   if (AMPARENTPE)  fclose(fp);/* Only the parent has to close the file        */
02524 
02525   /*
02526     Set these flags for safety, assuming that there might be some
02527     connections killed in the file (presumably should add checking for it,
02528     but it's almost always true that connections were killed, and it
02529     only affects the performance, and even that only slightly.)
02530   */
02531   exc_connections_killed=True;
02532   inh_connections_killed=True;
02533   
02534 
02535   /* Test every weight */
02536 #ifdef VERIFY_WEIGHT_SAVES
02537   verify_saved_weights(0.0000001);
02538 #endif
02539 
02540   hooklists_run_list(before_input,load_snap,True);
02541 #ifndef NO_INPUTS
02542   inputs->next();      /* Is this call necessary and/or desirable? */
02543   inputs->activate();  /* Recreate the last input */
02544 #endif
02545   ipc_barrier();       /* Synchronize all PEs                          */
02546 
02547   if (!AMPARENTPE) ipc_get(&iteration, IPC_INT, 1, PARENTPE);  /* Read the 't' value from the parent  */
02548   iteration++; /* Declare the iteration over since it presumably was when the file was saved */
02549   
02550   ipc_notify(IPC_ONE,IPC_STD,"Changing iteration to %d",iteration);
02551   startt=iteration;
02552 
02553   if (iteration > tend) {
02554     /* Arbitrary choice, but otherwise it would have to be done manually each time */
02555     const int new_tend = (int)(tend*1.5);  
02556     ipc_notify(IPC_ONE,IPC_STD,"Changing tend from %d to %d to allow use of network",tend,new_tend);
02557     tend = new_tend;
02558   }
02559   
02560   present_inputs(False);
02561   hooklists_run_list(after_learning,iteration,True);
02562 #endif
02563 
02564   return status;
02565 }
02566 
02567 
02568 
02569 #ifdef VERIFY_WEIGHT_SAVES 
02570 void verify_saved_weights( double tolerance )
02571 {
02572   int row, i, j, eye, x, y;
02573   int aff_errors_found=0;
02574 
02575   for(i=0; i<nrows; i++){
02576     row = MAPROW(i);
02577     for(j=0; j<N; j++) {
02578 
02579       if (Orig_map[row][j].centerx - cortex_map[row][j].centerx > tolerance)
02580         ipc_notify(IPC_ALL,IPC_ERROR,"row:%d j:%d       -- Centerx changed: %d -> %d",
02581                   row,j,(int)Orig_map[row][j].centerx,(int)cortex_map[row][j].centerx);
02582       if (Orig_map[row][j].centery - cortex_map[row][j].centery > tolerance)
02583         ipc_notify(IPC_ALL,IPC_ERROR,"row:%d j:%d       -- Centery changed: %d -> %d",
02584                   row,j,(int)Orig_map[row][j].centery,(int)cortex_map[row][j].centery);
02585       
02586       for(eye=0; eye<num_eyes; eye++)
02587         for(x=0; x<WTMAX; x++)
02588           for(y=0; y<WTMAX; y++)
02589             if (Orig_map[row][j].weights[eye][x][y] - cortex_map[row][j].weights[eye][x][y] >tolerance) {
02590               if (++aff_errors_found < VERIFY_WEIGHT_SAVES_ERROR_LIMIT)
02591                 ipc_notify(IPC_ALL,IPC_ERROR,"row:%d j:%d eye:%d x:%d y:%d -- Afferent weights differ: %e -> %e",
02592                           row,j,eye,x,y,
02593                           (double)Orig_map[row][j].weights[eye][x][y],
02594                           (double)cortex_map[row][j].weights[eye][x][y]);
02595               else if (aff_errors_found == VERIFY_WEIGHT_SAVES_ERROR_LIMIT)
02596                 ipc_notify(IPC_ALL,IPC_ERROR,"Reached limit for VERIFY_WEIGHT_SAVES error reporting; rest will be discarded");
02597             }
02598 
02599       verify_saved_lateral_weights(row,j, exc_rad, exc_array_width,
02600                                    Orig_map[row][j].lat_exc_wts,
02601                                    cortex_map[row][j].lat_exc_wts,
02602                                    tolerance,"lat_exc_wts");
02603 
02604       verify_saved_lateral_weights(row,j, inh_rad, inh_array_width,
02605                                    Orig_map[row][j].lat_inh_wts,
02606                                    cortex_map[row][j].lat_inh_wts,
02607                                    tolerance,"lat_inh_wts");
02608       
02609     }
02610   }
02611 }
02612 #endif
02613 
02614 
02615 
02616 #ifdef VERIFY_WEIGHT_SAVES 
02617 void verify_saved_lateral_weights( int i, int j, int radius, int array_width,
02618                                    l_weight *old_weights, l_weight *new_weights,
02619                                    double tolerance, const char *description)
02620 {
02621   const int lowk  = MAX(i-radius,0  );
02622   const int highk = MIN(i+radius,N-1);
02623   const int lowl  = MAX(j-radius,0  );
02624   const int highl = MIN(j+radius,N-1);
02625 
02626   static int errors_found=0;
02627   int k,l;
02628   
02629   for(k=lowk; k<= highk; k++) {
02630     const int partial_idx = PARTIAL_LAT_INDEX(i,j,k,radius,array_width);
02631     for (l=lowl; l<=highl; l++) {
02632       const int idx = FULL_LAT_INDEX(partial_idx,l);
02633       
02634       if (old_weights[idx] - new_weights[idx] > tolerance) {
02635         if (++errors_found < VERIFY_WEIGHT_SAVES_ERROR_LIMIT)
02636           ipc_notify(IPC_ALL,IPC_ERROR,"i:%d j:%d k:%d l:%d -- %s differ: %e -> %e",
02637                     i,j,k,l,description,
02638                     (double)old_weights[idx],
02639                     (double)new_weights[idx]);
02640         else if (errors_found == VERIFY_WEIGHT_SAVES_ERROR_LIMIT)
02641           ipc_notify(IPC_ALL,IPC_ERROR,"Reached limit for VERIFY_WEIGHT_SAVES error reporting; rest will be discarded");
02642       }
02643       
02644     }
02645   }
02646 }
02647 #endif

Generated at Mon Aug 21 00:30:54 2000 for RF-LISSOM by doxygen1.2.1 written by Dimitri van Heesch, © 1997-2000