"Fossies" - the Fresh Open Source Software Archive

Member "Pansophica-src-1.3/BAF_modules/som_lvq/src/br_som.c" (1 Feb 2008, 47235 Bytes) of package /linux/www/old/Pansophica-src-1.3-1.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "br_som.c" see the Fossies "Dox" file reference documentation.

    1 /******************************************************************************
    2 
    3  Pansophica, An intelligent, virtual-reality, web search agent
    4  Copyright (C) MMVIII, NeuralVR Technologies Ltd.
    5 
    6  This program is free software: you can redistribute it and/or modify
    7  it under the terms of the GNU General Public License as published by
    8  the Free Software Foundation, either version 3 of the License, or
    9  (at your option) any later version.
   10 
   11  This program is distributed in the hope that it will be useful,
   12  but WITHOUT ANY WARRANTY; without even the implied warranty of
   13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   14  GNU General Public License for more details.
   15 
   16  You should have received a copy of the GNU General Public License
   17  along with this program.  If not, see http://www.gnu.org/licenses/.
   18 
   19  MODULE: br_som.c
   20  $Id: br_som.c,v 1.11 2008/02/01 18:23:07 dean Exp $
   21 
   22  SYNOPSIS
   23  Routines for learning, thinking and labeling a som
   24 
   25  HISTORY
   26  $Log: br_som.c,v $
   27  Revision 1.11  2008/02/01 18:23:07  dean
   28  first GPL, mac ready
   29 
   30  Revision 1.10  2003/11/17 21:23:07  dean
   31  incremental work on wget mod
   32 
   33  Revision 1.9  2003/11/14 04:29:04  dean
   34  ERROR and CLEANUP tags with BAF_ prefix
   35 
   36  Revision 1.8  2003/11/13 20:18:06  dean
   37  removal of generic macros that collide on Windows, BAF_ prefix
   38 
   39  Revision 1.7  2003/11/05 21:49:26  dean
   40  most of the way there
   41 
   42  Revision 1.6  2003/10/22 03:55:17  dean
   43  updated copyrighting licensing
   44 
   45  Revision 1.5  2003/04/29 23:07:31  dean
   46  updated to redhat 9 build
   47 
   48  Revision 1.4  1999/10/15 23:09:32  dean
   49  module re-entrancy guard placed inside this file
   50 
   51  Revision 1.3  1999/09/23 19:41:56  dean
   52  added definition req'd by new non-reentrancy guard
   53 
   54  Revision 1.2  1999/01/26 20:48:53  dean
   55  replacement of util_mem calls with macros
   56 
   57  Revision 1.1.1.1  1999/01/21 20:42:51  dean
   58  initial import of the new BAF_modules
   59 
   60  Revision 1.17  1998/12/04 18:30:18  dean
   61  Added NPL notice
   62 
   63 
   64  IncrDev Jun 11, 98 by dab: added umat module
   65  Created Apr 30, 98 by dab: amalgamated three modules into one
   66 
   67  NOTES
   68  Consists of thre folllowing modules:
   69      br_learn,
   70      br_think,
   71      br_label, and
   72      br_umat.
   73  
   74  See relevant sections for details.
   75 
   76 ******************************************************************************/
   77 
   78 #include <stdio.h>
   79 #include <math.h>
   80 #include <float.h>
   81 #include <string.h>
   82 #include "modules_defs.h"
   83 #include "br_som_defs.h"
   84 /* : for the som stuff */
   85 #include "lvq_pak.h"
   86 #include "som_rout.h"
   87 #include "datafile.h"
   88 
   89 /* : a buffer for reading the data files */
   90 /* #define BUFFER_SIZE 1000 */
   91 #define BUFFER_SIZE 0
   92 
   93 /* : actions */
   94 #define BR_LRN_LEARN "learn"
   95 #define BR_LRN_INIT "init"
   96 #define BR_LRN_QERROR "qerror"
   97 #define BR_THK_THINK "think"
   98 #define BR_LAB_LABEL "label"
   99 
  100 /* : use zero here to get all the labels */
  101 #define BR_LAB_NUM_LABELS 0
  102 
  103 /* : for string matching on params */
  104 #define TOPOL_HEXA_STR "hexa"
  105 #define TOPOL_RECT_STR "rect"
  106 #define NEIGH_BUBBLE_STR "bubble"
  107 #define NEIGH_GAUSSIAN_STR "gauss"
  108 
  109 /* : for our lack of reentrancy ... lock_get and lock_release */
  110 
  111 
  112 /* : global for entrancy blocking */
  113 THREAD_MUTEX_REF g_br_som_mod_mutex = NULL;
  114 
  115 /******************************************************************************
  116 
  117  FUNCTION: mod_lock_get
  118 
  119  SYNOPSIS:
  120  This module is not re-entrant so we'll block until we're exclusive.
  121 
  122 ******************************************************************************/
  123 
  124 static int 
  125 br_som_mod_lock_get(
  126 void
  127 )
  128 {
  129   BAF_IN(PRIVATE);
  130 
  131   /* : get it */
  132   BAF_CATCH( thread_mutex_lock( g_br_som_mod_mutex ) ) {
  133     BAF_ERROR();
  134   }
  135 
  136   BAF_OUT(PRIVATE);
  137 
  138 
  139  BAF_ERROR:
  140 
  141   BAF_THROW();
  142 }
  143 
  144 
  145 /******************************************************************************
  146 
  147  FUNCTION: mod_lock_release
  148 
  149  SYNOPSIS:
  150  Releases our lock on the module
  151 
  152  HISTORY:
  153 
  154 ******************************************************************************/
  155 
  156 static int 
  157 br_som_mod_lock_release(
  158 void
  159 )
  160 {
  161   BAF_IN(PRIVATE);
  162 
  163   /* : get it */
  164   BAF_CATCH( thread_mutex_unlock( g_br_som_mod_mutex ) ) {
  165     BAF_ERROR();
  166   }
  167 
  168   BAF_OUT(PRIVATE);
  169 
  170 
  171  BAF_ERROR:
  172 
  173   BAF_THROW();
  174 }
  175 
  176 
  177 /******************************************************************************
  178 
  179  FUNCTION: br_som_atexit
  180 
  181  SYNOPSIS:
  182  Disposes the mutex when the module unloads
  183 
  184  HISTORY:
  185 
  186 ******************************************************************************/
  187 
  188 void
  189 br_som_atexit(
  190 void
  191 )
  192 {
  193   if ( g_br_som_mod_mutex ) 
  194     thread_mutex_dispose( &g_br_som_mod_mutex );
  195 
  196   return;
  197 }
  198 
  199 
  200 /******************************************************************************
  201 
  202  FUNCTION: br_som_init
  203 
  204  SYNOPSIS:
  205  Initializes a mutex when the module loads
  206 
  207  HISTORY:
  208 
  209 ******************************************************************************/
  210 
  211 void
  212 br_som_init(
  213 void
  214 )
  215 {
  216   MSG(PRIVATE,"br_som_init in");
  217 
  218   if ( g_br_som_mod_mutex == NULL ) {
  219     BAF_CATCH( thread_mutex_new( &g_br_som_mod_mutex ) ) {
  220       BAF_ERROR();
  221     }
  222     atexit( br_som_atexit );
  223   }
  224 
  225   MSG(PRIVATE,"br_som_init out");
  226   return;
  227 
  228 
  229  BAF_ERROR:
  230 
  231   MSG(PUBLIC,"br_som_init fails");
  232   return;
  233 }
  234 
  235 
  236 /******************************************************************************
  237 
  238  FUNCTION: br_som_fini
  239 
  240  SYNOPSIS:
  241  Disposes the mutex when the module unloads
  242 
  243  HISTORY:
  244 
  245 ******************************************************************************/
  246 
  247 void
  248 br_som_fini(
  249 void
  250 )
  251 {
  252   MSG(PRIVATE,"br_som_fini in");
  253 
  254   // since this is now static, this goes here
  255   MSG(PRIVATE,"br_som_fini out");
  256   return;
  257   
  258   // used to do this ...
  259   BAF_CATCH( thread_mutex_dispose( &g_br_som_mod_mutex ) ) {
  260     BAF_ERROR();
  261   }
  262   g_br_som_mod_mutex = NULL;
  263 
  264   MSG(PRIVATE,"br_som_fini out");
  265   return;
  266 
  267 
  268  BAF_ERROR:
  269 
  270   MSG(PUBLIC,"br_som_fini fails");
  271   return;
  272 }
  273 
  274 
  275 /******************************************************************************
  276 
  277  (c) MMIII, NeuralVR Technologies Ltd., All Rights Reserved.
  278 
  279  MODULE: br_learn.c
  280 
  281  SYNOPSIS
  282  Trains a som
  283 
  284  HISTORY
  285  Created Apr 13, 98 by dab
  286 
  287  NOTES
  288  Three actions:  'init', 'learn', and 'qerror'.
  289 
  290  init
  291  ----
  292  Linearly inits a new som so that it will provide a good distribution of the
  293  data sample within the bounds of the som.
  294       s - type of init, can be 'lininit' or 'randinit'
  295       d - x dimension
  296     d - y dimension
  297     s - topology ( rect or hexa )
  298     s - neighbourhood ( bubble or guassian )
  299     s - path to data file
  300     s - path to code page file
  301 
  302  Returns the qerror.
  303 
  304  learn
  305  -----
  306  Trains the som.
  307     s - path to data file
  308     s - path to code page file
  309     d - length of learning run
  310     f - rate of learning run
  311     f - radius of learning run
  312 
  313  Returns the qerror
  314 
  315  qerror
  316  ------
  317  Evaluates the qerror.  Called internally in init and learn, but can be 
  318  called separately here ( for the start of a re-train for instance ).
  319     s - path to data file
  320     s - path to code page file
  321 
  322  Returns the qerror
  323 
  324 ******************************************************************************/
  325 
  326 /* : for results */
  327 typedef enum {
  328   BR_LRN_OK,
  329   BR_LRN_FAIL,
  330   BR_LRN_BAD_PARAMS,
  331   BR_LRN_CANT_INIT_NET,
  332   BR_LRN_CANT_LEARN,
  333   BR_LRN_CANT_RETURN_QERROR,
  334   BR_LRN_CANT_REPLY,
  335   BR_LRN_UNSUPPORTED
  336 } BR_LRN_RES;
  337 
  338 static char *br_lrn_s_error[] = {
  339   "br_lrn no error",
  340   "br_lrn general failure",
  341   "br_lrn bad parameters",
  342   "br_lrn can't prepare neural net",
  343   "br_lrn can't learn",
  344   "br_lrn can't return q_error",
  345   "br_lrn can't reply",
  346   "br_lrn unsupported"
  347 };
  348 
  349 /* : structs to pass around privately */
  350 typedef struct {
  351   float rate;
  352   float radius;
  353   int length;
  354 } BR_LRN_RUN;
  355 
  356 typedef struct {
  357   char *init_type;
  358   int xdim;
  359   int ydim;
  360   char *topol;
  361   char *neigh;
  362   char *data_path;
  363   char *code_path;
  364   BR_LRN_RUN learn;
  365   float qerror;
  366   struct entries *data;
  367   struct entries *codes;
  368 } BR_LRN_INFO, *BR_LRN_INFO_PTR;
  369 
  370 
  371 /******************************************************************************
  372 
  373  FUNCTION: br_lrn_q_error
  374 
  375  SYNOPSIS
  376  Calculates the q_error on the given code file
  377 
  378  HISTORY
  379  Created  by dab
  380 
  381 ******************************************************************************/
  382 
  383 BR_LRN_RES
  384 br_lrn_q_error(
  385 BR_LRN_INFO_PTR info
  386 )
  387 {
  388   long nod = 0;
  389   struct teach_params teach;
  390   int qmode = 0;
  391   float qerror = 0;
  392   
  393   BAF_IN(PRIVATE);
  394 
  395   teach.radius = 1.0;
  396   qmode = 0;
  397 
  398   label_not_needed(1);
  399 
  400   info->data = open_entries( info->data_path );
  401   if ( info->data == NULL ) {
  402     BAF_ERROR_MSG("can't open data");
  403   }
  404 
  405   info->codes = open_entries( info->code_path );
  406   if ( info->codes == NULL ) {
  407     BAF_ERROR_MSG("can't open codes");
  408   }
  409 
  410   if ( info->codes->topol < TOPOL_HEXA ) {
  411     BAF_ERROR_MSG("no topology in codes file" );
  412   }
  413 
  414   if ( info->data->dimension != info->codes->dimension ) {
  415     BAF_ERROR_MSG("data-code dimensin mis-match" );
  416   }
  417 
  418   set_teach_params( &teach, info->codes, info->data, BUFFER_SIZE );
  419   set_som_params( &teach );
  420 
  421   qerror = find_qerror( &teach );
  422 
  423   nod = teach.data->num_entries;
  424   info->qerror = qerror / (float) nod;
  425 
  426   if ( info->data != NULL ) {
  427     close_entries( info->data );
  428     info->data = NULL;
  429   }
  430   if ( info->codes != NULL ) {
  431     close_entries( info->codes );
  432     info->data = NULL;
  433   }
  434 
  435   BAF_OUT(PRIVATE);
  436 
  437 
  438  BAF_ERROR:
  439 
  440   if ( info->data != NULL ) {
  441     close_entries( info->data );
  442     info->data = NULL;
  443   }
  444   if ( info->codes != NULL ) {
  445     close_entries( info->codes );
  446     info->data = NULL;
  447   }
  448 
  449   BAF_THROW();
  450 }
  451 
  452 
  453 /******************************************************************************
  454 
  455  FUNCTION: br_lrn_init
  456 
  457  SYNOPSIS
  458  Sets up the som for learning
  459 
  460  HISTORY
  461  Created Apr 14, 98 by dab
  462 
  463 ******************************************************************************/
  464 
  465 BR_LRN_RES
  466 br_lrn_init(
  467 BR_LRN_INFO_PTR info
  468 )
  469 {
  470   int noc = 0;
  471   int topol = 0;
  472   int neigh = 0;
  473 
  474   BAF_IN(PRIVATE);
  475 
  476   /* the topology type of the map */
  477   /* : get the topology */
  478   if ( strcmp ( info->topol, TOPOL_RECT_STR ) == 0 ) {
  479     topol = TOPOL_RECT;
  480   }
  481   else {
  482     topol = TOPOL_HEXA;
  483   }
  484 
  485   /* : neighborhood */
  486   if ( strcmp( info->neigh, NEIGH_GAUSSIAN_STR ) == 0 ) {
  487     neigh = NEIGH_GAUSSIAN;
  488   }
  489   else {
  490     neigh = NEIGH_BUBBLE;
  491   }
  492   
  493   label_not_needed(1);
  494 
  495   noc = info->xdim * info->ydim;
  496   if ( noc <= 0 ) {
  497     BAF_ERROR_MSG("dimensionality wrong" );
  498   }
  499   info->data = open_entries( info->data_path );
  500   if ( info->data_path == NULL) {
  501     BAF_ERROR_MSG("can't open data file" );
  502   }
  503   
  504   /* set options for data file */
  505   /* : ... this may make a difference in initialization */
  506   set_buffer( info->data, BUFFER_SIZE );
  507   init_random( 0 );
  508 
  509   /* do initialization */
  510   if ( strcmp( info->init_type, "lininit" ) == 0 ) {
  511     info->codes = lininit_codes( info->data, topol, neigh, 
  512                  info->xdim, info->ydim);
  513   } else {
  514     info->codes = randinit_codes( info->data, topol, neigh, 
  515                  info->xdim, info->ydim);
  516   }
  517 
  518   close_entries( info->data );
  519   info->data = NULL;
  520 
  521   if ( info->codes == NULL ) {
  522     BAF_ERROR_MSG("can't init codes" );
  523   }
  524 
  525   save_entries_wcomments( info->codes, info->code_path,
  526               "# random seed: 0\n");
  527 
  528   close_entries( info->codes );
  529   info->codes = NULL;
  530 
  531   BAF_CATCH( br_lrn_q_error( info ) ) {
  532     BAF_ERROR_MSG("can't evaluate qerror" );
  533   }
  534 
  535   BAF_OUT(PRIVATE);
  536 
  537 
  538  BAF_ERROR:
  539 
  540   /* : clean up */
  541   if ( info->data != NULL ) {
  542     close_entries( info->data );
  543     info->data = NULL;
  544   }
  545   if ( info->codes != NULL ) {
  546     close_entries( info->codes );
  547     info->codes = NULL;
  548   }
  549 
  550   BAF_THROW();
  551 }
  552 
  553 
  554 /******************************************************************************
  555 
  556  FUNCTION: br_lrn_learn
  557 
  558  SYNOPSIS
  559  Does the learning run on the som and evaluates the error
  560 
  561  HISTORY
  562  Created Apr 14, 98 by dab
  563 
  564 ******************************************************************************/
  565 
  566 BR_LRN_RES
  567 br_lrn_learn(
  568 BR_LRN_INFO_PTR info
  569 )
  570 {
  571   struct teach_params params;
  572   struct typelist *type_tmp = NULL;
  573   
  574   BAF_IN(PRIVATE);
  575 
  576   use_fixed( 0 );
  577   use_weights( 0 );
  578   label_not_needed( 1 );
  579 
  580   /* : set the params of the learning */
  581   params.length = info->learn.length;
  582   params.alpha = info->learn.rate;
  583   params.radius = info->learn.radius;
  584 
  585   info->data = open_entries( info->data_path );
  586   if ( info->data == NULL ) {
  587     BAF_ERROR_MSG("can't open data file" );
  588   }
  589 
  590   info->codes = open_entries( info->code_path );
  591   if ( info->codes == NULL ) {
  592     BAF_ERROR_MSG("can't open codes file" );
  593   }
  594 
  595   if ( info->codes->topol < TOPOL_HEXA ) {
  596     BAF_ERROR_MSG("error in codes file" );
  597   }
  598 
  599   if ( info->data->dimension != info->codes->dimension ) {
  600     BAF_ERROR_MSG("mismatch between codes and data" );
  601   }
  602 
  603   set_teach_params( &params, info->codes, info->data, BUFFER_SIZE );
  604   set_som_params( &params );
  605   params.snapshot = NULL;
  606 
  607   init_random( 0 );
  608 
  609   /* take teaching vectors in random order */
  610   info->data->flags.random_order = 1;
  611 
  612   type_tmp = get_type_by_id(alpha_list, ALPHA_LINEAR);
  613 
  614   params.alpha_type = type_tmp->id;
  615   params.alpha_func = type_tmp->data;
  616 
  617   info->codes = som_training( &params );
  618 
  619   save_entries( info->codes, info->code_path );
  620 
  621   if ( info->data != NULL ) {
  622     close_entries( info->data );
  623     info->data = NULL;
  624   }
  625   if ( info->codes != NULL ) {
  626     close_entries( info->codes );
  627     info->data = NULL;
  628   }
  629 
  630   BAF_CATCH( br_lrn_q_error( info ) ) {
  631     BAF_ERROR_MSG("can't evaluate qerror" );
  632   }
  633 
  634   BAF_OUT(PRIVATE);
  635 
  636 
  637  BAF_ERROR:
  638 
  639   if ( info->data != NULL ) {
  640     close_entries( info->data );
  641     info->data = NULL;
  642   }
  643   if ( info->codes != NULL ) {
  644     close_entries( info->codes );
  645     info->data = NULL;
  646   }
  647 
  648   BAF_THROW();
  649 }
  650 
  651 
  652 /******************************************************************************
  653 
  654  FUNCTION: br_lrn_dispose_info
  655 
  656  SYNOPSIS
  657  Cleans up an info structure
  658 
  659  HISTORY
  660  Created Apr 14, 98 by dab
  661 
  662 ******************************************************************************/
  663 
  664 BR_LRN_RES
  665 br_lrn_dispose_info(
  666 BR_LRN_INFO_PTR *pp_info
  667 )
  668 {
  669   BR_LRN_INFO_PTR info = *pp_info;
  670 
  671   BAF_IN(PRIVATE);
  672 
  673   /* : guard against multiple diposals */
  674   if ( pp_info == NULL ) {
  675     BAF_OUT(PRIVATE);
  676   }
  677   if ( *pp_info == NULL ) {
  678     BAF_OUT(PRIVATE);
  679   }
  680   
  681   GIVE(info->init_type);
  682 
  683   /* : allocations */
  684   GIVE(info->topol);
  685   GIVE(info->neigh);
  686   GIVE(info->data_path);
  687   GIVE(info->code_path);
  688   
  689   /* : guard against multiples */
  690   GIVE( (*pp_info) );
  691   *pp_info = NULL;
  692 
  693   BAF_OUT(PRIVATE);
  694 }
  695 
  696 
  697 /******************************************************************************
  698 
  699  FUNCTION: br_lrn_new_info
  700 
  701  SYNOPSIS
  702  Allocates and returns a new info
  703 
  704  HISTORY
  705  Created Apr 14, 98 by dab
  706 
  707 ******************************************************************************/
  708 
  709 BR_LRN_RES
  710 br_lrn_new_info(
  711 BR_LRN_INFO_PTR *pp_info
  712 )
  713 {
  714   BAF_IN(PRIVATE);
  715 
  716   TAKE( *pp_info ,, sizeof(BR_LRN_INFO) ) {
  717     BAF_THROW_MSG("can't allocate" );
  718   }
  719 
  720   BAF_OUT(PRIVATE);
  721 }
  722 
  723 
  724 /******************************************************************************
  725 
  726  FUNCTION: br_lrn_handle_learn
  727 
  728  SYNOPSIS
  729  Handles the learn action
  730 
  731  HISTORY
  732  Created Apr 14, 98 by dab
  733 
  734 ******************************************************************************/
  735 
  736 BR_LRN_RES
  737 br_lrn_handle_learn(
  738 ENDO_MSG_REF msg,
  739 float *q_error
  740 )
  741 {
  742   BR_LRN_RES br_res = 0;
  743   BR_LRN_INFO_PTR info = NULL;
  744 
  745   BAF_IN(PRIVATE);
  746 
  747   /* : zero the error */
  748   *q_error = 0;
  749 
  750   /* : allocate our info */
  751   BAF_CATCH( br_lrn_new_info( &info ) ) {
  752     BAF_ERROR_MSG("can't allocate info" );
  753   }
  754 
  755   /* : get our params */
  756   BAF_CATCH( endo_msg_get_args( msg,
  757                 "ssdff",
  758                 &(info->data_path),
  759                 &(info->code_path),
  760                 &(info->learn.length),
  761                 &(info->learn.rate),
  762                 &(info->learn.radius) ) ) {
  763     br_res = BR_LRN_BAD_PARAMS;
  764     BAF_ERROR();
  765   }
  766 
  767   /* : learn */
  768   BAF_CATCH_ERR( br_res, br_lrn_learn( info ) ) {
  769     /* : we'll return the error from the learning function */
  770     BAF_ERROR();
  771   }
  772 
  773   /* : return our q_error */
  774   *q_error = info->qerror;
  775   
  776   /* : clean up */
  777   if ( info != NULL ) {
  778     BAF_CATCH( br_lrn_dispose_info( &info ) ) {
  779       BAF_ERROR_MSG("can't dispose info struct" );
  780     }
  781   }
  782 
  783   BAF_OUT(PRIVATE);
  784 
  785 
  786  BAF_ERROR:
  787 
  788   /* : clean up */
  789   if ( info != NULL ) {
  790     BAF_CATCH( br_lrn_dispose_info( &info ) ) {
  791       MSG(PRIVATE,"can't dispose info");
  792     }
  793   }
  794 
  795   if ( br_res == BR_LRN_OK )
  796     br_res = BR_LRN_FAIL;
  797 
  798   BAF_THROW_ERR( br_res );
  799 }
  800 
  801 
  802 /******************************************************************************
  803 
  804  FUNCTION: br_lrn_handle_init
  805 
  806  SYNOPSIS
  807  Handles the learn action
  808 
  809  HISTORY
  810  Created  by dab
  811 
  812 ******************************************************************************/
  813 
  814 BR_LRN_RES
  815 br_lrn_handle_init(
  816 ENDO_MSG_REF msg,
  817 float *q_error
  818 )
  819 {
  820   BR_LRN_RES br_res = 0;
  821   BR_LRN_INFO_PTR info = NULL;
  822 
  823   BAF_IN(PRIVATE);
  824 
  825   /* : zero the error */
  826   *q_error = 0;
  827 
  828   /* : allocate our info */
  829   BAF_CATCH( br_lrn_new_info( &info ) ) {
  830     BAF_ERROR();
  831   }
  832 
  833   /* : get our params */
  834   BAF_CATCH( endo_msg_get_args( msg,
  835                 "sddssss",
  836                 &(info->init_type),
  837                 &(info->xdim),
  838                 &(info->ydim),
  839                 &(info->topol),
  840                 &(info->neigh),
  841                 &(info->data_path),
  842                 &(info->code_path) ) ) {
  843     br_res = BR_LRN_BAD_PARAMS;
  844     BAF_ERROR();
  845   }
  846 
  847   /* : init ... */
  848   BAF_CATCH_ERR( br_res, br_lrn_init( info ) ) {
  849     BAF_ERROR();
  850   }
  851 
  852   /* : return our q_error */
  853   *q_error = info->qerror;
  854   
  855   /* : clean up */
  856   if ( info != NULL ) {
  857     BAF_CATCH( br_lrn_dispose_info( &info ) ) {
  858       BAF_ERROR_MSG("can't dispose info struct" );
  859     }
  860   }
  861 
  862   BAF_OUT(PRIVATE);
  863 
  864 
  865  BAF_ERROR:
  866 
  867   /* : clean up */
  868   if ( info != NULL ) {
  869     BAF_CATCH( br_lrn_dispose_info( &info ) ) {
  870       MSG(PRIVATE,"can't dispose info struct" );
  871     }
  872   }
  873 
  874   if ( br_res == BR_LRN_OK )
  875     br_res = BR_LRN_FAIL;
  876 
  877   BAF_THROW_ERR( br_res );
  878 }
  879 
  880 
  881 /******************************************************************************
  882 
  883  FUNCTION: br_lrn_handle_qerror
  884 
  885  SYNOPSIS
  886  Handles the learn action
  887 
  888  HISTORY
  889  Created  by dab
  890 
  891 ******************************************************************************/
  892 
  893 BR_LRN_RES
  894 br_lrn_handle_qerror(
  895 ENDO_MSG_REF msg,
  896 float *q_error
  897 )
  898 {
  899   BR_LRN_RES br_res = 0;
  900   BR_LRN_INFO_PTR info = NULL;
  901 
  902   BAF_IN(PRIVATE);
  903 
  904   /* : zero the error */
  905   *q_error = 0;
  906 
  907   /* : allocate our info */
  908   BAF_CATCH( br_lrn_new_info( &info ) ) {
  909     BAF_ERROR();
  910   }
  911 
  912   /* : get our params */
  913   BAF_CATCH( endo_msg_get_args( msg,
  914                 "ss",
  915                 &(info->data_path),
  916                 &(info->code_path) ) ) {
  917     br_res = BR_LRN_BAD_PARAMS;
  918     BAF_ERROR();
  919   }
  920 
  921   /* : qerror */
  922   BAF_CATCH_ERR( br_res, br_lrn_q_error( info ) ) {
  923     BAF_ERROR_MSG("can't get qerror" );
  924   }
  925 
  926   /* : return our q_error */
  927   *q_error = info->qerror;
  928   
  929   /* : clean up */
  930   if ( info != NULL ) {
  931     BAF_CATCH( br_lrn_dispose_info( &info ) ) {
  932       BAF_ERROR_MSG("can't dispose info struct" );
  933     }
  934   }
  935 
  936   BAF_OUT(PRIVATE);
  937 
  938 
  939  BAF_ERROR:
  940 
  941   /* : clean up */
  942   if ( info != NULL ) {
  943     BAF_CATCH( br_lrn_dispose_info( &info ) ) {
  944       MSG(PRIVATE,"can't dispose info");
  945     }
  946   }
  947 
  948   if ( br_res == BR_LRN_OK )
  949     br_res = BR_LRN_FAIL;
  950 
  951   BAF_THROW_ERR( br_res );
  952 }
  953 
  954 
  955 /******************************************************************************
  956 
  957  FUNCTION: br_learn
  958 
  959  SYNOPSIS
  960  Main entry point for module which learns
  961 
  962  HISTORY
  963  Created Apr 13, 98 by dab
  964 
  965 ******************************************************************************/
  966 
  967 int
  968 br_learn(
  969 ENDO_MSG_REF msg,
  970 char *action
  971 )
  972 {
  973   BR_LRN_RES br_res = 0;
  974   float q_error = 0;
  975 
  976   BAF_IN(PUBLIC);
  977 
  978   /* : now our module specific actions */
  979   if ( strcmp( BR_LRN_LEARN, action ) == 0 ) {
  980 
  981     BAF_CATCH_ERR( br_res, br_lrn_handle_learn( msg, &q_error ) ) {
  982       BAF_ERROR();
  983     }
  984 
  985   }
  986 
  987   /* : init */
  988   else if ( strcmp( BR_LRN_INIT, action ) == 0 ) {
  989 
  990     BAF_CATCH_ERR( br_res, br_lrn_handle_init( msg, &q_error ) ) {
  991       BAF_ERROR();
  992     }
  993 
  994   }
  995 
  996   /* : qerror */
  997   else if ( strcmp( BR_LRN_QERROR, action ) == 0 ) {
  998 
  999     BAF_CATCH_ERR( br_res, br_lrn_handle_qerror( msg, &q_error ) ) {
 1000       BAF_ERROR();
 1001     }
 1002 
 1003   }
 1004 
 1005   else {
 1006 
 1007     /* : it's an unsuported action type */
 1008     br_res = BR_LRN_UNSUPPORTED;
 1009     BAF_ERROR();
 1010 
 1011   }
 1012 
 1013   MSG(PUBLIC,"returning q_error of: %f\n", q_error );
 1014 
 1015   /* : reply */
 1016   BAF_CATCH( endo_msg_reply_args( msg, "f", q_error ) ) {
 1017     br_res = BR_LRN_CANT_RETURN_QERROR;
 1018     BAF_ERROR();
 1019   }
 1020 
 1021   BAF_OUT(PUBLIC);
 1022 
 1023 
 1024  BAF_ERROR:
 1025 
 1026   /* : make sure that we have an error */
 1027   if ( br_res == BR_LRN_OK )
 1028     br_res = BR_LRN_FAIL;
 1029 
 1030   /* : reply with the error, ignore any trouble in the reply */
 1031   BAF_CATCH( endo_msg_reply_err( msg, br_lrn_s_error[br_res] ) ) {
 1032     MSG(PUBLIC,"can't reply error");
 1033   }
 1034 
 1035   BAF_THROW_MSG( br_lrn_s_error[br_res] );
 1036 }
 1037 
 1038 
 1039 
 1040 
 1041 /******************************************************************************
 1042 
 1043  (c) MMIII, NeuralVR Technologies Ltd., All Rights Reserved.
 1044 
 1045  MODULE: br_think.c
 1046 
 1047  SYNOPSIS
 1048  Maps input data to a co-ordinate in the som
 1049 
 1050  HISTORY
 1051  Created Apr 14, 98 by dab
 1052 
 1053  NOTES
 1054  One action, 'think'.
 1055 
 1056  think
 1057  -----
 1058  Takes the following args ...
 1059       s - path to data file in
 1060     s - path to data file out
 1061     s - path to code page file, preferably labelled
 1062 
 1063  Returns success or fail.
 1064 
 1065 ******************************************************************************/
 1066 
 1067 /* : structs to pass around privately */
 1068 
 1069 /* : for results */
 1070 typedef enum {
 1071   BR_THK_OK,
 1072   BR_THK_FAIL,
 1073   BR_THK_BAD_PARAMS,
 1074   BR_THK_DATA_FILE_NO_GOOD,
 1075   BR_THK_OUTPUT_FILE_NO_GOOD,
 1076   BR_THK_CODES_FILE_NO_GOOD,
 1077   BR_THK_DATA_CODES_MISMATCH,
 1078   BR_THK_CANT_REPLY,
 1079   BR_THK_UNSUPPORTED
 1080 } BR_THK_RES;
 1081 
 1082 static char *br_thk_s_error[] = {
 1083   "br_thk no error",
 1084   "br_thk general failure",
 1085   "br_thk bad parameters",
 1086   "br_thk data file no good",
 1087   "br_thk output file no good",
 1088   "br_thk codes file no good",
 1089   "br_thk data and codes file mismatch",
 1090   "br_thk can't reply",
 1091   "br_thk unsupported"
 1092 };
 1093 
 1094 typedef struct {
 1095   char *data_path_in;
 1096   char *data_path_out;
 1097   char *code_path;
 1098   struct entries *data;
 1099   struct entries *codes;
 1100   struct teach_params params;
 1101 } BR_THK_INFO, *BR_THK_INFO_PTR;
 1102 
 1103 
 1104 /******************************************************************************
 1105 
 1106  FUNCTION: br_thk_setup
 1107 
 1108  SYNOPSIS
 1109  Runs the data file through the som
 1110 
 1111  HISTORY
 1112  Created Apr 14, 98 by dab
 1113 
 1114 ******************************************************************************/
 1115 
 1116 BR_THK_RES
 1117 br_thk_setup(
 1118 BR_THK_INFO_PTR info
 1119 )
 1120 {
 1121   BR_THK_RES br_res = 0;
 1122 
 1123   BAF_IN(PRIVATE);
 1124 
 1125   label_not_needed( 1 );
 1126 
 1127   /* : open the data file */
 1128   info->data = open_entries( info->data_path_in );
 1129   if ( info->data == NULL ) {
 1130     br_res = BR_THK_DATA_FILE_NO_GOOD;
 1131     BAF_ERROR();
 1132   }
 1133 
 1134   /* : open the codes file */
 1135   info->codes = open_entries( info->code_path );
 1136   if ( info->codes == NULL ) {
 1137     br_res = BR_THK_CODES_FILE_NO_GOOD;
 1138     BAF_ERROR();
 1139   }
 1140 
 1141   /* : a quick sanity check */
 1142   if ( info->codes->topol < TOPOL_HEXA ) {
 1143     /* : not a map file */
 1144     br_res = BR_THK_CODES_FILE_NO_GOOD;
 1145     BAF_ERROR();
 1146   }
 1147 
 1148   /* : make sure that we have a match in dimensionality */
 1149   if ( info->codes->dimension != info->data->dimension ) {
 1150     /* : mismatch in dimensionality */
 1151     br_res = BR_THK_DATA_CODES_MISMATCH;
 1152     BAF_ERROR();
 1153   }
 1154 
 1155   /* : set up the teach and som params */
 1156   set_teach_params( &(info->params), info->codes, info->data, BUFFER_SIZE );
 1157   set_som_params( &(info->params) );
 1158   info->data->flags.skip_empty = 0;
 1159 
 1160   BAF_OUT(PRIVATE);
 1161 
 1162 
 1163  BAF_ERROR:
 1164 
 1165   if ( br_res == BR_THK_OK )
 1166     br_res = BR_THK_FAIL;
 1167 
 1168   BAF_THROW_ERR( br_res );
 1169 }
 1170 
 1171 
 1172 /******************************************************************************
 1173 
 1174  FUNCTION: br_thk_think
 1175 
 1176  SYNOPSIS
 1177  Does the thinking around here
 1178 
 1179  HISTORY
 1180  Created Apr 14, 98 by dab
 1181 
 1182 ******************************************************************************/
 1183 
 1184 static BR_THK_RES
 1185 br_thk_think(
 1186 struct teach_params *teach,
 1187 char *out_file_name
 1188 )
 1189 {
 1190   BR_THK_RES br_res = 0;
 1191   int length_known;
 1192   struct data_entry *datatmp = NULL;
 1193   struct entries *data = teach->data;
 1194   struct entries *codes = teach->codes;
 1195   struct entries *fake_data = NULL;
 1196   struct data_entry *fake_entry = NULL;
 1197   struct file_info *fi = NULL;
 1198   WINNER_FUNCTION *winner = teach->winner;
 1199   struct winner_info win_info;
 1200   int emptylab = LABEL_EMPTY;
 1201   long index, nod, bpos;
 1202   eptr p;
 1203 
 1204   BAF_IN(PRIVATE);
 1205 
 1206   emptylab = find_conv_to_ind("EMPTY_LINE");
 1207 
 1208   /* initialize fake entries table */
 1209   fake_data = alloc_entries();
 1210   if (fake_data == NULL) {
 1211     BAF_ERROR_MSG("can't allocate for memory entries" );
 1212   }
 1213 
 1214   fake_data->dimension = 3;
 1215   fake_data->topol = codes->topol;
 1216   fake_data->neigh = codes->neigh;
 1217   fake_data->xdim = codes->xdim;
 1218   fake_data->ydim = codes->ydim;
 1219 
 1220   fake_entry = alloc_entry(fake_data);
 1221   if (fake_entry == NULL) {
 1222     BAF_ERROR_MSG("can't allocate for fake entry" );
 1223   }
 1224   fake_data->entries = fake_entry;
 1225 
 1226   /* open output file */
 1227   fi = open_file( out_file_name, "w+");
 1228   if (fi == NULL) {
 1229     br_res = BR_THK_OUTPUT_FILE_NO_GOOD;
 1230     BAF_ERROR();
 1231   }
 1232 
 1233   fake_data->fi = fi;
 1234   /* write header of output file */
 1235   write_header(fi, fake_data);
 1236 
 1237   /* Scan all input entries. */
 1238   datatmp = rewind_entries(data, &p);
 1239 
 1240   if ((length_known = data->flags.totlen_known))
 1241     nod = data->num_entries;
 1242   else
 1243     nod = 0;
 1244 
 1245   while (datatmp != NULL) {
 1246 
 1247     /* bpos = winner(codes, datatmp); */
 1248     if (winner(codes, datatmp, &win_info, 1) == 0) {
 1249 
 1250       /* empty sample */
 1251       /* Save the classification and coordinates */
 1252       set_entry_label(fake_entry, emptylab); /* labels */
 1253       fake_entry->points[0] = -1;
 1254       fake_entry->points[1] = -1;
 1255       /* And the quantization error */
 1256       fake_entry->points[2] = -1.0;
 1257 
 1258     }
 1259     else {
 1260 
 1261       bpos = win_info.index;
 1262       index = get_entry_label(win_info.winner);
 1263     
 1264       /* Save the classification and coordinates */
 1265       copy_entry_labels(fake_entry, win_info.winner); /* labels */
 1266       fake_entry->points[0] = bpos % codes->xdim;
 1267       fake_entry->points[1] = bpos / codes->xdim;
 1268       /* And the quantization error */
 1269       fake_entry->points[2] = sqrt(win_info.diff);
 1270     }
 1271     /* write new entry */
 1272     write_entry(fi, fake_data, fake_entry);
 1273 
 1274     /* Take the next input entry */
 1275     datatmp = next_entry(&p);
 1276 
 1277 #ifdef DEBUG
 1278     if (length_known)
 1279       mprint((long) nod--);
 1280 #endif
 1281 
 1282   }
 1283 
 1284 #ifdef DEBUG
 1285   if (length_known) {
 1286     mprint((long) 0);
 1287     fprintf(stderr, "\n");
 1288   }
 1289 #endif
 1290 
 1291   /* : clean up */
 1292   if ( fake_data != NULL )
 1293     free_entries( fake_data );
 1294 
 1295   BAF_OUT(PRIVATE);
 1296 
 1297 
 1298  BAF_ERROR:
 1299 
 1300   if ( br_res == BR_THK_OK )
 1301     br_res = BR_THK_FAIL;
 1302 
 1303   /* : clean up */
 1304   if ( fake_data != NULL )
 1305     free_entries( fake_data );
 1306 
 1307   BAF_THROW_ERR( br_res );
 1308 }
 1309 
 1310 
 1311 /******************************************************************************
 1312 
 1313  FUNCTION: br_thk_dispose_info
 1314 
 1315  SYNOPSIS
 1316  Cleans up an info structure
 1317 
 1318  HISTORY
 1319  Created Apr 14, 98 by dab
 1320 
 1321 ******************************************************************************/
 1322 
 1323 BR_THK_RES
 1324 br_thk_dispose_info(
 1325 BR_THK_INFO_PTR *pp_info
 1326 )
 1327 {
 1328   BR_THK_INFO_PTR info = *pp_info;
 1329 
 1330   BAF_IN(PRIVATE);
 1331 
 1332   /* : guard against multiple disposals */
 1333   if ( pp_info == NULL ) {
 1334     BAF_OUT(PRIVATE);
 1335   }
 1336   if ( *pp_info == NULL ) {
 1337     BAF_OUT(PRIVATE);
 1338   }
 1339   
 1340   GIVE(info->data_path_in);
 1341   GIVE(info->data_path_out);
 1342   GIVE(info->code_path);
 1343 
 1344   /* : others ... */
 1345   if ( info->data != NULL ) {
 1346     close_entries( info->data );
 1347     info->data = NULL;
 1348   }
 1349   if ( info->codes != NULL ) {
 1350     close_entries( info->codes );
 1351     info->codes = NULL;
 1352   }
 1353   
 1354   /* : guard against multiples */
 1355   GIVE( (*pp_info) );
 1356   *pp_info = NULL;
 1357 
 1358   BAF_OUT(PRIVATE);
 1359 }
 1360 
 1361 
 1362 /******************************************************************************
 1363 
 1364  FUNCTION: br_thk_new_info
 1365 
 1366  SYNOPSIS
 1367  Allocates and returns a new info
 1368 
 1369  HISTORY
 1370  Created Apr 14, 98 by dab
 1371 
 1372 ******************************************************************************/
 1373 
 1374 BR_THK_RES
 1375 br_thk_new_info(
 1376 BR_THK_INFO_PTR *pp_info
 1377 )
 1378 {
 1379   BAF_IN(PRIVATE);
 1380 
 1381   TAKE( *pp_info, (BR_THK_INFO_PTR), sizeof(BR_THK_INFO) ) {
 1382     BAF_THROW_MSG("can't allocate" );
 1383   }
 1384 
 1385   BAF_OUT(PRIVATE);
 1386 }
 1387 
 1388 
 1389 /******************************************************************************
 1390 
 1391  FUNCTION: br_thk_handle_think
 1392 
 1393  SYNOPSIS
 1394  Handles the think action
 1395 
 1396  HISTORY
 1397  Created Apr 14, 98 by dab
 1398 
 1399 ******************************************************************************/
 1400 
 1401 BR_THK_RES
 1402 br_thk_handle_think(
 1403 ENDO_MSG_REF msg
 1404 )
 1405 {
 1406   BR_THK_RES br_res = 0;
 1407   BR_THK_INFO_PTR info = NULL;
 1408 
 1409   BAF_IN(PRIVATE);
 1410 
 1411   /* : allocate our info */
 1412   BAF_CATCH( br_thk_new_info( &info ) ) {
 1413     BAF_ERROR();
 1414   }
 1415 
 1416   /* : get our params */
 1417   BAF_CATCH( endo_msg_get_args( msg,
 1418                 "sss",
 1419                 &(info->data_path_in),
 1420                 &(info->data_path_out),
 1421                 &(info->code_path) ) ) {
 1422     br_res = BR_THK_BAD_PARAMS;
 1423     BAF_ERROR();
 1424   }
 1425 
 1426   /* : set things up */
 1427   BAF_CATCH_ERR( br_res, br_thk_setup( info ) ) {
 1428     BAF_ERROR();
 1429   }
 1430 
 1431   /* : do the run, a bit different as I was having some trouble */
 1432   BAF_CATCH_ERR( br_res, br_thk_think( &(info->params), info->data_path_out ) ) {
 1433     BAF_ERROR();
 1434   }
 1435   
 1436   /* : clean up */
 1437   if ( info != NULL ) {
 1438     BAF_CATCH( br_thk_dispose_info( &info ) ) {
 1439       BAF_ERROR_MSG("can't dispose info struct" );
 1440     }
 1441   }
 1442 
 1443   BAF_OUT(PRIVATE);
 1444 
 1445 
 1446  BAF_ERROR:
 1447 
 1448   /* : clean up */
 1449   if ( info != NULL ) {
 1450     BAF_CATCH( br_thk_dispose_info( &info ) ) {
 1451       MSG(PRIVATE,"can't dispose info");
 1452     }
 1453   }
 1454 
 1455   if ( br_res == BR_THK_OK )
 1456     br_res = BR_THK_FAIL;
 1457 
 1458   BAF_THROW_ERR( br_res );
 1459 }
 1460 
 1461 
 1462 /******************************************************************************
 1463 
 1464  FUNCTION: br_think
 1465 
 1466  SYNOPSIS
 1467  Main entry point for module which thinks
 1468 
 1469  HISTORY
 1470  IncrDev Apr 30, 98 by dab: amalgamated into one module
 1471  Created Apr 14, 98 by dab
 1472 
 1473 ******************************************************************************/
 1474 
 1475 int
 1476 br_think(
 1477 ENDO_MSG_REF msg_ref,
 1478 char *action
 1479 )
 1480 {
 1481   BR_THK_RES br_res = 0;
 1482 
 1483   BAF_IN(PUBLIC);
 1484 
 1485   /* : now our module specific actions */
 1486   if ( strcmp( BR_THK_THINK, action ) == 0 ) {
 1487 
 1488     /* : call our handler for this case */
 1489     BAF_CATCH_ERR( br_res, br_thk_handle_think( msg_ref ) ) {
 1490       BAF_ERROR();
 1491     }
 1492 
 1493   }
 1494 
 1495   else {
 1496 
 1497     /* : it's an unsuported action type */
 1498     br_res = BR_THK_UNSUPPORTED;
 1499     BAF_ERROR();
 1500 
 1501   }
 1502 
 1503   BAF_CATCH( endo_msg_reply_success( msg_ref ) ) {
 1504     br_res = BR_THK_CANT_REPLY;
 1505     BAF_ERROR();
 1506   }
 1507 
 1508   BAF_OUT(PUBLIC);
 1509 
 1510 
 1511  BAF_ERROR:
 1512 
 1513   /* : make sure that we have an error */
 1514   if ( br_res == BR_THK_OK )
 1515     br_res = BR_THK_FAIL;
 1516 
 1517   /* : reply with the error, ignore any trouble in the reply */
 1518   BAF_CATCH( endo_msg_reply_err( msg_ref, br_thk_s_error[br_res] ) ) {
 1519     MSG(PRIVATE,"can't reply error");
 1520   }
 1521 
 1522   /* : failure returns here */
 1523   BAF_THROW_MSG( br_thk_s_error[br_res] );
 1524 }
 1525 
 1526 
 1527 
 1528 
 1529 /******************************************************************************
 1530 
 1531  (c) MMIII, NeuralVR Technologies Ltd., All Rights Reserved.
 1532 
 1533  MODULE: br_label
 1534 
 1535  SYNOPSIS
 1536  Labels the code pages for a som
 1537 
 1538  HISTORY
 1539  Created Apr 14, 98 by dab
 1540 
 1541  NOTES
 1542  One action 'label'.
 1543 
 1544  label
 1545  -----
 1546  Takes the following args:
 1547         s - data_file with labels
 1548       s - code_path
 1549       s - target for labeled code file
 1550 
 1551  Returns success or fail
 1552 
 1553 ******************************************************************************/
 1554 
 1555 /* : for results */
 1556 typedef enum {
 1557   BR_LAB_OK,
 1558   BR_LAB_FAIL,
 1559   BR_LAB_BAD_PARAMS,
 1560   BR_LAB_BAD_DATA_FILE,
 1561   BR_LAB_BAD_CODES_FILE,
 1562   BR_LAB_DATA_CODES_MISMATCH,
 1563   BR_LAB_CANT_FIND_LABELS,
 1564   BR_LAB_CANT_REPLY,
 1565   BR_LAB_UNSUPPORTED
 1566 } BR_LAB_RES;
 1567 
 1568 static char *br_lab_s_error[] = {
 1569   "br_lab no error",
 1570   "br_lab general failure",
 1571   "br_lab bad parameters",
 1572   "br_lab bad data file",
 1573   "br_lab bad code page file",
 1574   "br_lab data file and codes file mismatch",
 1575   "br_lab can't find labels",
 1576   "br_lab can't reply",
 1577   "br_lab unsupported"
 1578 };
 1579 
 1580 
 1581 /******************************************************************************
 1582 
 1583  FUNCTION: br_lab_find_labels
 1584 
 1585  SYNOPSIS
 1586  Does the actual label finding
 1587 
 1588  HISTORY
 1589  Created Apr 14, 98 by dab
 1590 
 1591  NOTES
 1592  Taken pretty much from the Kohonen code ...
 1593 
 1594 ******************************************************************************/
 1595 
 1596 BR_LAB_RES
 1597 br_lab_find_labels(
 1598 struct teach_params *teach,
 1599 int numlabs
 1600 )
 1601 {
 1602 #ifdef DEBUG
 1603   long nol;
 1604 #endif
 1605   long noc, index;
 1606   int i, labs;
 1607   int datalabel, ind;
 1608   struct data_entry *codetmp, *datatmp;
 1609   WINNER_FUNCTION *winner = teach->winner;
 1610   struct entries *data = teach->data;
 1611   struct entries *codes = teach->codes;
 1612   struct winner_info win_info;
 1613   struct hitlist **hits = NULL;
 1614   struct hit_entry *hit;
 1615 #ifdef DEBUG
 1616   int showmeter = 0;
 1617 #endif
 1618   eptr p;
 1619 
 1620   BAF_IN(PRIVATE);
 1621 
 1622   if (numlabs < 0)
 1623     numlabs = 0;
 1624 
 1625   data = teach->data;
 1626   codes = teach->codes;
 1627 
 1628   if (rewind_entries(codes, &p) == NULL) {
 1629     BAF_ERROR_MSG("can't rewind entries" );
 1630   }
 1631   
 1632   noc = codes->num_entries;
 1633 
 1634   /* allocate a hitlist for all codebook units */
 1635   hits = calloc(noc, sizeof(struct hitlist *));
 1636   if (hits == NULL) {
 1637     BAF_ERROR_MSG("can't calloc for hit list" );
 1638   }
 1639 
 1640   for (i = 0; i < noc; i++) {
 1641 
 1642     hits[i] = new_hitlist();
 1643     if (hits[i] == NULL) {
 1644 
 1645       MSG(PRIVATE,"can't get hitlist");
 1646 
 1647       /* free allocated hitlists */
 1648       while (--i >= 0)
 1649     free_hitlist(hits[i]);
 1650       free(hits);
 1651 
 1652       BAF_ERROR();
 1653     }
 1654 
 1655   }
 1656 
 1657   /* Scan all data entries */
 1658   datatmp = rewind_entries( data, &p );
 1659   if ( datatmp == NULL) {
 1660     BAF_ERROR_MSG("can't rewind entries" );
 1661   }
 1662 
 1663 #ifdef DEBUG
 1664   /* show progress meter only if number of data vectors is known (when
 1665      not using buffered input) */
 1666   showmeter = data->flags.totlen_known;
 1667   if (showmeter)
 1668     nol = data->num_entries;
 1669   else
 1670     nol = 0;
 1671 #endif
 1672 
 1673   ind = 0;
 1674 
 1675   while (datatmp != NULL) {
 1676 
 1677     datalabel = get_entry_label(datatmp);
 1678 
 1679     if (winner(codes, datatmp, &win_info, 1) == 0)
 1680       goto skip_hit; /* winner not found -> assume that all components
 1681             of sample vector were masked off -> skip this
 1682             sample */
 1683 
 1684     /* add a hit in the winning unit's hitlist for the class of the
 1685        sample. Ignores samples with no class (= empty label) */
 1686 
 1687     index = win_info.index;
 1688     if (datalabel != LABEL_EMPTY)
 1689       add_hit(hits[index], datalabel);
 1690 
 1691   skip_hit:
 1692     /* Take the next data entry */
 1693     datatmp = next_entry(&p);
 1694     ind++;
 1695 
 1696 #ifdef DEBUG
 1697     if (showmeter)
 1698       mprint(nol--);
 1699 #endif
 1700   }
 1701 
 1702 #ifdef DEBUG
 1703   mprint(0);
 1704   fprintf(stderr, "\n");
 1705 #endif
 1706 
 1707   /* Set the label of codebook entries according the
 1708      selections. Numlabs tells how many labels at maximum to assign to
 1709      a certain codebook vector. 0 means all */
 1710 
 1711   codetmp = rewind_entries(codes, &p);
 1712   index = 0;
 1713 
 1714   while (codetmp != NULL) {
 1715 
 1716     if (numlabs == 0)
 1717       labs = hits[index]->entries;
 1718     else
 1719       labs = min(hits[index]->entries, numlabs);
 1720 
 1721     /* remove previous labels from codebook vector */
 1722     clear_entry_labels(codetmp);
 1723 
 1724     for (i = 0, hit = hits[index]->head; i < labs; i++, hit = hit->next)
 1725       add_entry_label(codetmp, hit->label);
 1726 
 1727     free_hitlist(hits[index]);
 1728     hits[index] = NULL;
 1729 
 1730     codetmp = next_entry(&p);
 1731     index++;
 1732   }
 1733 
 1734   free(hits);
 1735 
 1736   BAF_OUT(PRIVATE);
 1737 
 1738 
 1739  BAF_ERROR:
 1740 
 1741   BAF_THROW();
 1742 }
 1743 
 1744 
 1745 /******************************************************************************
 1746 
 1747  FUNCTION: br_lab_label_code
 1748 
 1749  SYNOPSIS
 1750  Prepares and finds labels
 1751 
 1752  HISTORY
 1753  Created Apr 14, 98 by dab
 1754 
 1755 ******************************************************************************/
 1756 
 1757 static BR_LAB_RES
 1758 br_lab_label_code(
 1759 char *data_path,
 1760 char *code_path,
 1761 char *code_path_out
 1762 )
 1763 {
 1764   BR_LAB_RES br_res = 0;
 1765   struct entries *data = NULL;
 1766   struct entries *codes = NULL;
 1767   struct teach_params params;
 1768   long buffer = BUFFER_SIZE;
 1769   int num_labels = BR_LAB_NUM_LABELS;
 1770 
 1771   BAF_IN(PRIVATE);
 1772 
 1773   /* : open the input data file */
 1774   data = open_entries( data_path );
 1775   if ( data == NULL ) {
 1776     br_res = BR_LAB_BAD_DATA_FILE;
 1777     BAF_ERROR_MSG("can't open data file" );
 1778   }
 1779 
 1780   label_not_needed( 1 );
 1781 
 1782   /* : open the codes file */
 1783   codes = open_entries( code_path );
 1784   if ( codes == NULL ) {
 1785     br_res = BR_LAB_BAD_CODES_FILE;
 1786     BAF_ERROR_MSG("can't open codes file" );
 1787   }
 1788 
 1789   /* : sanity checks */
 1790   if ( codes->topol < TOPOL_HEXA ) {
 1791     br_res = BR_LAB_BAD_CODES_FILE;
 1792     BAF_ERROR_MSG("codes file looks bad" );
 1793   }
 1794 
 1795   /* : make sure dimensionality matches */
 1796   if ( codes->dimension != data->dimension ) {
 1797     br_res = BR_LAB_DATA_CODES_MISMATCH;
 1798     BAF_ERROR_MSG("codes file doesn't match data file" );
 1799   }
 1800 
 1801   set_teach_params( &params, codes, data, buffer );
 1802   set_som_params( &params );
 1803 
 1804   br_res = br_lab_find_labels( &params, num_labels );
 1805   if ( br_res != BR_LAB_OK ) {
 1806     br_res = BR_LAB_CANT_FIND_LABELS;
 1807     BAF_ERROR_MSG("fail to map labels to codes" );
 1808   }
 1809 
 1810   /* : write the labelled code vectors to the file */
 1811   save_entries( codes, code_path_out );
 1812 
 1813   /* : clean up */
 1814   if ( data != NULL )
 1815     close_entries( data );
 1816   if ( codes != NULL )
 1817     close_entries( codes );
 1818   
 1819   BAF_OUT(PRIVATE);
 1820 
 1821 
 1822  BAF_ERROR:
 1823 
 1824   /* : clean up */
 1825   if ( data != NULL )
 1826     close_entries( data );
 1827   if ( codes != NULL )
 1828     close_entries( codes );
 1829 
 1830   if ( br_res == BR_LAB_OK ) 
 1831     br_res = BR_LAB_FAIL;
 1832 
 1833   BAF_THROW_ERR( br_res );
 1834 }
 1835 
 1836 
 1837 /******************************************************************************
 1838 
 1839  FUNCTION: br_lab_handle_label
 1840 
 1841  SYNOPSIS
 1842  Handles the learn action
 1843 
 1844  HISTORY
 1845  Created Apr 14, 98 by dab
 1846 
 1847 ******************************************************************************/
 1848 
 1849 static BR_LAB_RES
 1850 br_lab_handle_label(
 1851 ENDO_MSG_REF msg
 1852 )
 1853 {
 1854   BR_LAB_RES br_res = 0;
 1855   char *data_path = NULL;
 1856   char *code_path = NULL;
 1857   char *code_path_out = NULL;
 1858 
 1859   BAF_IN(PRIVATE);
 1860 
 1861   /* : get our params */
 1862   BAF_CATCH( endo_msg_get_args( msg,
 1863                 "sss",
 1864                 &data_path,
 1865                 &code_path,
 1866                 &code_path_out ) ) {
 1867     br_res = BR_LAB_BAD_PARAMS;
 1868     BAF_ERROR_MSG("can't get params" );
 1869   }
 1870 
 1871   BAF_CATCH_ERR( br_res, br_lab_label_code( data_path, code_path, code_path_out )){
 1872     BAF_ERROR();
 1873   }
 1874   
 1875   /* : clean up */
 1876   GIVE(data_path );
 1877   GIVE(code_path);
 1878   GIVE(code_path_out);
 1879 
 1880   BAF_OUT(PRIVATE);
 1881 
 1882 
 1883  BAF_ERROR:
 1884 
 1885   GIVE(data_path );
 1886   GIVE(code_path);
 1887   GIVE(code_path_out);
 1888 
 1889   if ( br_res == BR_LAB_OK )
 1890     br_res = BR_LAB_FAIL;
 1891 
 1892   BAF_THROW_ERR( br_res );
 1893 }
 1894 
 1895 
 1896 /******************************************************************************
 1897 
 1898  FUNCTION: br_label
 1899 
 1900  SYNOPSIS
 1901  Main entry point for module to label som
 1902 
 1903  HISTORY
 1904  IncrDev Apr 30, 98 by dab: amagamated som routines into one module
 1905  Created Apr 14, 98 by dab
 1906 
 1907 ******************************************************************************/
 1908 
 1909 int
 1910 br_label(
 1911 ENDO_MSG_REF msg_ref,
 1912 char *action
 1913 )
 1914 {
 1915   BR_LAB_RES br_res = 0;
 1916 
 1917   BAF_IN(PUBLIC);
 1918 
 1919   /* : now our module specific actions */
 1920   if ( strcmp( BR_LAB_LABEL, action ) == 0 ) {
 1921 
 1922     /* : call our handler for this case */
 1923     BAF_CATCH_ERR( br_res, br_lab_handle_label( msg_ref ) ) {
 1924       BAF_ERROR();
 1925     }
 1926 
 1927   }
 1928 
 1929   else {
 1930 
 1931     /* : it's an unsuported action type */
 1932     br_res = BR_LAB_UNSUPPORTED;
 1933     BAF_ERROR();
 1934 
 1935   }
 1936 
 1937   BAF_CATCH( endo_msg_reply_success( msg_ref ) ) {
 1938     br_res = BR_LAB_CANT_REPLY;
 1939     BAF_ERROR();
 1940   }
 1941 
 1942   BAF_OUT(PUBLIC);
 1943 
 1944 
 1945  BAF_ERROR:
 1946   
 1947   /* : make sure that we have an error */
 1948   if ( br_res == BR_LAB_OK )
 1949     br_res = BR_LAB_FAIL;
 1950 
 1951   /* : reply with the error, ignore any trouble in the reply */
 1952   BAF_CATCH( endo_msg_reply_err( msg_ref, br_lab_s_error[br_res] ) ) {
 1953     BAF_ERROR_MSG("br_label can't reply error" );
 1954   }
 1955 
 1956   BAF_THROW_MSG( br_lab_s_error[br_res] );
 1957 }
 1958 
 1959 
 1960 
 1961 
 1962 /******************************************************************************
 1963 
 1964  (c) MMIII, NeuralVR Technologies Ltd., All Rights Reserved.
 1965 
 1966  MODULE: br_umat.c
 1967 
 1968  SYNOPSIS
 1969  Returns a umat calc on a given som
 1970 
 1971  NOTE
 1972  One action, 'umat'.
 1973 
 1974  umat
 1975  ----
 1976  Takes the following args:
 1977      s - code_path -> code file
 1978      d - average ( 1 for yes, 0 for no ) ( default is both these 0 )
 1979      d - median ( 1 for yes, 0 for no )
 1980 
 1981  Allocates and returns array of floats.
 1982      p - pointer to an array of floats ( xdim * ydim big )
 1983      d - xdim
 1984      d - ydim
 1985      f - minimum distance between nodes
 1986      f - max distance between nodes
 1987 
 1988 ******************************************************************************/
 1989 
 1990 #include "umat.h"
 1991 
 1992 /* : for results */
 1993 typedef enum {
 1994   BR_UMAT_OK,
 1995   BR_UMAT_FAIL,
 1996   BR_UMAT_BAD_PARAMS,
 1997   BR_UMAT_BAD_CODE_FILE,
 1998   BR_UMAT_CANT_REPLY,
 1999   BR_UMAT_UNSUPPORTED
 2000 } BR_UMAT_RES;
 2001 
 2002 static char *br_umat_s_error[] = {
 2003   "br_umat no error",
 2004   "br_umat general failure",
 2005   "br_umat bad parameters",
 2006   "br_umat bad code page file",
 2007   "br_umat can't reply",
 2008   "br_umat unsupported"
 2009 };
 2010 
 2011 #define UMAT_ACTION "umat"
 2012 
 2013 
 2014 /******************************************************************************
 2015 
 2016  FUNCTION: br_umat_umat
 2017 
 2018  SYNOPSIS
 2019  Allocates and returns a linear float buffer with the umat vals
 2020 
 2021  HISTORY
 2022  Created  by dab
 2023 
 2024 ******************************************************************************/
 2025 
 2026 static BR_UMAT_RES
 2027 br_umat_umat(
 2028 char *code_path,
 2029 int average,
 2030 int median,
 2031 float **pp_umat_ret,
 2032 int *xdim,
 2033 int *ydim,
 2034 double *d_min,
 2035 double *d_max
 2036 )
 2037 {
 2038   BR_UMAT_RES umat_res = 0;
 2039   float *umat_ret = NULL;
 2040   struct umatrix *umat = NULL;
 2041   int x, y;
 2042 
 2043   BAF_IN(PRIVATE);
 2044 
 2045   label_not_needed(1);
 2046 
 2047   umat = read_map( code_path, 0, 0 );
 2048   if ( umat == NULL ) {
 2049     umat_res = BR_UMAT_BAD_CODE_FILE;
 2050     BAF_ERROR_MSG("can't load code file" );
 2051   }
 2052   calc_umatrix( umat, 0, 0, d_min, d_max);
 2053 
 2054   if ( average == 1 )
 2055     average_umatrix( umat );
 2056 
 2057   if ( median == 1 )
 2058     median_umatrix( umat );
 2059 
 2060   /* : allocate our return buffer */
 2061   TAKE( *pp_umat_ret ,(float *), sizeof(float)*((umat->uydim)*(umat->uxdim))) {
 2062     BAF_ERROR_MSG("can't allocate for return buffer" );
 2063   }
 2064   umat_ret = *pp_umat_ret;
 2065 
 2066   /* : print the results to our return buffer */
 2067   for (y = 0; y < umat->uydim; y++) {
 2068     for (x = 0; x < umat->uxdim; x++) {
 2069       *umat_ret = (float)(umat->uvalue[x][y] * 100.0);
 2070       umat_ret++;
 2071     }
 2072   }
 2073 
 2074   /* : return our dimensions */
 2075   *xdim = umat->uxdim;
 2076   *ydim = umat->uydim;
 2077 
 2078   if ( umat != NULL ) {
 2079     free_umat( umat );
 2080     umat = NULL;
 2081   }
 2082   
 2083   BAF_OUT(PRIVATE);
 2084 
 2085 
 2086  BAF_ERROR:
 2087 
 2088   if ( umat_res == BR_UMAT_OK )
 2089     umat_res = BR_UMAT_FAIL;
 2090 
 2091   if ( umat != NULL ) {
 2092     free_umat( umat );
 2093     umat = NULL;
 2094   }
 2095   
 2096   BAF_THROW_ERR( umat_res );
 2097 }
 2098 
 2099 
 2100 /******************************************************************************
 2101 
 2102  FUNCTION: br_umat_handle_umat
 2103 
 2104  SYNOPSIS
 2105  Handles the umat action
 2106 
 2107  HISTORY
 2108  Created  by dab
 2109 
 2110 ******************************************************************************/
 2111 
 2112 static BR_UMAT_RES
 2113 br_umat_handle_umat(
 2114 ENDO_MSG_REF msg,
 2115 float **pp_umat_ret,
 2116 int *xdim,
 2117 int *ydim,
 2118 double *d_min,
 2119 double *d_max
 2120 )
 2121 {
 2122   BR_UMAT_RES br_res = 0;
 2123   char *code_path = NULL;
 2124   int average = 0;
 2125   int median = 0;
 2126 
 2127   BAF_IN(PRIVATE);
 2128 
 2129   BAF_CATCH( endo_msg_get_args( msg,
 2130                 "sdd",
 2131                 &code_path,
 2132                 &average,
 2133                 &median ) ) {
 2134     br_res = BR_UMAT_BAD_PARAMS;
 2135     BAF_ERROR();
 2136   }
 2137 
 2138   /* : umat */
 2139   BAF_CATCH_ERR( br_res, br_umat_umat( code_path, average, median, 
 2140                    pp_umat_ret, xdim, ydim, d_min, d_max )){
 2141     BAF_ERROR();
 2142   }
 2143 
 2144   GIVE( code_path );
 2145 
 2146   BAF_OUT(PRIVATE);
 2147 
 2148 
 2149  BAF_ERROR:
 2150 
 2151   GIVE( code_path );
 2152 
 2153   if ( br_res == BR_UMAT_OK )
 2154     br_res = BR_UMAT_FAIL;
 2155 
 2156   BAF_THROW_ERR( br_res );
 2157 }
 2158 
 2159 
 2160 /******************************************************************************
 2161 
 2162  FUNCTION: br_umat
 2163 
 2164  SYNOPSIS
 2165  Main entry point for umatting
 2166 
 2167  HISTORY
 2168  Created  by dab
 2169 
 2170 ******************************************************************************/
 2171 
 2172 int
 2173 br_umat(
 2174 ENDO_MSG_REF msg,
 2175 char *action
 2176 )
 2177 {
 2178   BR_UMAT_RES br_res = 0;
 2179   float *umat_ret = NULL;
 2180   int xdim = 0;
 2181   int ydim = 0;
 2182   double d_min = 0.0;
 2183   double d_max = 0.0;
 2184 
 2185   BAF_IN(PUBLIC);
 2186 
 2187   /* : now our module specific actions */
 2188   if ( strcmp( UMAT_ACTION, action ) == 0 ) {
 2189 
 2190     /* : call the umat handler */
 2191     BAF_CATCH_ERR( br_res, br_umat_handle_umat( msg, &umat_ret, &xdim, &ydim,
 2192                         &d_min, &d_max) ) {
 2193       BAF_ERROR();
 2194     }
 2195 
 2196     /* : special return here */
 2197     BAF_CATCH( endo_msg_reply_args( msg, "pddff", umat_ret, xdim, ydim,
 2198                 (float)d_min, (float)d_max ) ) {
 2199       BAF_ERROR();
 2200     }
 2201 
 2202     /* : go directly to success as we've just replied */
 2203     goto SKIP_REPLY;
 2204 
 2205   }
 2206 
 2207   else {
 2208 
 2209     /* : it's an unsuported action type */
 2210     br_res = BR_UMAT_UNSUPPORTED;
 2211     BAF_ERROR();
 2212 
 2213   }
 2214 
 2215   /* : reply */
 2216   BAF_CATCH( endo_msg_reply_success( msg ) ) {
 2217     BAF_ERROR_MSG("can't reply success");
 2218   }
 2219 
 2220 
 2221  SKIP_REPLY:
 2222 
 2223   BAF_OUT(PUBLIC);
 2224 
 2225 
 2226  BAF_ERROR:
 2227 
 2228   /* : make sure that we have an error */
 2229   if ( br_res == BR_UMAT_OK )
 2230     br_res = BR_UMAT_FAIL;
 2231 
 2232   /* : reply with the error, ignore any trouble in the reply */
 2233   BAF_CATCH( endo_msg_reply_err( msg, br_umat_s_error[br_res] ) ) {
 2234     MSG(PUBLIC,"can't reply with error");
 2235   }
 2236 
 2237   BAF_THROW_MSG( br_umat_s_error[br_res] );
 2238 }
 2239 
 2240 
 2241 
 2242 
 2243 /******************************************************************************
 2244 
 2245  (c) MMIII, NeuralVR Technologies Ltd., All Rights Reserved.
 2246 
 2247  MODULE: br_som_main
 2248 
 2249  SYNOPSIS
 2250  Main entry point for module
 2251 
 2252  HISTORY
 2253  Created Apr 30, 98 by dab
 2254 
 2255 ******************************************************************************/
 2256 
 2257 /* : errors */
 2258 typedef enum {
 2259   SOM_OK,
 2260   SOM_FAIL,
 2261   SOM_CAN_GET_MODULE_LOCK,
 2262   SOM_UNSUPPORTED
 2263 } SOM_RES;
 2264 
 2265 /* : strings */
 2266 char *br_som_s_error[] = {
 2267   "br_som no error",
 2268   "br_som failure",
 2269   "br_som can't get module lock",
 2270   "br_som unsupported"
 2271 };
 2272 
 2273 /******************************************************************************
 2274 
 2275  FUNCTION: br_som
 2276 
 2277  SYNOPSIS
 2278  Switches to handler for each action type
 2279 
 2280  HISTORY
 2281  Created Apr 14, 98 by dab
 2282 
 2283  NOTES
 2284  Handler for each action returns reply 
 2285 
 2286 ******************************************************************************/
 2287 
 2288 int
 2289 br_som(
 2290 ENDO_MSG_REF msg_ref
 2291 )
 2292 {
 2293   char *action = NULL;
 2294   SOM_RES som_res = 0;
 2295   int opt_err = 0;
 2296 
 2297   BAF_IN(PUBLIC);
 2298 
 2299   BAF_CATCH( br_som_mod_lock_get() ) {
 2300     som_res = SOM_CAN_GET_MODULE_LOCK;
 2301     BAF_ERROR();
 2302   }
 2303 
 2304   opt_err = global_options( 0, NULL );
 2305 
 2306   BAF_CATCH( endo_msg_get_action( msg_ref, &action ) ) {
 2307     /* : we must reply with failure here */
 2308     som_res = SOM_FAIL;
 2309     BAF_ERROR();
 2310   }
 2311 
 2312   /* : now our module specific actions */
 2313   /* : modules reply with their own success and failure */
 2314 
 2315   /* : labeling */
 2316   if ( strcmp( BR_LAB_LABEL, action ) == 0 ) {
 2317 
 2318     /* : call our handler for this case */
 2319     BAF_CATCH( br_label( msg_ref, action ) ) {
 2320       BAF_ERROR();
 2321     }
 2322 
 2323   }
 2324 
 2325   /* : thinking */
 2326   else if ( strcmp( BR_THK_THINK, action ) == 0 ) {
 2327     
 2328     BAF_CATCH( br_think( msg_ref, action ) ) {
 2329       BAF_ERROR();
 2330     }
 2331 
 2332   }
 2333 
 2334   /* : learning, init */
 2335   /* : learning */
 2336   /* : learning, qerror */
 2337   else if ( (strcmp( BR_LRN_INIT, action ) == 0) ||
 2338         (strcmp( BR_LRN_LEARN, action ) == 0) ||
 2339         (strcmp( BR_LRN_QERROR, action ) == 0) ) {
 2340     
 2341     BAF_CATCH( br_learn( msg_ref, action ) ) {
 2342       BAF_ERROR();
 2343     }
 2344 
 2345 
 2346   }
 2347 
 2348   else if ( strcmp( action, UMAT_ACTION ) == 0 ) {
 2349 
 2350     BAF_CATCH( br_umat( msg_ref, action ) ) {
 2351       BAF_ERROR();
 2352     }
 2353 
 2354   }
 2355 
 2356   else {
 2357 
 2358     /* : it's an unsuported action type */
 2359     /* : we must reply with failure here */
 2360     som_res = SOM_UNSUPPORTED;
 2361     BAF_ERROR();
 2362 
 2363   }
 2364 
 2365   /* : handlers for each module reply with success */
 2366 
 2367   GIVE( action );
 2368 
 2369   BAF_CATCH( br_som_mod_lock_release() ) {
 2370     MSG(PUBLIC,"can't release module lock");
 2371   }
 2372 
 2373   BAF_OUT(PUBLIC);
 2374 
 2375 
 2376  BAF_ERROR:
 2377 
 2378   GIVE( action );
 2379 
 2380   BAF_CATCH( br_som_mod_lock_release() ) {
 2381     MSG(PUBLIC,"can't release module lock");
 2382   }
 2383 
 2384   if ( som_res == SOM_OK )
 2385     som_res = SOM_FAIL;
 2386 
 2387   /* : reply with the error, ignore any trouble in the reply */
 2388   BAF_CATCH( endo_msg_reply_err( msg_ref, br_som_s_error[som_res] ) ) {
 2389     MSG(PUBLIC,"can't reply with error");
 2390   }
 2391 
 2392   BAF_THROW_MSG( br_som_s_error[som_res] );
 2393 }
 2394 
 2395 
 2396 
 2397