home *** CD-ROM | disk | FTP | other *** search
/ Programmer 7500 / MAX_PROGRAMMERS.iso / INFO / NEURLNET / NASANETS.ZIP / WEIGHTS.C < prev    next >
Encoding:
C/C++ Source or Header  |  1990-06-07  |  31.6 KB  |  802 lines

  1. /*=============================*/
  2. /*           NETS              */
  3. /*                             */
  4. /* a product of the AI Section */
  5. /* NASA, Johnson Space Center  */
  6. /*                             */
  7. /* principal author:           */
  8. /*       Paul Baffes           */
  9. /*                             */
  10. /* contributing authors:       */
  11. /*      Bryan Dulock           */
  12. /*      Chris Ortiz            */
  13. /*=============================*/
  14.  
  15.  
  16. /*
  17. ----------------------------------------------------------------------
  18.   Code For Manipulating The Weight Structures 
  19. ----------------------------------------------------------------------
  20.   This code is divided into 4 major sections:
  21.  
  22.   (1) include files
  23.   (2) externed functions
  24.   (3) global variables
  25.   (4) subroutines
  26.  
  27.   Each section is further explained below.
  28. ----------------------------------------------------------------------
  29. */
  30.  
  31.  
  32. /*
  33. ----------------------------------------------------------------------
  34.   INCLUDE FILES
  35. ----------------------------------------------------------------------
  36. */
  37. #include  "common.h"
  38. #include  "netio.h"
  39. #include  "weights.h"
  40. #include  "layer.h"
  41.  
  42.  
  43. /*
  44. ----------------------------------------------------------------------
  45.   EXTERNED FUNCTIONS AND GLOBALS
  46. ----------------------------------------------------------------------
  47. */
  48. extern float   C_Sint_to_float();
  49. extern char    *sys_long_alloc();
  50. extern char    *sys_alloc();
  51. extern void    sys_long_free();
  52. extern void    sys_free();
  53. extern float   IO_my_get_float();
  54. extern void    IO_my_get_string();
  55. extern void    IO_print();
  56. extern void    IO_insert_format();
  57. extern int     IO_more();
  58.  
  59. extern D_Sint  P_full_dot_forward();
  60. extern D_Sint  P_s_pattern_dot_forward();
  61. extern D_Sint  P_t_pattern_dot_forward();
  62. extern D_Sint  P_full_dot_backward();
  63. extern D_Sint  P_s_pattern_dot_backward();
  64. extern D_Sint  P_t_pattern_dot_backward();
  65. extern void    P_full_update_wts();
  66. extern void    P_s_pattern_update_wts();
  67. extern void    P_t_pattern_update_wts();
  68.  
  69. extern char   IO_str[MAX_LINE_SIZE];
  70. extern char   IO_wkstr[MAX_LINE_SIZE];
  71.  
  72.  
  73. /*
  74. ----------------------------------------------------------------------
  75.   GLOBAL VARIABLES
  76. ----------------------------------------------------------------------
  77.  There are two global values used by this code: "weight_max" and 
  78.   "weight_min".  They keep track of the INITIAL maximum and minimum
  79.   weights set by the user. I suppose there is no strict reason why 
  80.   global variables are needed here, except as a mere convenience. Since
  81.   several routines reference these variables, and since these routines 
  82.   are called at different times, I thought it would be easier to have
  83.   these two values stored as local globals (ie, only global to routines
  84.   resident in this file).
  85.  A third global variable, weight_range, was added at a later time. Its
  86.   main purpose is to speed up the process of assigning the random weights
  87.   for the network. The base is the difference between the maximum and 
  88.   minimum values.
  89. ----------------------------------------------------------------------
  90. */
  91. static Sint  weight_max, weight_min, weight_range;
  92.  
  93.  
  94. /*
  95. ======================================================================
  96.   ROUTINES IN WEIGHTS.C                                                   
  97. ======================================================================
  98.   The routines in this file are grouped below by function.  Each routine
  99.   is prefixed by the string "W_" indicating that it is defined in the 
  100.   "weights.c" file.  The types returned by the routines are also shown 
  101.   here so that cross checking is more easily done between these functions
  102.   and the other files which intern them.
  103.  
  104.  
  105.   Type Returned                 Routine                                 
  106.   -------------                 -------                                 
  107.                                                                       
  108.   WEIGHT ROUTINES                                                   
  109.     Weights *                   W_alloc_weights
  110.     int32                       W_set_decoder
  111.     void                        W_weight_range
  112.     Sint                        W_random_weight
  113.     void                        W_free_weights
  114.     void                        W_show_weights
  115.  
  116.   WEIGHT_LST ROUTINES
  117.     Weights_lst *               W_alloc_weights_lst
  118.     Weights_lst *               W_insert_before
  119.     Weights_lst *               W_insert_after
  120.     void                        W_free_weights_lst
  121. ======================================================================
  122. */
  123.  
  124.  
  125. Weights  *W_alloc_weights(ptr_source, ptr_target, ptr_layer_spec)
  126. Layer       *ptr_source, *ptr_target;
  127. Layer_spec  *ptr_layer_spec;
  128. /*
  129. ----------------------------------------------------------------------
  130.  This routine allocates a Weights structure with the correctly sized
  131.   weights array.  The size of the weights array is determined by the
  132.   two arguments 'source' and 'target' which are the numbers of nodes
  133.   in the source layer and target layer respectively.  The weights are
  134.   assumed to point FROM the source layer TO the target layer.
  135.  This routine must also determine whether or not the weights form a 
  136.   fully connected scheme or a pattern of connections. This is determined
  137.   by looking at the layer spec which is passed as the last argument.
  138.   This spec contains values for the pattern, if one was specified for
  139.   the source/target pair, stored in the "targets" array. NOTE THAT THIS
  140.   ARRAY will specify weights from the SOURCE to the TARGET, but the pattern
  141.   will relate to the LARGER of the two targets. Thus, two checks must be
  142.   made. First, a check must be made to find the larger of the two layers
  143.   so that the decoder matrix can be set for the correct layer, and second
  144.   it must be determined whether or not the pattern FITS THE TWO LAYERS.
  145.   The targets array must be searched in order to find the patterns 
  146.   corresponding to the correct source/target pair. If no pattern exists, 
  147.   then the result is a CONNECT_ALL scheme, otherwise it is a PATTERNED scheme.
  148.  Note that a weight array has no significance without two layers to
  149.   which the weights refer.  Thus, pointers to actual LAYER STRUCTURES
  150.   are passed as arguments to this function from which the size info
  151.   is extracted.
  152.  
  153.  If any problems occur during weight allocation, then the ERROR value
  154.   is returned as the "type" of the weights.
  155. ----------------------------------------------------------------------
  156. */
  157. BEGIN
  158.    int32    W_set_decoder(), i, num_weights;
  159.    int      s_size, t_size, j;
  160.    Weights  *result;
  161.    Sint     W_random_weight();
  162.  
  163.    /*---------------------------------------*/
  164.    /* get the source and target layer sizes */
  165.    /*---------------------------------------*/
  166.    s_size = ptr_source->num_nodes;
  167.    t_size = ptr_target->num_nodes;
  168.    
  169.    /*-------------------------------------*/
  170.    /* setup the default weights structure */
  171.    /*-------------------------------------*/
  172.    result = (Weights *) sys_alloc((unsigned)sizeof(Weights));
  173.    result->source_size  = s_size;
  174.    result->target_size  = t_size;
  175.    result->source_layer = ptr_source;
  176.    result->target_layer = ptr_target;
  177.    result->values      = NULL;
  178.    result->decoder     = NULL;
  179.    result->map_area    = 0;
  180.    result->prev_deltaW = NULL;
  181.  
  182.    /*----------------------------------*/
  183.    /* Find the value of "targets" that */
  184.    /* corresponds to the target layer  */
  185.    /*----------------------------------*/
  186.    for (j = 0; j < ptr_layer_spec->num_targets; j++)
  187.       if (ptr_layer_spec->targets[j][0] == ptr_target->ID)
  188.          break;
  189.          
  190.    /*----------------------------------------------*/
  191.    /* check to see that the target layer was found */
  192.    /*----------------------------------------------*/
  193.    if (j == ptr_layer_spec->num_targets) BEGIN
  194.       sprintf(IO_str, 
  195.               "\n*** INTERNAL ERROR: no TARGET in targets array for Layer %d to %d",
  196.               ptr_source->ID, ptr_target->ID);
  197.       IO_print(0);
  198.       result->type = ERROR;
  199.       return(result);
  200.    ENDIF
  201.    
  202.    /*-----------------------------------------------*/
  203.    /* Now find out the connection scheme used. if   */
  204.    /* targets not 0, then patterned connect is used */
  205.    /*-----------------------------------------------*/
  206.    if (ptr_layer_spec->targets[j][1] != 0) BEGIN      /* PATTERNED CONNECTION */
  207.       result->type = PATTERNED;
  208.       
  209.       /*------------------------------------------*/
  210.       /* set the function pointers depending upon */
  211.       /* a comparison of source and target sizes  */
  212.       /*------------------------------------------*/
  213.       if (s_size > t_size) BEGIN
  214.          result->f_prop   = P_s_pattern_dot_forward;
  215.          result->b_prop   = P_s_pattern_dot_backward;
  216.          result->w_update = P_s_pattern_update_wts;
  217.       ENDIF
  218.       else BEGIN
  219.          result->f_prop   = P_t_pattern_dot_forward;
  220.          result->b_prop   = P_t_pattern_dot_backward;
  221.          result->w_update = P_t_pattern_update_wts;
  222.       ENDELSE
  223.       
  224.       num_weights = W_set_decoder(s_size, t_size, result, ptr_layer_spec->targets[j]);
  225.       if (num_weights == 0) BEGIN
  226.          result->type = ERROR;
  227.          return(result);
  228.       ENDIF
  229.    ENDIF
  230.    
  231.    /*----------------------------------------*/
  232.    /* otherwise a connect-all scheme is used */
  233.    /*----------------------------------------*/
  234.    else BEGIN                                         /* FULLY CONNECTED      */
  235.       result->type = CONNECT_ALL;
  236.       num_weights = s_size * t_size;
  237.       
  238.       /*--------------------------------------------------*/
  239.       /* set function pointers for fully connected scheme */
  240.       /*--------------------------------------------------*/
  241.       result->f_prop   = P_full_dot_forward;
  242.       result->b_prop   = P_full_dot_backward;
  243.       result->w_update = P_full_update_wts;
  244.    ENDELSE
  245.    
  246.    /*--------------------------------------*/
  247.    /* allocate space for the weight values */
  248.    /* then set randomly and zero deltas.   */
  249.    /*--------------------------------------*/
  250.    result->values      = (Sint *) sys_long_alloc((long)(num_weights * sizeof(Sint)));
  251.    result->prev_deltaW = (Sint *) sys_long_alloc((long)(num_weights * sizeof(Sint)));
  252.    for (i = 0; i < num_weights; i++) BEGIN
  253.       result->values[i]      = W_random_weight();
  254.       result->prev_deltaW[i] = 0; 
  255.    ENDIF
  256.  
  257.    return(result);
  258.  
  259. END /* W_alloc_weights */
  260.  
  261.  
  262. void  W_free_weights(ptr_weights)
  263. Weights  *ptr_weights;
  264. /*
  265. ----------------------------------------------------------------------
  266.   Frees just a weights structure. Assumes that the corresponding 
  267.    weights_lst structure has been dealt with by the caller.
  268. ----------------------------------------------------------------------
  269. */
  270. BEGIN
  271.  
  272.    if (ptr_weights == NULL) return;
  273.    
  274.    /*------------------------*/
  275.    /* free values and deltas */
  276.    /*------------------------*/
  277.    sys_long_free((char *) ptr_weights->values);
  278.    sys_long_free((char *) ptr_weights->prev_deltaW);
  279.    
  280.    /*--------------------------------*/
  281.    /* free patterned info if present */
  282.    /*--------------------------------*/
  283.    if (ptr_weights->decoder != NULL)
  284.       sys_long_free((char *) ptr_weights->decoder);
  285.       
  286.    sys_free((char *) ptr_weights);
  287.  
  288. END /* W_free_weights */
  289.  
  290.  
  291. int32  W_set_decoder(s_size, t_size, ptr_weights, ptr_one_target)
  292. int      s_size, t_size;
  293. Weights  *ptr_weights;
  294. int16    ptr_one_target[];
  295. /*
  296. ----------------------------------------------------------------------
  297.   Returns the number of weights which should be allocated or 0 if some
  298.   error is detected.
  299.  
  300.   Some formulas concerning Nerual Net mappings between layers which
  301.   are other than fully connected.  The backprop net I have at this time
  302.   only allows for one kind of mapping: fully-connected.  The idea here
  303.   is to add some versatality to the connection scheme by allowing the
  304.   user to define "mapping areas" which would essentially model the 
  305.   mapping of nodes which are close together to the same node of the
  306.   intermediate layer.  Overlapping of these areas is permitted to
  307.   allow for border nodes to map to multiple intermediate nodes. The
  308.   idea is to specify two layers, one larger than the other, of 
  309.   dimension M x N (smaller) and U x V (larger).  Then, a mapping area
  310.   is defined of size P x Q and overlap R x S.  The R overlap is in 
  311.   the P dimension and can be at most P-1 (and the R, S-1). The following
  312.   describes how to translate between the weight number and the nodes
  313.   of the LARGER layer.  To map to the smaller layer is easy: you just
  314.   use (weight# DIV mapping-area).
  315.  
  316.   Note the following formulas:
  317.     M x N   smaller layer dimensions
  318.     U x V   larger layer dimensions
  319.     P x Q   mapping rectangle dimensions
  320.     R x S   overlap of mapping rectangles, in x,y dimensions respectively
  321.  
  322.   This gives the following relationships between M-U and N-V:
  323.     U = P + [(P - R) * (M - 1)]
  324.     V = Q + [(Q - S) * (N - 1)]
  325.  
  326.     or
  327.  
  328.     M = 1 + [(U - P) / (P - R)]
  329.     N = 1 + [(V - Q) / (Q - S)]
  330.  
  331.   Now, given a weight number (the number of weights = P * Q * M * N) 
  332.   we can determine the corresponding node of the input and output layers
  333.   as follows.  First, note that each mapping can be considered to start
  334.   at some point and have a series of rows each the same length.  In 
  335.   addition, these rows will be separated in the Y direction by a distance
  336.   of exactly U (the x dimension of the larger layer). Finally, each
  337.   mapping area is separated in the X direction depending upon the P and
  338.   R values; ie, the width minus the overlap. Thus, if we call the 
  339.   starting node of an area Ts (for "Top start"), then each mapping area
  340.   is separated by P - R in the X direction and Q - S in the Y direction.
  341.   This gives Ts = (row in small layer) * U * (Q-S) as the start of the
  342.   area and Ts + (row in map area) * U as the start of the row which 
  343.   has the node connected to the weight in question. In the column (or X)
  344.   direction, we need to "jump" over the correct number of areas (which
  345.   corresponds to the column number of the smaller layer) and then add
  346.   in the number of columns into the mapping area. This first value is
  347.   Ts + [(col in small layer) * P] - [(col in small layer) * R]. Finally,
  348.   the column of the mapping area is added in. Here are the formulas for
  349.   this calculation:
  350.  
  351.    area-of-map        = P * Q
  352.    area-number        = weight# DIV area-of-map
  353.    row-in-small-layer = area-number DIV M
  354.    col-in-small-layer = area-number MOD M
  355.    row-in-map-area    = (weight# MOD area-of-map) DIV P
  356.    col-in-map-area    = weight# MOD P
  357.  
  358.    start-row-of-map   = row-in-small-layer * U * (Q-S)
  359.    rows-into-the-map  = row-in-map-area * U
  360.    start-col-of-map   = col-in-small-layer * (P-R)
  361.    cols-into-the-map  = col-in-map-area
  362.    FINAL RESULT       = (start-row-of-map + rows-into-map)
  363.                         + (start-col-of-map + cols-into-map)
  364.  
  365.   NOTE: the last parameter is a pointer to a ROW of integers of the
  366.   "targets" array of some layer spec. This amounts to being a list of
  367.   the P, Q, R, and S values for the pattern. Only this row is important,
  368.   thus it may be passed in as "ptr_layer_spec->targets[i]" where "i"
  369.   is the index of the desired target. The result is one row of the targets
  370.   array of the layer spec with dimension 5 (see definition of a layer spec).
  371.  
  372.   NOTE: see documentation under 'PS_get_layer'
  373. ----------------------------------------------------------------------
  374. */
  375. BEGIN
  376.    int32  i, M, N, U, V, P, Q, R, S, area, num_weights, area_num;
  377.    int32  start_row_map, rows_into_map, start_col_map, cols_into_map;
  378.    int16  *decode_list;
  379.  
  380.    if (s_size > t_size) BEGIN
  381.       M = (int32) ptr_weights->target_layer->X_dim;
  382.       N = (int32) ptr_weights->target_layer->Y_dim;
  383.       U = (int32) ptr_weights->source_layer->X_dim;
  384.       V = (int32) ptr_weights->source_layer->Y_dim;
  385.    ENDIF
  386.    else BEGIN
  387.       M = (int32) ptr_weights->source_layer->X_dim;
  388.       N = (int32) ptr_weights->source_layer->Y_dim;
  389.       U = (int32) ptr_weights->target_layer->X_dim;
  390.       V = (int32) ptr_weights->target_layer->Y_dim;
  391.    ENDELSE
  392.    P = (int32) ptr_one_target[1];
  393.    Q = (int32) ptr_one_target[2];
  394.    R = (int32) ptr_one_target[3];
  395.    S = (int32) ptr_one_target[4];
  396.    if ((U != (P + ((P-R) * (M-1)))) 
  397.        || (V != (Q + ((Q-S) * (N-1))))) BEGIN
  398.       sprintf(IO_str, "\n*** ERROR: Layer %d will not map evenly to layer %d",
  399.              ptr_weights->source_layer->ID, ptr_weights->target_layer->ID);
  400.       IO_print(0);
  401.       sprintf(IO_str, "\n\nUse the following formulas:");
  402.       IO_print(0);
  403.       sprintf(IO_str, "\n   X_big_layer = X_pattern + (X_pattern - X_overlap) * (X_small_layer - 1)");
  404.       IO_print(0);
  405.       sprintf(IO_str, "\n   Y_big_layer = Y_pattern + (Y_pattern - Y_overlap) * (Y_small_layer - 1)");
  406.       IO_print(0);
  407.       sprintf(IO_str, "\n\nNet specification produced the following:");
  408.       IO_print(0);
  409.       sprintf(IO_str, "\n   X_big_layer=%ld;  X_pattern=%ld;  X_overlap=%ld;  X_small_layer=%ld",
  410.              U, P, R, M); 
  411.       IO_print(0);
  412.       sprintf(IO_str, "\n   Y_big_layer=%ld;  Y_pattern=%ld;  Y_overlap=%ld;  Y_small_layer=%ld\n",
  413.              V, Q, S, N);
  414.       IO_print(0); 
  415.       return(0);
  416.    ENDIF
  417.    area = P * Q;
  418.    num_weights = area * M * N;
  419.    decode_list = (int16 *) sys_long_alloc((long)(num_weights * sizeof(int16)));
  420.    ptr_weights->decoder = decode_list;
  421.    for (i = 0; i < num_weights; i++) BEGIN
  422.       area_num = i / area;
  423.       start_row_map = (area_num / M) * U * (Q - S); 
  424.       rows_into_map = ((i % area) / P) * U;
  425.       start_col_map = (area_num % M) * (P - R);
  426.       cols_into_map = (i % P);
  427.       *decode_list++ = (int16)(start_row_map + rows_into_map 
  428.                                + start_col_map + cols_into_map);
  429.    ENDFOR
  430.    ptr_weights->map_area = (int) area;
  431.    return(num_weights);
  432.  
  433. END  /* W_set_decoder */
  434.  
  435.  
  436. void W_weight_range(max_wts)
  437. int  max_wts;
  438. /*
  439. ----------------------------------------------------------------------
  440.  This routine calculates the range of allowable weight values, given  
  441.   a number indicating the maximum number of weights coming into a     
  442.   node in the net.  The formula for this calculation is:              
  443.       10 = .5 * (num_wts) * (maximum allowable weight)                
  444.   for more discussion on the above formula, see the documentation with
  445.   'check_layer_sizes' in buildnet.c                                        
  446.  All that is done here is to make the calculation, solving for the    
  447.   maximum allowable weights, and store the result in 'weight_max'     
  448.   which is visible in this file only.                        
  449. ----------------------------------------------------------------------
  450. */
  451. BEGIN
  452.    char   temp_str[MAX_WORD_SIZE];
  453.    float  result, temp, min_weight_value;
  454.    
  455.    /*-------------------------------------*/
  456.    /* precalculate default minimum weight */
  457.    /*-------------------------------------*/
  458.    min_weight_value = 1.0 / ((float)WTS_SCALE);
  459.  
  460.    /*----------------------------------*/
  461.    /* calculate default maximum weight */
  462.    /*----------------------------------*/
  463.    result = temp = (10.0 / 0.5 / (float)max_wts);
  464.    if (result < min_weight_value)
  465.       result = min_weight_value;
  466.    
  467. #if  !DELIVERY
  468.    /*-------------------------------------*/
  469.    /* if not in DELIVERY mode, prompt the */
  470.    /* user using temp as a default        */
  471.    /*-------------------------------------*/
  472.    sprintf(IO_wkstr, "\n   Enter maximum weight value(default =%%.f): ");
  473.    IO_insert_format(IO_wkstr);
  474.    sprintf(IO_str, IO_wkstr, temp);
  475.    IO_print(0);
  476.    IO_my_get_string(temp_str);
  477.    if (temp_str[0] != ENDSTRING)
  478.       if (sscanf(temp_str, "%f", &result) != 1) BEGIN
  479.          sprintf(IO_str, "\n   sorry, I don't understand.  Try again: ");
  480.          IO_print(0);
  481.          result = IO_my_get_float();
  482.       ENDIF
  483.    /*-----------------------------------------*/
  484.    /* check if the value given is appropriate */
  485.    /* Use default in such a case              */
  486.    /*-----------------------------------------*/
  487.    if ((result > 32.0) || (result <= 0)) BEGIN
  488.       sprintf(IO_str, "   OUT OF RANGE(> 0, <= 32). Default value used.");
  489.       IO_print(0);
  490.       result = temp;
  491.    ENDIF
  492. #endif
  493.  
  494.    /*--------------------------------------------*/
  495.    /* in any event, set the weight max to result */
  496.    /* and set result to the minimum weight value */
  497.    /*--------------------------------------------*/
  498. #if  USE_SCALED_INTS
  499.    weight_max = (Sint)(result * (float)SINT_SCALE);
  500. #else
  501.    weight_max = result;
  502. #endif
  503.    result = min_weight_value;
  504.    
  505. #if  !DELIVERY
  506.    /*--------------------------------------------*/
  507.    /* if not delivery, prompt a second round for */
  508.    /* the minimum weight value. Put valin result */
  509.    /*--------------------------------------------*/
  510.    sprintf(IO_wkstr, "\n   Enter minimum weight value(default =%%.f): ");
  511.    IO_insert_format(IO_wkstr);
  512.    sprintf(IO_str, IO_wkstr, result);
  513.    IO_print(0);
  514.    IO_my_get_string(temp_str);
  515.    if (temp_str[0] != ENDSTRING)
  516.       if (sscanf(temp_str, "%f", &result) != 1) BEGIN
  517.       sprintf(IO_str, "\n   sorry, I don't understand.  Try again: ");
  518.       IO_print(0);
  519.       result = IO_my_get_float();
  520.    ENDIF
  521.    /*-----------------------------------------*/
  522.    /* check if the value given is not in the  */
  523.    /* appropriate. Use default in such a case */
  524.    /*-----------------------------------------*/
  525.    if ((result >= 32.0) || (result < 0)) BEGIN
  526.       sprintf(IO_str, "   OUT OF RANGE(>= 0, <= 32). Default value used.");
  527.       IO_print(0);
  528.       result = min_weight_value;
  529.    ENDIF
  530. #endif
  531.  
  532.    /*----------------------------------*/
  533.    /* set the minimum weight to result */
  534.    /*----------------------------------*/
  535. #if  USE_SCALED_INTS
  536.    weight_min = (Sint)(result * (float)SINT_SCALE);
  537. #else
  538.    weight_min = result;
  539. #endif
  540.    
  541.    /*------------------------------------*/
  542.    /* if max < min, then set base to min */
  543.    /* Otherwise, leave it as max - min   */
  544.    /*------------------------------------*/
  545.    if ((weight_range = weight_max - weight_min) <= 0) BEGIN
  546.       weight_range = weight_max;
  547.       weight_min = 0;
  548.    ENDIF
  549.  
  550. END /* W_weight_range */
  551.  
  552.  
  553. Sint  W_random_weight()
  554. /*
  555. ----------------------------------------------------------------------
  556.  returns a positive or negative random number between weight_max and  
  557.   weight_min.                                                         
  558. ----------------------------------------------------------------------
  559. */
  560. BEGIN      
  561.    D_Sint  temp;
  562.    
  563. #if  USE_SCALED_INTS
  564.    /*-------------------------------------------*/
  565.    /* for integers, we generate a random weight */
  566.    /* by using the weight_range as a MOD value  */
  567.    /* on the rand function. This works since we */
  568.    /* know rand returns int and we know Sints   */
  569.    /* are 16-bits long.                         */
  570.    /*-------------------------------------------*/
  571.    temp = (D_Sint)(rand() % weight_range + weight_min);
  572.    
  573.    /*------------------------------------------*/
  574.    /* rand is again used to determine the sign */
  575.    /*------------------------------------------*/
  576.    if ((rand() % 1000) > 500)
  577.       temp = temp * -1;
  578.    
  579.    /*--------------------------------------------------*/
  580.    /* the result is converted to a Sint by multiplying */
  581.    /* by the scale factor and dividing by precision    */
  582.    /*--------------------------------------------------*/
  583.    return( (Sint)((temp * SINT_SCALE) / WTS_SCALE) );
  584. #else
  585.    /*-------------------------------------------*/
  586.    /* divide a random number by a number large  */
  587.    /* enough to make the result between 0 and 1 */
  588.    /* Note the "%" mod operator which keeps the */
  589.    /* results of the rand small enough to make  */
  590.    /* sure the divide returns a number < 1.     */
  591.    /* Most rand functions return a number from  */
  592.    /* 0 - 32767 but some (like the VAX) don't.  */
  593.    /*-------------------------------------------*/
  594.    temp = (float)(rand() % 32768) / (float)(1L<<15);
  595.       
  596.    /*---------------------------------------------*/
  597.    /* convert temp to a weight by multiplying it  */
  598.    /* by the range of possible weights and adding */
  599.    /* that to the minimum weight value.           */
  600.    /*---------------------------------------------*/
  601.    temp = weight_min + weight_range * temp;
  602.  
  603.    /*--------------------------------------*/
  604.    /* then pull the same old trick to make */
  605.    /* it randomly positive or negative.    */
  606.    /*--------------------------------------*/
  607.    if ((rand() % 1000) > 500)
  608.       temp = temp * -1;
  609.    return((Sint)temp);
  610. #endif
  611.  
  612. END /* W_random_weight */
  613.  
  614.  
  615. Weights_lst  *W_alloc_weights_lst(ptr_weights)
  616. Weights  *ptr_weights;
  617. /*
  618. ----------------------------------------------------------------------
  619.  Given a pointer to a Weights structure, this routine allocates a     
  620.   Weights_lst structure and assigns its 'value' field to the incoming 
  621.   argument.  As with other routines like this one (see layer.h), the  
  622.   unassigned pointers are set to NULL.                                
  623. ----------------------------------------------------------------------
  624. */
  625. BEGIN
  626.    Weights_lst  *result;
  627.  
  628.    result = (Weights_lst *) sys_alloc((unsigned)sizeof(Weights_lst));
  629.    result->value = ptr_weights;
  630.    result->next  = NULL;
  631.  
  632.    return(result);
  633.  
  634. END /* W_alloc_weights_lst */
  635.  
  636.  
  637. Weights_lst  *W_insert_before(ptr_node, ptr_lst)
  638. Weights_lst  *ptr_node, *ptr_lst;
  639. /*
  640. ----------------------------------------------------------------------
  641.  As with the layer.h routines, this guy takes in two arguments, one   
  642.   which is a pointer to a new element to be inserted into the list    
  643.   indicated by the second argument.  The second argument is assumed   
  644.   to be pointing to the element BEFORE WHICH the new node should be   
  645.   inserted. (see documentation for L_insert_before).                  
  646. ----------------------------------------------------------------------
  647. */
  648. BEGIN
  649.    if (ptr_node == NULL)
  650.       return(ptr_lst);
  651.    else if (ptr_lst == NULL)
  652.       return(ptr_node);
  653.    else BEGIN
  654.       ptr_node->next = ptr_lst;        /* set up new node pointer     */
  655.       return(ptr_node);                /* return ptr to inserted node */
  656.    ENDELSE
  657.  
  658. END /* W_insert_before */
  659.  
  660.  
  661. Weights_lst  *W_insert_after(ptr_node, ptr_lst)
  662. Weights_lst  *ptr_node, *ptr_lst;
  663. /*
  664. ----------------------------------------------------------------------
  665.  As with the layer.h routines, this guy takes in two arguments, one   
  666.   which is a pointer to a new element to be inserted into the list    
  667.   indicated by the second argument.  The second argument is assumed   
  668.   to be pointing to the element AFTER WHICH the new node should be    
  669.   inserted. (see documentation for L_insert_after).                   
  670. ----------------------------------------------------------------------
  671. */
  672. BEGIN
  673.    if (ptr_node == NULL)
  674.       return(ptr_lst);
  675.    else if (ptr_lst == NULL)
  676.       return(ptr_node);
  677.    else BEGIN
  678.       ptr_node->next = ptr_lst->next;  /* set up new node pointer     */
  679.       ptr_lst->next  = ptr_node;       /* reset prev node next ptr    */
  680.       return(ptr_lst);                 /* return ptr to list          */
  681.    ENDELSE
  682.  
  683. END /* W_insert_after */
  684.  
  685.  
  686. void  W_free_weights_lst(ptr_lst)
  687. Weights_lst  *ptr_lst;
  688. /*
  689. ----------------------------------------------------------------------
  690.   Frees the weights list structures and the corresponding weight arrays
  691.    to which the list elements refer.
  692. ----------------------------------------------------------------------
  693. */
  694. BEGIN
  695.    void          W_free_weights();
  696.    Weights_lst  *last;
  697.    
  698.    if (ptr_lst == NULL) return;
  699.    
  700.    while (ptr_lst != NULL) BEGIN
  701.       W_free_weights(ptr_lst->value);
  702.       last = ptr_lst;
  703.       ptr_lst = ptr_lst->next;
  704.       sys_free((char *) last);
  705.    ENDWHILE
  706.  
  707. END /* W_free_weights_lst */
  708.  
  709.  
  710. void  W_show_weights(ptr_weights)
  711. Weights  *ptr_weights;
  712. /*
  713. ----------------------------------------------------------------------
  714.  Given a pointer to a set of weights, this guy prints out the weight  
  715.   values in COLUMN major order (because that is how we assume the 2-d 
  716.   array is stored in 1-d format).  Thus, if we had a set of weights   
  717.   between layer A and layer B we would see weights in the following   
  718.   order:  A1,B1; A2,B1; A3,B1;...A1,B2; A2,B2; A3,B2;...An-1,Bm;      
  719.   An,Bm  where 'n' and 'm' are the sizes of layers A and B respec-    
  720.   tively (when the connection scheme is CONNECT_ALL).
  721.  Since our array is stored COLUMN MAJOR, we consider adjacent elements
  722.   to be in the same column.  We use our first index, j, to indicate   
  723.   which column we are on (starting with 0).  Now, moving from one     
  724.   column to the next is tricky, because it has to do with the ROW SIZE
  725.   and not the column size.  Think of it this way: for each set of     
  726.   values, we want to print out i, or 's_size', elements.  Then we want
  727.   to jump to the next set of values.  Since we just printed s_size    
  728.   elements, it makes sense to jump s_size elements down and start the 
  729.   whole thing again.  't_size' only has relevance in knowing HOW MANY 
  730.   TIMEs to do the jumping!!!                
  731.  If the connection scheme is PATTERNED, then the printout follows the
  732.   smaller of the two layers. That is, since the weights are stored in
  733.   relation to the smaller layer (in groups of 'map_area' size), the 
  734.   printout also follows this format. 
  735. ----------------------------------------------------------------------
  736. */
  737. BEGIN
  738.    int    i, j, s_size, t_size, area;
  739.    Sint   *wt_values;
  740.    int16  *ptr_decoder;
  741.    float  t1;                    /* temporary value for Sint conversion */
  742.  
  743.    s_size = ptr_weights->source_size;
  744.    t_size = ptr_weights->target_size;
  745.    
  746.    if (ptr_weights->type == CONNECT_ALL)
  747.       for (j = 0; j < t_size; j++) BEGIN
  748.          for (i = 0; i < s_size; i++) BEGIN
  749.             t1 = C_Sint_to_float( ptr_weights->values[i + (j * s_size)] );
  750.             sprintf(IO_wkstr, "weight %d,%d = %%.f  ", i, j);
  751.             IO_insert_format(IO_wkstr);
  752.             sprintf(IO_str, IO_wkstr, t1);
  753.             if (IO_more(0) == ERROR) return;
  754.             if ((i+1) % 3 == 0) BEGIN
  755.                sprintf(IO_str, "\n");
  756.                if(IO_more(0) == ERROR) return;
  757.             ENDIF
  758.          ENDFOR
  759.          sprintf(IO_str, "\n\n");
  760.          if(IO_more(0) == ERROR) return;
  761.       ENDFOR
  762.    else BEGIN
  763.       area      = ptr_weights->map_area;
  764.       wt_values = ptr_weights->values;
  765.       ptr_decoder = ptr_weights->decoder;
  766.       if (t_size < s_size)
  767.          for (j = 0; j < t_size; j++) BEGIN
  768.             for (i = 0; i < area; i++) BEGIN
  769.                t1 = C_Sint_to_float(*wt_values++);
  770.                sprintf(IO_wkstr, "weight %d,%d = %%.f  ", *ptr_decoder++, j);
  771.                IO_insert_format(IO_wkstr);
  772.                sprintf(IO_str, IO_wkstr, t1);
  773.                if(IO_more(0) == ERROR) return;
  774.                if ((i+1) % 3 == 0) BEGIN
  775.                   sprintf(IO_str, "\n");
  776.                   if(IO_more(0) == ERROR) return;
  777.                ENDIF
  778.             ENDFOR
  779.             sprintf(IO_str, "\n\n");
  780.             IO_print(0);
  781.             if(IO_more(0) == ERROR) return;
  782.          ENDFOR
  783.       else
  784.          for (i = 0; i < s_size; i++) BEGIN
  785.             for (j = 0; j < area; j++) BEGIN
  786.                t1 = C_Sint_to_float(*wt_values++);
  787.                sprintf(IO_wkstr, "weight %d,%d = %%.f  ", i, *ptr_decoder++);
  788.                IO_insert_format(IO_wkstr);
  789.                sprintf(IO_str, IO_wkstr, t1);
  790.                if(IO_more(0) == ERROR) return;
  791.                if ((j+1) % 3 == 0) BEGIN
  792.                   sprintf(IO_str, "\n");
  793.                   if(IO_more(0) == ERROR) return;
  794.                ENDIF
  795.             ENDFOR
  796.             sprintf(IO_str, "\n\n");
  797.             if(IO_more(0) == ERROR) return;
  798.          ENDFOR
  799.    ENDELSE
  800.  
  801. END /* W_show_weights */
  802.