00001
00045 #include <math.h>
00046 #include <string.h>
00047 #include <stdio.h>
00048
00049 #include "ipc.h"
00050 #include "cmdparam.h"
00051 #include "inputs.h"
00052 #include "tilt.h"
00053 #include "ppm_draw.h"
00054
00055 #include "analyze.h"
00056 #include "file_io.h"
00057 #include "globals.h"
00058 #include "kernel.h"
00059 #include "lissom.h"
00060
00061
00062
00063
00064
00065
00066
00067
00068 #define NMAP_FEATURES 10
00069
00070 #define MAX_NUMBER_OF_PRESENTATIONS 3
00071
00072 #define MAX_NUM_PORTIONS 2
00073
00075 #define MAX_ANGLE_STEPS 360
00076
00077
00079 #define MAX_NUMBER_OF_SPOTS 5
00080
00081
00082
00083 #define ALL_UNITS 0
00084 #define MAX_UNITS 1
00085
00086 #define INIT 0
00087 #define SETL 1
00088
00089
00090 typedef struct
00091 {
00092 int i,j ;
00093 double or_selectivity ;
00094 int or_preference ;
00095 int phase, freq ;
00096 double od ;
00097 double activity ;
00098 } Act_Feature ;
00099
00100
00101
00102
00103
00104
00105
00106 int save_steps = 1;
00107 int t_presentation=Uninitialized;
00108 int number_of_portions = Uninitialized;
00109 int cortex_portion_boundary = Uninitialized;
00110 int save_angle_responses = False;
00111
00113 int retina_portion_boundary=Uninitialized;
00114 int truncate_inputs_across_boundary = False;
00115
00116
00117
00118
00119
00120
00121 CMD_DECLARE(analyze_activity);
00122 CMD_DECLARE(analyze_portions);
00123 CMD_DECLARE(divide_cortex);
00124 CMD_DECLARE(training_angle_distribution);
00125
00126
00127
00128
00129
00130
00131
00132 void compute_activity_statistics(double activity[NMAX][NMAX],
00133 double weighted_or_prefs[3][2][2],
00134 double base_response[MAX_ANGLE_STEPS][MAX_NUMBER_OF_SPOTS][2],
00135 FILE *fp);
00136 void find_activity_max(double activity[NMAX][NMAX],
00137 int *nexamples, Act_Feature *examples,
00138 double weightedORpref[2],
00139 int ilow, int ihigh, int jlow, int jhigh);
00140 void print_summary_header(FILE *fp, int num_portions);
00141
00142
00143
00144
00145
00146
00147
00149 int current_angle_step=0;
00150
00152 double average_or_prefs[2][3][MAX_NUM_PORTIONS][2];
00153
00157 int append_summary = False;
00158
00161 double ae_base_response[2][MAX_ANGLE_STEPS][MAX_NUMBER_OF_SPOTS][2];
00162
00163
00164 00165 00166
00167
00168
00169
00170
00171
00172
00173
00174
00175
00176 void tilt_init_hook( void )
00177 {
00178 CMD_DOC(analyze_activity,NULL,2,"%s <start> <end>",
00179 "Sets the start and end iterations for analyze_portions measures");
00180
00181 CMD_DOC(analyze_portions,"init_network",0,"%s",
00182 "Compute activity statistics for the initial and settled responses,\n"
00183 "saving pictures if needed. The statistics are computed separately for\n"
00184 "each portion.");
00185
00186 CMD_DOC(divide_cortex,"init_network",0,"%s",
00187 "Lesions receptive fields down the cortex_portion_boundary, typically the\n"
00188 "vertical midline. After this call, all weights on neurons on the left side\n"
00189 "of the cortex to receptors on the right side of the retina are zero, and\n"
00190 "vice-versa for the right side. The changes are permanent and irreversible;\n"
00191 "the old weight values are lost.\n\n"
00192 "Also, the input patterns used henceforth are truncated at the\n"
00193 "retina_portion_boundary to ensure that the patterns do not cross over into \n"
00194 "the receptive fields of the opposite side of the cortex (CURRENTLY UNIMPLEMENTED).\n\n"
00195 "This is used to distinguish lateral connection effects from receptive field\n"
00196 "effects, since after this call the only way for the left and right halves\n"
00197 "to interact is through the lateral connections.\n\n"
00198 "If there is some receptive field scatter enabled, the operation of\n"
00199 "this routine will need to be scrutinized very carefully to ensure\n"
00200 "that it is operating as intended. Having neurons on one side of the\n"
00201 "cortex whose receptive fields are on the opposite side of the retina\n"
00202 "may make the results difficult to interpret.");
00203
00204
00205
00206
00207
00208
00209
00210
00211
00212
00213 PARAM_I(PARAM_INT, cortex_portion_boundary,0,NMAX,
00214 "Unit number specifying the boundary between right and left sides\n"
00215 "of the cortex,");
00216 params_define_default_expr("cortex_portion_boundary","N/inputs_pereye");
00217
00218 PARAM_I(PARAM_INT, number_of_portions,0,MAX_NUM_PORTIONS,
00219 "Number of portions in which the cortex shall be divided for testing purposes.");
00220
00221 params_define_default_expr("number_of_portions","1");
00222
00223 PARAM_I(PARAM_BOOL, save_angle_responses,False,True,
00224 "Whether to save a copy of the average orientation activated for each angle\n"
00225 "when analyze_portions executes.");
00226
00227 PARAM_L(PARAM_INT, save_steps,Uninitialized,
00228 "Save network activation, etc. every (save_steps)th time analyze_portions\n"
00229 "is called. E.g.\n"
00230 "save_steps = 1 : save every step\n"
00231 "save_steps = 3 : save every third step\n"
00232 "save_steps = Uninitialized : do not save images.");
00233 }
00234
00235
00236
00237
00238
00239
00240
00241 cmdstat cmd_analyze_portions( CMD_ARGS )
00242 {
00243 static FILE *init_summary;
00244 static FILE *setl_summary;
00245 static int has_been_called=False;
00246
00247 (void)argc;
00248 (void)argv;
00249
00250 if (or_dumped == Uninitialized) {
00251 if (!has_been_called)
00252 ipc_notify(IPC_ONE,IPC_WARNING,"analyze_portions results will be incomplete because measure_or_pref has not yet been called");
00253 }
00254
00255 else if (learning && (iteration-or_dumped) > 180) {
00256 ipc_notify(IPC_ONE,IPC_WARNING,
00257 "measure_or_pref was called %d iterations ago; analyze_activity data may be stale",
00258 iteration-or_dumped);
00259 }
00260
00261
00262 if ((AMPARENTPE) && ((init_summary == NULL) || (setl_summary == NULL)) ) {
00263
00264 char append[2] = "a";
00265 char overwrite[2] = "w";
00266 char *openflags;
00267 char filename[50];
00268
00269 openflags = (append_summary ? append : overwrite);
00270 append_summary = True;
00271
00272 if (init_summary == NULL) {
00273 sprintf(filename,"%s.init.txt",filebase);
00274 if( (init_summary=fopen(filename,openflags))==NULL ) {
00275 ipc_notify(IPC_ALL,IPC_ERROR,"File %s not opened", filename );
00276 return CMD_FILE_ERROR;
00277 }
00278 print_summary_header(init_summary,number_of_portions);
00279 }
00280
00281 if (setl_summary == NULL) {
00282 sprintf(filename,"%s.setl.txt",filebase);
00283 if( (setl_summary=fopen(filename,openflags))==NULL ) {
00284 ipc_notify(IPC_ALL,IPC_ERROR,"File %s not opened", filename );
00285 return CMD_FILE_ERROR;
00286 }
00287 print_summary_header(setl_summary,number_of_portions);
00288 }
00289
00290 }
00291
00292
00293 compute_activity_statistics(init_activity,average_or_prefs[INIT],
00294 ae_base_response[INIT], init_summary);
00295
00296
00297 compute_activity_statistics(prev_map_activity,average_or_prefs[SETL],
00298 ae_base_response[SETL], setl_summary);
00299
00300
00301
00302
00303
00304
00305
00306
00307 if (save_steps && (save_steps != Uninitialized) && (current_angle_step % save_steps == 0))
00308 cmd_plot_activity(0,NULL);
00309
00310 has_been_called=True;
00311
00312 return CMD_NO_ERROR;
00313 }
00314
00315
00316
00319 cmdstat cmd_analyze_activity( CMD_ARGS )
00320 {
00321
00322 int activity_analysis_start = cmdi(argv[0]);
00323 int activity_analysis_end = cmdi(argv[1]);
00324
00325 (void)argc;
00326
00327
00328
00329 {
00330 char specifier[20];
00331 const char *args[]={"after_presentation",NULL,"analyze_portions"};
00332 snprintf(specifier,20,"%d-%d",activity_analysis_start,activity_analysis_end);
00333 args[1]=specifier;
00334 cmd_hook(3,args);
00335 }
00336
00337
00338
00339
00340 return CMD_NO_ERROR;
00341 }
00342
00343
00344
00345 cmdstat cmd_divide_cortex( CMD_ARGS )
00346 {
00347 int i,j,k,l,lowk,lowl,highk,highl,basek;
00348 (void)argv;
00349 (void)argc;
00350
00351
00352
00353
00354 truncate_inputs_across_boundary = True;
00355
00356 for(i=0; i<nrows; i++){
00357 const int row = MAPROW(i);
00358 for(j=0; j<N; j++)
00359 {
00360 00361
00362 if (row < cortex_portion_boundary) {
00363 lowk = MAX(cortex_map[row][j].centerx-rf_radius,retina_portion_boundary);
00364 highk= MIN(cortex_map[row][j].centerx+rf_radius,RN-1);
00365 }
00366
00367 00368
00369 else {
00370 lowk = MAX(cortex_map[row][j].centerx-rf_radius,0);
00371 highk= MIN(cortex_map[row][j].centerx+rf_radius,retina_portion_boundary-1);
00372 }
00373
00374 basek = MAX(cortex_map[row][j].centerx-rf_radius,0 );
00375 lowl = MAX(cortex_map[row][j].centery-rf_radius,0 );
00376 highl = MIN(cortex_map[row][j].centery+rf_radius,RN-1);
00377
00378
00379 00380 00381
00382
00383
00384 for (k=lowk; k <=highk; k++)
00385 for (l=lowl; l<=highl; l++) {
00386 cortex_map[row][j].weights[0][k-basek][l-lowl] = 0.0;
00387 cortex_map[row][j].weights[1][k-basek][l-lowl] = 0.0;
00388 }
00389 }
00390 }
00391
00392 ipc_notify(IPC_ONE,IPC_STD,"Cortex divided at vertical coordinate %d along retina vertical coordinate %d",
00393 cortex_portion_boundary,retina_portion_boundary);
00394
00395 return CMD_NO_ERROR;
00396 }
00397
00398
00399
00400
00401
00402
00403
00404
00405
00406
00407
00408
00409
00410
00411
00412
00413
00414
00415
00416
00417
00418
00419
00420
00421
00422
00423
00424
00425
00426
00427
00428
00429
00430
00431
00432
00433
00434
00435
00436
00437
00438
00439
00440
00441
00442
00443
00444
00445
00446
00447
00449 void print_summary_header(FILE *fp, int num_portions)
00450 {
00451 int i;
00452
00453
00454 #define PLINE(start,repeat) fprintf(fp,start); for (i=0;i<num_portions; i++) fprintf(fp,repeat); fprintf(fp,"\n")
00455 #define PPORT(start,repeat) fprintf(fp,start); for (i=0;i<num_portions; i++) fprintf(fp,repeat,i); fprintf(fp,"\n")
00456
00457 PPORT(" |","---------- Portion%2d ------------------------|");
00458 PLINE(" |"," |");
00459 PLINE(" |","t |Orientation |Maximum Activation |");
00460 PLINE(" |","h |Preference | P |");
00461 PPORT(" |","e%2d | | O r |");
00462 PLINE(" |","t | all max all- | Unit R e activ |");
00463 PLINE(" t |","a |units units base |( i, j) f:ation |");
00464 PLINE(" -------","----------------------------------------------");
00465
00466 #undef PLINE
00467 #undef PPORT
00468 }
00469
00470
00471
00482 void compute_activity_statistics(double activity[NMAX][NMAX],
00483 double weighted_or_prefs[3][2][2],
00484 double base_response[MAX_ANGLE_STEPS][MAX_NUMBER_OF_SPOTS][2],
00485 FILE *fp)
00486 {
00487 int pres_index=0;
00488 int nexamples = 1;
00489
00490
00491 Act_Feature examples[2][ NMAP_FEATURES];
00492
00493
00494
00495 if (t_presentation != Uninitialized)
00496 pres_index = t_presentation;
00497
00498 if (AMPARENTPE){ 00499
00500
00501
00502
00503
00504 find_activity_max(activity,
00505 &nexamples,&(examples[0][0]),
00506 weighted_or_prefs[pres_index][0],
00507 0, cortex_portion_boundary-1, 0, (N-1) );
00508
00509 if (number_of_portions > 1)
00510 find_activity_max(activity,
00511 &nexamples,&(examples[1][0]),
00512 weighted_or_prefs[pres_index][1],
00513 cortex_portion_boundary, (N-1), 0, (N-1) );
00514
00515
00516
00517 {
00518 int portion_number, which_units, example_number;
00519
00520
00521 fprintf(fp,"%6d",iteration);
00522
00523
00524 for (portion_number=0; portion_number < number_of_portions; portion_number++) {
00525 char or_pref_string[8] = "";
00526
00527
00528 if (save_angle_responses &&
00529 (pres_index == 0) &&
00530 (current_angle_step < MAX_ANGLE_STEPS))
00531 for (which_units=ALL_UNITS; which_units<=MAX_UNITS; which_units++) {
00532 base_response[current_angle_step][portion_number][which_units] =
00533 weighted_or_prefs[pres_index][portion_number][which_units];
00534 00535 00536
00537 }
00538
00539
00540 if (inputs->is_active(portion_number,0)) {
00541 const double thetarad = inputs->angle_of_object(portion_number,0);
00542 const double theta = RADIANS_TO_DEGREES(thetarad);
00543 fprintf(fp," |%5.1f ",theta);
00544 }
00545 else
00546 fprintf(fp," | ");
00547
00548
00549 for (which_units=ALL_UNITS; which_units<=MAX_UNITS; which_units++)
00550 if ( or_dumped == Uninitialized ||
00551 weighted_or_prefs[pres_index][portion_number][which_units] == Uninitialized)
00552 fprintf(fp," ");
00553 else fprintf(fp,"%5.1f ",
00554 RADIANS_TO_DEGREES(weighted_or_prefs[pres_index]
00555 [portion_number][which_units]));
00556
00557 00558
00559 if (or_dumped == Uninitialized ||
00560 weighted_or_prefs[pres_index][portion_number][ALL_UNITS] == Uninitialized ||
00561 base_response[current_angle_step][portion_number][ALL_UNITS] == Uninitialized ||
00562 (pres_index != 0))
00563 fprintf(fp," ");
00564 else
00565 fprintf(fp,"%6.2f ",
00566 RADIANS_TO_DEGREES(CONSTRAIN_SYMMETRIC(
00567 weighted_or_prefs[pres_index]
00568 [portion_number][ALL_UNITS] -
00569 base_response[current_angle_step]
00570 [portion_number][ALL_UNITS])));
00571
00572
00573 for (example_number=0; example_number < nexamples; example_number++) {
00574 if (or_dumped != Uninitialized)
00575 sprintf(or_pref_string, "%03d",
00576 (int)OR_PREF_TO_DEGREES(examples[portion_number]
00577 [example_number].or_preference));
00578 fprintf(fp,"(%3d,%3d)%3s:%5.3f ",
00579 examples[portion_number][example_number].i,
00580 examples[portion_number][example_number].j,
00581 or_pref_string,
00582 examples[portion_number][example_number].activity);
00583 }
00584 }
00585 fprintf(fp,"\n");
00586
00587
00588 if (pres_index == 2) {
00589 fprintf(fp,"\n");
00590
00591 for (which_units=ALL_UNITS; which_units<=MAX_UNITS; which_units++) {
00592 double perceived_angle_separate = Uninitialized;
00593 char perceived_angle_separate_string[8] = "";
00594 double perceived_angle_simultaneous = Uninitialized;
00595 char perceived_angle_simultaneous_string[8] = "";
00596 double difference = Uninitialized;
00597 char difference_string[8] = "";
00598
00599
00600 if ( or_dumped != Uninitialized &&
00601 (weighted_or_prefs[0][0][which_units] != Uninitialized) &&
00602 (weighted_or_prefs[2][1][which_units] != Uninitialized)) {
00603 perceived_angle_separate =
00604 fabs(weighted_or_prefs[0][0][which_units] -
00605 weighted_or_prefs[2][1][which_units]);
00606 sprintf(perceived_angle_separate_string, "%5.1f",
00607 RADIANS_TO_DEGREES(perceived_angle_separate));
00608 }
00609
00610
00611 if (or_dumped != Uninitialized &&
00612 (weighted_or_prefs[0][0][which_units] != Uninitialized) &&
00613 (weighted_or_prefs[2][1][which_units] != Uninitialized)) {
00614 perceived_angle_simultaneous =
00615 fabs(weighted_or_prefs[1][0][which_units] -
00616 weighted_or_prefs[1][1][which_units]);
00617 sprintf(perceived_angle_simultaneous_string, "%5.1f",
00618 RADIANS_TO_DEGREES(perceived_angle_simultaneous));
00619 }
00620
00621 if ((perceived_angle_simultaneous != Uninitialized) &&
00622 (perceived_angle_separate != Uninitialized)) {
00623 difference = perceived_angle_simultaneous - perceived_angle_separate;
00624 sprintf(difference_string, "%6.2f",
00625 RADIANS_TO_DEGREES(difference));
00626 }
00627
00628 switch (which_units){
00629 case ALL_UNITS: fprintf(fp,"AngleDiffs(allUnits) "); break;
00630 case MAX_UNITS: fprintf(fp,"AngleDiffs(maxUnits) "); break;
00631 }
00632
00633 if (inputs->is_active(1,0)) {
00634 const double thetadiff = fabs(inputs->angle_of_object(0,0)-inputs->angle_of_object(1,0));
00635
00636 fprintf(fp,"retina:%5.1f perceived,separate:%5s p,both:%5s illusory:%6s \n",
00637 RADIANS_TO_DEGREES(thetadiff),
00638 perceived_angle_separate_string,
00639 perceived_angle_simultaneous_string,
00640 difference_string);
00641 }
00642 }
00643
00644 fprintf(fp,"\n\n");
00645 }
00646 }
00647 }
00648 }
00649
00650
00651
00667 void find_activity_max(double activity[NMAX][NMAX],
00668 int *nexamples, Act_Feature *examples,
00669 double weightedORpref[2],
00670 int ilow, int ihigh, int jlow, int jhigh)
00671 {
00672 int i,j,k,m,example_number;
00673
00674 double or_vector_sum_x[2] = {0,0};
00675 double or_vector_sum_y[2] = {0,0};
00676
00677
00678 if (( (ihigh-ilow+1)*(jhigh-jlow+1) < *nexamples) || (*nexamples >= NMAP_FEATURES)){
00679 ipc_notify(IPC_ALL,IPC_WARNING,"Not enough data, or index overflow: ihigh-ilow+1 = %d, jhigh-jlow+1 = %d, nexamples=%d",
00680 ihigh-ilow+1, jhigh-jlow+1, *nexamples);
00681 *nexamples = 0;
00682 return;
00683 }
00684
00685
00686 for(i=0; i < *nexamples; i++)
00687 examples[i].activity = 0.0;
00688
00689
00690
00691 for(i=ilow; i<=ihigh; i++)
00692 for(j=jlow; j<=jhigh; j++){
00693
00694 if ((or_dumped != Uninitialized) && (activity[i][j] > 0.0)) {
00695
00696 const double angle = 2*DEGREES_TO_RADIANS(OR_PREF_TO_DEGREES(or_pref[combined_eyes][i][j]));
00697
00698
00699 or_vector_sum_x[ALL_UNITS] += activity[i][j] * cos(angle);
00700 or_vector_sum_y[ALL_UNITS] += activity[i][j] * sin(angle);
00701
00702
00703 if (activity[i][j] >= 1.0){
00704 or_vector_sum_x[MAX_UNITS] += activity[i][j] * cos(angle);
00705 or_vector_sum_y[MAX_UNITS] += activity[i][j] * sin(angle);
00706 }
00707 }
00708
00709
00710 for(m=0; (m < *nexamples) &&
00711 (examples[m].activity > activity[i][j]); m++);
00712
00713 for(k= (*nexamples); k >m; k--)
00714 examples[k] = examples[k-1];
00715
00716 examples[m].activity = activity[i][j];
00717 examples[m].i = i; examples[m].j = j;
00718
00719
00720
00721 }
00722
00723
00724 for (example_number=0; example_number < *nexamples; example_number++) {
00725 i = examples[example_number].i;
00726 j = examples[example_number].j;
00727 if (or_dumped != Uninitialized) {
00728 examples[example_number].or_preference = or_pref[ combined_eyes][i][j];
00729 examples[example_number].freq = sp_freq[ combined_eyes][i][j];
00730 examples[example_number].phase = sp_phase[combined_eyes][i][j];
00731 }
00732 }
00733
00734
00735 {
00736 double magnitude[2];
00737 double angle[2];
00738 double angle_around_origin;
00739 int which_units;
00740
00741 for (which_units=ALL_UNITS; which_units<=MAX_UNITS; which_units++) {
00742
00743 00744 00745 00746 00747 00748 00749 00750
00751
00752 magnitude[which_units] =
00753 sqrt(or_vector_sum_x[which_units]*or_vector_sum_x[which_units] +
00754 or_vector_sum_y[which_units]*or_vector_sum_y[which_units]);
00755
00756 if (magnitude[which_units] > 0) {
00757
00758
00759 angle_around_origin = atan2(or_vector_sum_y[which_units],
00760 or_vector_sum_x[which_units]);
00761
00762 00763
00764 angle[which_units] = CONSTRAIN_ANGLE(angle_around_origin/2);
00765
00766 00767 00768 00769 00770
00771
00772 weightedORpref[which_units] = angle[which_units];
00773 }
00774 else
00775 weightedORpref[which_units] = Uninitialized;
00776
00777 }
00778 }
00779
00780
00781 if ((weightedORpref[MAX_UNITS] == Uninitialized) &&
00782 (activity[examples[*nexamples-1].i][examples[*nexamples-1].j] > 0))
00783 weightedORpref[MAX_UNITS] =
00784 DEGREES_TO_RADIANS(OR_PREF_TO_DEGREES(examples[*nexamples-1].or_preference));
00785 }
00786
00787
00788