home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / World_Of_Computer_Software-02-385-Vol-1of3.iso / r / rcc1.zip / rcc1 / rcc1.c next >
C/C++ Source or Header  |  1991-10-07  |  108KB  |  3,446 lines

  1. /*************************************************************************
  2.  * C implementation of the Recurrent Cascade-correlation learning algorithm
  3.  * 
  4.  * Written By:         Conor Doherty
  5.  *             Department of Computer Science
  6.  *             University College Dublin
  7.  *             Ireland
  8.  * 
  9.  *             Internet: cdohert@ccvax.ucd.ie
  10.  * 
  11.  * This code has been placed in the public domain by the author.  As a     
  12.  * matter of simple courtesy, anyone using or adapting this code is      
  13.  * expected to acknowledge the source.  The author would like to hear      
  14.  * about any attempts to use this system, successful or not.
  15.  * 
  16.  * This code is based on the common lisp implementation of Recurrent
  17.  * Cascade-Correlation written by Scott E. Fahlman (May 12, 1991
  18.  * version).  It is a modification of the C implementation of
  19.  * Cascade-Correlation written by R. Scott Crowder, III (version 1.32).
  20.  * Changes between Cascade-Correlation and Recurrent Cascade-Correlation
  21.  * are denoted by RCC in program comments.
  22.  * 
  23.  * Questions or bug reports about this implementation should be directed
  24.  * to Conor Doherty at the email address listed above.  Questions about
  25.  * the basic algorithm should be directed to Scott Fahlman (Internet
  26.  * address: Scott.Fahlman@cs.cmu.edu).
  27.  * 
  28.  * For an explanation of this algorithm and some results, see "The
  29.  * Recurrent Cascade-Correlation Learning Architecture" by Scott E.
  30.  * Fahlman in D. S. Touretzky (ed.), "Advances in Neural Information
  31.  * Processing Systems 3", Morgan Kaufmann, 1991.  A somewhat longer
  32.  * version is available as CMU Computer Science Tech Report
  33.  * CMU-CS-91-100.
  34.  * 
  35.  * A example network file and use of this program are included at the end
  36.  * of this file.
  37.  ************************************************************************/
  38.  
  39. #include <stdio.h>
  40. #include <math.h>
  41. #include <ctype.h>
  42. #include <signal.h>
  43. #include <time.h>
  44. #include <string.h>
  45.  
  46. #define VERSION   1.00
  47. #define REL_DATE  "RCC: Sept-25-91"
  48.  
  49. /* some stuff to make C code a little more readable                 */
  50. typedef int       BOOLEAN;
  51.  
  52. #ifdef mips
  53. /* Pmax compiler is almost ANSI, it just doesn't understand 'void *' */
  54. typedef char     *VOIDP;
  55. #else
  56. typedef void     *VOIDP;
  57. #endif
  58.  
  59. /*****************************************************************************/
  60. /* Parameter table contains all user settable parameters.  It is used by the */
  61. /* input routines to change the values of the named parameters.  The list of */
  62. /* parameters must be sorted alphabetically so that the search routine will  */
  63. /* work.  Parameter names are used as keywords in the search.  Keywords are  */
  64. /* lower case to speed the comparison process.                               */
  65. /*****************************************************************************/
  66.  
  67. struct parmentry {char *keyword;    /* variable name in lower case */
  68.           int vartype;      /* can be INT, FLOAT, or ENUM */
  69.           VOIDP varptr;     /* cast to correct type before use */
  70.         };
  71.  
  72. typedef struct parmentry PARMS;
  73.  
  74. /* general symbols */
  75. #define TRUE      1
  76. #define FALSE     0
  77. #define BOMB      -99
  78. #define LINELEN   80
  79. #define EOL       '\0'
  80.  
  81. /* switches used in the interface routines */
  82. #define INT         0
  83. #define FLOAT       1
  84. #define ENUM        2      /* interger values that use #defines */
  85. #define BOOLE       3
  86. #define GETTRAINING 4
  87. #define GETTEST     5
  88. #define GO          6
  89. #define INT_NO      7      /* parameters only good in netfile */
  90. #define FLOAT_NO    8      /* most are used in memory allocation  */
  91. #define ENUM_NO     9      /* and cannot be changed mid-simulation */
  92. #define BOOLE_NO    10
  93. #define VALUE       11
  94. #define GETTRAININGFILE 12
  95. #define GETTESTFILE     13
  96. #define SAVE        14
  97. #define INITFILE    15
  98.  
  99.  
  100. #define NEXTLINE    0
  101. #define FAILURE    -1
  102.  
  103. /* switch constants */
  104.  
  105. #define SIGMOID        0
  106. #define GAUSSIAN       1
  107. #define LINEAR         2
  108. #define ASYMSIGMOID    3
  109. #define VARSIGMOID     4
  110.  
  111. #define WIN            20
  112. #define STAGNANT       21
  113. #define TIMEOUT        22
  114. #define LOSE           23
  115.  
  116. #define BITS           30
  117. #define INDEX          31
  118.  
  119. #define FATAL           0
  120. #define WARN            1
  121.  
  122.  
  123.  
  124. /* Allocate global storage */
  125. /***********************************************************************/
  126. /*  Assorted Parameters.                                               */
  127. /*  These parameters and switches control the quickprop learning       */
  128. /*  algorithm used to train the output weights.                        */
  129. /***********************************************************************/
  130. int UnitType;           /* hidden unit type can be SIGMOID or GAUSIAN*/
  131. int OutputType;               /* output unit type can be SIGMOID or LINEAR */
  132. float SigmoidMax;       /* Maximum output vaule for sigmoid units. Used */
  133.                            /* to alter sigmoid range without having to edit */ 
  134.                            /* training values.  Use the symbols "min" and  */
  135.                            /* "max" in the input file.  The input routines */ 
  136.                            /* will translate to the appropriate float values.*/
  137. float SigmoidMin;       /* Minimum output vaule for sigmoid units.  */
  138. float WeightRange;         /* Random-init weights in range [-WR,+WR] */
  139. float SigmoidPrimeOffset;  /* Add to sigmoid-prime to kill flat spots */
  140. float WeightMultiplier;       /* Scale Candidate correlation to get init weight */
  141. float OutputMu;           /* Mu used to quickprop train output weights. */
  142. float OutputShrinkFactor;  /* Used in computing whether the proposed step is */
  143.                            /* too large.  Related to OutputMu.               */
  144. float OutputEpsilon;       /* Controls the amount of linear gradient descent */
  145.                            /* to use in updating output weights.             */
  146. float OutputDecay;       /* This factor times the current weight is added  */
  147.                            /* to the slope at the start of each output epoch */
  148.                            /* Keeps weights from growing too big.            */
  149. int OutputPatience;       /* If we go for this many epochs with no real     */
  150.                            /* change, it's time to stop tuning.  If 0, go on */
  151.                            /* forever.                                       */
  152. float OutputChangeThreshold; /* The error must change by at least this */
  153.                            /* fraction of its old value to count as a  */
  154.                            /* significant change.                      */
  155. float InputMu;           /* Mu used to quickprop train input weights.  */
  156. float InputShrinkFactor;   /* Used in computing whether the proposed step is */
  157.                            /* too large.  Related to InputMu. */
  158. float InputEpsilon;       /* Controls the amount of linear gradient descent */
  159.                            /* to use in updating Input weights. */
  160. float InputDecay;       /* This factor times the current weight is added  */
  161.                            /* to the slope at the start of each Input epoch */
  162.                            /* Keeps weights from growing too big. */
  163. int InputPatience;       /* If we go for this many epochs with no real */
  164.                            /* change, it's time to stop tuning.  If 0, go on */
  165.                            /* forever. */
  166. float InputChangeThreshold; /* The error must change by at least this */
  167.                            /* fraction of its old value to count as a  */
  168.                            /* significant change. */
  169.  
  170. /***********************************************************************/
  171. /*  Variables related to error and correlation.                        */
  172. /***********************************************************************/
  173. float TrueError;           /* Total output error for one epoch */
  174. float ScoreThreshold;      /* This close to desired value => bit is correct */
  175. int   ErrorBits;           /* Total # bits in epoch that were wrong */
  176. float *SumErrors;       /* Accumulate the sum of the error values used in */
  177.                            /* the correlation phase. Sum is stored seperately */
  178.                /* for each output.  Values are converted to */
  179.                /* average errors before use in ADJUST_CORRELATION */
  180. float *DummySumErrors;       /* Replace SumErrors with this for test epochs. */
  181. float SumSqError;       /* Accumulate the sum of the square of the error  */
  182.                            /* values used in the correlation phase. */
  183. float BestCandidateScore;  /* Best correlation score of all candidate units. */
  184. int   BestCandidate;       /* Index of the candidate unit with best score. */
  185.  
  186. /***********************************************************************/
  187. /* These variables and switches control the simulation and display.    */
  188. /***********************************************************************/
  189. BOOLEAN UseCache;       /* If TRUE, cache the forward-pass values instead */
  190.                            /* of repeatedly computing them. */
  191. int     Epoch;             /* Current epoch number */
  192. BOOLEAN Graphics;       /* If TRUE, print progress after each epoch. */
  193. BOOLEAN NonRandomSeed;       /* TRUE => use 1 as the seed for the random */
  194.                 /* number generator.  Useful when comparing */
  195.                /* different parameter settings.  FALSE => use */
  196.                /* system clock to start random sequence. */
  197. BOOLEAN Test;           /* If TRUE, run a test epoch and print the result */
  198.                            /* after each round of output tuning. */
  199. BOOLEAN SinglePass;        /* TRUE => Pause after forward/backward cycle */
  200. BOOLEAN SingleEpoch;       /* TRUE => Pause after each training epoch */
  201. BOOLEAN Step;              /* Turned to TRUE after each pause, briefly */
  202. int Trial;           /* Current trial number, used in log outputs */
  203.  
  204. /***********************************************************************/
  205. /* The sets of training inputs and outputs.                            */
  206. /***********************************************************************/
  207. int   NTrainingPatterns;    /* !! Not in Lisp version.  Needed here. */
  208. int   NTestPatterns;        /* !! Not in Lisp version.  Needed here. */
  209. float **TrainingInputs;
  210. float **TrainingOutputs;
  211. float *Goal;                /* Goal vector for the current training or */
  212.                             /* testing case.                           */
  213. char *T_T_files;            /* Pointer to Training or Test filenames  */
  214.                             /* in input line updated by PROCESS_LINE, */ 
  215.                             /* each time the user needs a file for input */ 
  216.                             /* of training or test data. */
  217. /***************************************************************************/
  218. /*  For some benchmarks there is a separate set of values used for testing */
  219. /*  the network's ability to generalize.  These values are not used during */
  220. /*  training.                                                              */
  221. /***************************************************************************/
  222. float **TestInputs;
  223. float **TestOutputs;
  224. /***************************************************************************/
  225. /*                                                                         */
  226. /* Fundamental data structures.                                            */
  227. /*                                                                         */
  228. /* Unit outputs and weights are floats.                                    */
  229. /*                                                                         */
  230. /* Instead of representing each unit by a structure, we represent the      */
  231. /* unit by a int.  This is used to index into various arrays that hold     */
  232. /* per-unit information, such as the activation value of each unit.        */
  233. /*                                                                         */
  234. /* Per-connection information for each connection COMING INTO unit is      */
  235. /* stored in a array of arrays.  The outer array is indexed by the unit    */
  236. /* number, and the inner array is then indexed by connection number.       */
  237. /*                                                                         */
  238. /* Unit 0 is always at a maximum-on value.  Connections from this unit     */
  239. /* supply a bias.  Next come some input units, then some hidden units.     */
  240. /*                                                                         */
  241. /* Output units have their own separate set of data structures, as do      */
  242. /* candidate units whose inputs are currently being trained.               */
  243. /***************************************************************************/
  244. int   MaxUnits;           /* Maximum number of input values and hidden  */
  245.                            /* in the network. */
  246. int   Nunits;              /* Total number of active units in net */
  247. int   Ninputs;             /* Number of input units */
  248. int   Noutputs;            /* Number of output units */
  249. int   Ncandidates;       /* Number of candidate units trained at once. */
  250. int   MaxCases;           /* Maximum number of training cases that can be */
  251.                            /* accommdated by the current data structures.  */
  252. int   Ncases;           /* Number of training cases currently in use. */
  253.                            /* Assume a contiguous block beginning with   */
  254. int   FirstCase;       /* Address of the first training case in the     */
  255.                            /* currently active set.  Usually zero, but may  */
  256.                            /* differ if we are training on different chunks */
  257.                            /* of the training set at different times.       */
  258.  
  259. /***************************************************************************/
  260. /* The following vectors hold values related to hidden units in the active */
  261. /* net and their input weights.                                            */
  262. /***************************************************************************/
  263. float *Values;          /* Current activation value for each unit */
  264. float *PrevValues;         /* Previous hidden output values for use in RCC */
  265. float **ValuesCache;       /* Holds a distinct Values array for each of the */
  266.                            /* MaxCases training cases.                      */
  267. float *ExtraValues;       /* Extra Values vector to use when no cache. */
  268. int   *Nconnections;       /* # of INCOMING connections per unit */
  269. int   **Connections;       /* C[i][j] lists jth unit projecting to unit i */
  270. float **Weights;           /* W[i][j] holds weight of C[i][j] */
  271.  
  272. /***************************************************************************/
  273. /* The following arrays of arrays hold values for the outputs of the active*/
  274. /*  network and the output-side weights.                                   */
  275. /***************************************************************************/
  276. float *Outputs;            /* Network output values */
  277. float *Errors;             /* Final error value for each unit */
  278. float **ErrorsCache;       /* Holds a distinct Errors array for each of the */
  279.                            /* MaxCases training cases.                      */
  280. float *ExtraErrors;       /* Extra Errors vector to use when no cache. */
  281. float **OutputWeights;       /* OW[i][j] holds the weight from hidden unit i */    
  282.                            /* to output unit j */
  283. float **OutputDeltas;      /* Change between previous OW and current one */
  284. float **OutputSlopes;      /* Partial derivative of TotalError wrt OW[i][j] */
  285. float **OutputPrevSlopes;  /* Previous value of OutputSlopes[i][j] */
  286.  
  287. /***************************************************************************/
  288. /* The following arrays have one entry for each candidate unit in the      */
  289. /* pool of trainees.                                                       */
  290. /***************************************************************************/
  291. float *CandValues;         /* Current output value of each candidate unit.   */
  292. float *CandPrevValues;     /* Previous Candidate output values for RCC       */
  293. float *CandSumValues;      /* Output value of each candidate unit, summed    */
  294.                        /* over an entire training set.                   */
  295. float **CandCor;           /* Correlation between unit & residual error at   */
  296.                            /* each output, computed over a whole epoch.      */
  297. float **CandPrevCor;       /* Holds the CandCor values from last epoch.      */
  298. float **CandWeights;       /* Current input weights for each candidate unit. */
  299. float **CandDeltas;        /* Input weights deltas for each candidate unit.  */
  300. float **CandSlopes;        /* Input weights slopes for each candidate unit.  */
  301. float **CandPrevSlopes;    /* Holds the previous values of CandSlopes.       */
  302. float **CandDvDw;          /* For storing present values of dv/dw for RCC    */ 
  303.  
  304. /***************************************************************************/
  305. /* This saves memory if each candidate unit receives a connection from       */
  306. /* each existing unit and input.  That's always true at present, but may     */
  307. /* not be in future.                                                         */
  308. /***************************************************************************/
  309. int *AllConnections;       /* A standard connection that connects a unit to  */
  310.                            /* all previous units, in order, but not to the   */
  311.                            /* bias unit.*/
  312.  
  313. /***************************************************************************/
  314. /* ErrorIndex specific globals.  Not in release Lisp version               */
  315. /***************************************************************************/
  316. int NtrainingOutputValues;    /* Number of outputs in the training set.  */
  317. int NtestOutputValues;        /* Number of outputs in the test set.      */
  318. float TrainingStdDev;        /* Std Dev of entire training set.  Used to*/
  319.                                 /* normalize the ErrorIndex. */
  320. float TestStdDev;
  321. float ErrorIndex;        /* Normalized error function for continuos  */
  322.                                 /* output training sets. */
  323. float ErrorIndexThreshold;    /* Stop training when ErrorIndex is < EIT. */
  324. int ErrorMeasure;        /* Set to BITS for using ErrorBits to stop */
  325.                                 /* of INDEX to use ErrorIndex to stop.  */
  326.  
  327. /***************************************************************************/
  328. /* Save and plot file related varibles                                     */
  329. /***************************************************************************/
  330. BOOLEAN DumpWeights;        /* Are we dumping weights into a file. */
  331. char DumpFileRoot[LINELEN+1];    /* Root of the names for the files */
  332. FILE *WeightFile;        /* Contains weights from the current net. */
  333.  
  334. /**************************************************************************/
  335. /* Recurrent CC switches for scheduled network resets                     */
  336. /**************************************************************************/
  337. BOOLEAN UseTrainingBreaks; /* reset during training? */
  338. BOOLEAN UseTestBreaks;     /* reset during testing? */
  339. BOOLEAN *TrainingBreaks;   /* structure containing training reset schedule */
  340. BOOLEAN *TestBreaks;       /* structure containing test reset schedule */
  341.  
  342. /*********************************************************************/
  343. /* keyword table used for updating the simulation parameters without */
  344. /* recompilation.                                                    */
  345. /*********************************************************************/
  346. /*  RCC                                                                     */
  347. /*  "UseTrainingBreaks" & "UseTestBreaks" added to the parameter table.     */
  348. /*  If these parameters are specifed as TRUE in the network setup file,     */
  349. /*  a reset TRUE/FALSE must be specified with each training/test pattern.   */
  350. /****************************************************************************/
  351. PARMS ParmTable[] = {
  352.   {"errorindexthreshold",   FLOAT, (VOIDP)&ErrorIndexThreshold},
  353.   {"errormeasure",        ENUM_NO, (VOIDP)&ErrorMeasure},
  354.   {"go",                    GO,    (VOIDP)NULL}, /* special keyword */
  355.   {"graphics",             BOOLE,  (VOIDP)&Graphics},
  356.   {"inputchangethreshold",  FLOAT, (VOIDP)&InputChangeThreshold},
  357.   {"inputdecay",            FLOAT, (VOIDP)&InputDecay},
  358.   {"inputepsilon",          FLOAT, (VOIDP)&InputEpsilon},
  359.   {"inputmu",               FLOAT, (VOIDP)&InputMu},
  360.   {"inputpatience",         INT,   (VOIDP)&InputPatience},
  361.   {"maxunits",             INT_NO, (VOIDP)&MaxUnits},
  362.   {"ncandidates",          INT_NO, (VOIDP)&Ncandidates},
  363.   {"ninputs",              INT_NO, (VOIDP)&Ninputs},
  364.   {"nonrandomseed",         BOOLE, (VOIDP)&NonRandomSeed},
  365.   {"noutputs",             INT_NO, (VOIDP)&Noutputs},
  366.   {"ntestpatterns",        INT_NO, (VOIDP)&NTestPatterns},
  367.   {"ntrainingpatterns",    INT_NO, (VOIDP)&NTrainingPatterns},
  368.   {"outputchangethreshold", FLOAT, (VOIDP)&OutputChangeThreshold},
  369.   {"outputdecay",           FLOAT, (VOIDP)&OutputDecay},
  370.   {"outputepsilon",         FLOAT, (VOIDP)&OutputEpsilon},
  371.   {"outputmu",              FLOAT, (VOIDP)&OutputMu},
  372.   {"outputpatience",        INT,   (VOIDP)&OutputPatience},
  373.   {"outputtype",            ENUM,  (VOIDP)&OutputType},
  374.   {"quit",                  BOMB,  (VOIDP)NULL}, /* special keyword */
  375.   {"save",                  SAVE, (VOIDP)NULL}, /* special keyword */
  376.   {"scorethreshold",        FLOAT, (VOIDP)&ScoreThreshold},
  377.   {"sigmoidmax",         FLOAT_NO, (VOIDP)&SigmoidMax},
  378.   {"sigmoidmin",         FLOAT_NO, (VOIDP)&SigmoidMin},
  379.   {"sigmoidprimeoffset",    FLOAT, (VOIDP)&SigmoidPrimeOffset},
  380.   {"singleepoch",          BOOLE,  (VOIDP)&SingleEpoch},
  381.   {"singlepass",           BOOLE,  (VOIDP)&SinglePass},
  382.   {"test",                 BOOLE,  (VOIDP)&Test},
  383.   {"testing",            GETTEST,  (VOIDP)NULL}, /* special keyword */
  384.   {"training",       GETTRAINING,  (VOIDP)NULL}, /* special keyword */
  385.   {"unittype",            ENUM_NO, (VOIDP)&UnitType},
  386.   {"usecache",           BOOLE_NO, (VOIDP)&UseCache},
  387.   {"usetestbreaks",          BOOLE, (VOIDP)&UseTestBreaks},
  388.   {"usetrainingbreaks",      BOOLE, (VOIDP)&UseTrainingBreaks},
  389.   {"values",                VALUE, (VOIDP)NULL},      /* special keyword */
  390.   {"weightfile",          INITFILE,  (VOIDP)NULL}, /* special keyword */
  391.   {"weightmultiplier",      FLOAT, (VOIDP)&WeightMultiplier},
  392.   {"weightrange",           FLOAT, (VOIDP)&WeightRange}
  393. };
  394. int Nparameters =         /* Number of entries in ParmTable */
  395.   sizeof(ParmTable)/sizeof(PARMS);
  396. BOOLEAN InterruptPending;    /* TRUE => user has pressed Control-C */
  397.  
  398.  
  399. char ErrMsg[1025];        /* general error message buffer */
  400.  
  401. /******************** end of global storage allocation  **********************/
  402. #ifdef CONNX
  403. long conx;
  404. #endif
  405.  
  406. /***********************************************************************/
  407. /*                                                                     */
  408. /*    function prototypes  (ANSI format)                               */
  409. /*                                                                     */
  410. /***********************************************************************/
  411.  
  412. /************
  413. * main routines mostly C specific
  414. *************/
  415. void GET_NETWORK_CONFIGURATION(char *fname);
  416. VOIDP GET_ARRAY_MEM(unsigned elt_count, 
  417.             unsigned elt_size, char *fun_name);
  418. void ERROR(int type, char *message);
  419.  
  420.  
  421. /************
  422. * learning utilities
  423. *************/
  424. float ACTIVATION(float sum);
  425. float ACTIVATION_PRIME(float value, float sum);
  426. float OUTPUT_FUNCTION(float sum);
  427. float OUTPUT_PRIME(float out);
  428.  
  429. /************
  430. * Network-building utilities. 
  431. *************/
  432.  
  433. void BUILD_NET(void);
  434. float RANDOM_WEIGHT(void);
  435. void INIT_NET(void);
  436.  
  437.  
  438. /************
  439. * Interface utilities
  440. *************/
  441. int FIND_KEY(char *searchkey);
  442. void PRINT_VALUE(int k);
  443. void LIST_ALL_VALUES(void);
  444. void PROMPT_FOR_VALUE(int k);
  445. void GET_TRAINING_DATA(FILE *infile);
  446. void GET_TEST_DATA(FILE *infile);
  447. void GET_TEST_DATA_FILE(void);
  448. void GET_TRAINING_DATA_FILE(void);
  449. void add_extension(char *fname, char *ext);
  450. int PROCESS_LINE(char *line);
  451. void strdncase(char *s);
  452. BOOLEAN Y_OR_N_P(char *prompt);
  453. void INTERACTIVE_PARM_UPDATE(void);
  454. char *TYPE_STRING(int var);
  455. char *BOOLE_STRING(int var);
  456. int TYPE_CONVERT(char *input);
  457. void CHECK_INTERRUPT(void);
  458. void TRAP_CONTROL_C(int sig);
  459.  
  460.  
  461. /************
  462. * Parameter setting function.
  463. *************/
  464. void INITIALIZE_GLOBALS(void);
  465.  
  466. /************
  467. * Candidate training and selecting utilities
  468. *************/
  469. void INIT_CANDIDATES(void);
  470. void INSTALL_NEW_UNIT(void);
  471. void COMPUTE_CORRELATIONS(BOOLEAN reset);
  472. void ADJUST_CORRELATIONS(void);
  473. void COMPUTE_SLOPES(BOOLEAN reset);
  474. void UPDATE_INPUT_WEIGHTS(void);
  475.  
  476. /************
  477. * outer training loop
  478. *************/
  479.  
  480. void LIST_PARAMETERS(void);
  481. int TRAIN(int outlimit, int inlimit, int rounds, BOOLEAN interact);
  482. void TEST_EPOCH(float test_threshold);
  483. void PRINT_SUMMARY(void);
  484. void OUT_PASS_USER_INTERFACE(void);
  485. void OUT_EPOCH_USER_INTERFACE(void);
  486. void IN_EPOCH_USER_INTERFACE(void);
  487. void OUT_EPOCH_OUTPUT(void);
  488. void IN_EPOCH_OUTPUT(void);
  489. void OUT_PASS_OUTPUT(void);
  490.  
  491. /************
  492. * quickprop routine
  493. *************/
  494.  
  495. void QUICKPROP_UPDATE(int i, float weights[], float deltas[], float slopes[], 
  496.               float prevs[], float epsilon, float decay, float mu, 
  497.               float shrink_factor);
  498.  
  499.  
  500. /************
  501. * training functions
  502. *************/
  503.  
  504. void SETUP_INPUTS(float input[]);
  505. void OUTPUT_FORWARD_PASS(void);
  506. void COMPUTE_UNIT_VALUE(int j, BOOLEAN reset);
  507. void FULL_FORWARD_PASS(float input[], BOOLEAN reset);
  508. void COMPUTE_ERRORS(float goal[], 
  509.             BOOLEAN output_slopesp, BOOLEAN statsp);
  510. void UPDATE_OUTPUT_WEIGHTS(void);
  511. void TRAIN_OUTPUTS_EPOCH(void);
  512. int TRAIN_OUTPUTS(int max_epochs);
  513.  
  514.  
  515. /************
  516. * candidate train functions
  517. *************/
  518. void TRAIN_INPUTS_EPOCH(void);
  519. void CORRELATIONS_EPOCH(void);
  520. int TRAIN_INPUTS(int max_epochs);
  521.  
  522. /************
  523. * ErrorIndex routines
  524. *************/
  525.  
  526. float ERROR_INDEX(float std_dev, int num);
  527. float STANDARD_DEV(float **outputs, int npatterns, int nvalues);
  528.  
  529. void INTERACT_SAVE_FILES(void);
  530. void SAVE_NET_FILE(void);
  531. void GET_WEIGHTS(char *realfname);
  532. void INTERACT_GET_WEIGHTS(void);
  533. void DUMP_WEIGHTS(FILE *fout);
  534. void SAVE_ALL_PARMS(FILE *fout);
  535. void SAVE_PARM_VALUE(FILE *fout, int k);
  536. void SAVE_TRAINING_SET(FILE *fout);
  537. void SAVE_TEST_SET(FILE *fout);
  538. void DUMP_PARMS(FILE *fout);
  539. void WRITE_NET_OUTPUT(void);
  540. void WRITE_UNIT_OUTPUT(void);
  541. void INTERACT_DUMP_WEIGHTS(void);
  542. void INIT_DUMP_FILES(char *fname);
  543. void SETUP_DUMP_FILES(void);
  544.  
  545. /* function prototypes from <stdlib.h> */
  546.  
  547.  
  548. extern VOIDP calloc(unsigned etl_count, unsigned elt_size);
  549.  
  550. #ifdef __STDC__            /* compiler does conform to the standard */
  551. extern double atof(const char *s);
  552. extern char *strtok(char *s, char *set);
  553. #else                /* compiler doesn't conform to the standard */
  554. extern double atof();
  555. extern char *strtok();
  556. #endif
  557.  
  558. #ifndef INT_MAX
  559. #define INT_MAX 32767
  560. #endif
  561. /******************end of prototypes ****************************/
  562.  
  563.  
  564. #ifndef PREDICT_ONLY
  565.  
  566. main(int argc, char *argv[])
  567. {
  568.   int inlim, outlim, rounds, trials;
  569.   int nhidden;            /* number of hidden units used in run  */
  570.   int vics, defs, i;
  571.   long total_epochs, total_units, total_trials;
  572.   long min_units, max_units, min_epochs, max_epochs;
  573.   char fname[LINELEN+1];
  574.   BOOLEAN interact = FALSE;
  575.   /***************/
  576.  
  577.   if((argc != 1) && (argc != 6)){ /* wrong number of args */
  578.     printf("Usage: cascor NetFile InEpochs OutEpochs NewUnits Trials\n");
  579.     printf("   or  cascor\n");
  580.     return;
  581.   }
  582.   else if(argc == 1)
  583.     interact = TRUE;
  584.  
  585.   INITIALIZE_GLOBALS();
  586.  
  587.   /* initialize testing parms */
  588.   total_epochs = 0;
  589.   total_units = 0;
  590.   min_units = INT_MAX;
  591.   min_epochs = INT_MAX;
  592.   max_units = 0;
  593.   max_epochs = 0;
  594.   total_trials = 0;
  595.   vics = 0;
  596.   defs = 0;
  597.   /* Get network */
  598.   if(interact){
  599.     printf ("Enter name of network: "); scanf ("%s", fname);
  600.     }
  601.   else
  602.     strcpy(fname, argv[1]);
  603.  
  604.   GET_NETWORK_CONFIGURATION(fname);
  605.  
  606.   /* initialize the random number generator before initializing the network*/
  607.   if(NonRandomSeed)        /* Does user want a fixed sequence? */
  608.     srand(1);            /* Use a fixed starting point */
  609.   else
  610.     srand(time(NULL));        /* Use a random starting point */
  611.  
  612.   INIT_NET();
  613.  
  614.   /* Start the main processing loop */
  615.   do {
  616.     if(interact){
  617.       printf("Number of epochs to train inputs: "); scanf ("%d", &inlim);
  618.       printf("Number of epochs to train outputs: "); scanf ("%d", &outlim);
  619.       printf("Maximum number of new units: "); scanf ("%d", &rounds);
  620.       printf("Trials for this problem: "); scanf ("%d", &trials);
  621.       if(Y_OR_N_P("Change some parameters?")) INTERACTIVE_PARM_UPDATE();
  622.     }
  623.     else{
  624.       inlim = atoi(argv[2]);
  625.       outlim = atoi(argv[3]);
  626.       rounds = atoi(argv[4]);
  627.       trials = atoi(argv[5]);
  628.     }
  629.     printf("Starting run for %s, Ilim %d, Olim %d, MaxUnits %d, Trials %d.\n",
  630.        fname, inlim, outlim, rounds, trials);
  631.     if(NonRandomSeed)
  632.       printf(" Fixed starting point used for random weights.\n\n");
  633.     else
  634.       printf(" Random starting point used for random weights.\n\n");
  635.  
  636.     for(i=0;i<trials; i++){
  637.       Trial = i+1;
  638.       if(DumpWeights)
  639.     SETUP_DUMP_FILES();
  640.       printf("\n   Trial %d:\n", Trial);
  641.       switch (TRAIN (outlim, inlim, rounds, interact)){
  642.       case WIN:
  643.     vics++;
  644.     break;
  645.       case LOSE:
  646.     defs++;
  647.     break;
  648.       }
  649.       if(Test)TEST_EPOCH(ScoreThreshold);    /* how did we do? */
  650. #ifdef CONNX
  651.       printf(" Connection Crossings: %d\n\n", conx);
  652. #endif
  653.       /* collect trail stats */
  654.       nhidden = Nunits - Ninputs - 1;    /* don't count inputs or bias unit */
  655.       total_epochs += Epoch;
  656.       total_units += nhidden;
  657.       total_trials++;
  658.       min_epochs = (Epoch < min_epochs) ? Epoch : min_epochs;
  659.       max_epochs = (Epoch > max_epochs) ? Epoch : max_epochs;
  660.       min_units = (nhidden < min_units) ? nhidden : min_units;
  661.       max_units = (nhidden > max_units) ? nhidden : max_units;
  662.  
  663.       if(interact && Y_OR_N_P(" Do you want to save the current settings?"))
  664.     SAVE_NET_FILE();
  665.  
  666.       if(DumpWeights)
  667.     DUMP_WEIGHTS(WeightFile);
  668.       else if(interact && 
  669.           Y_OR_N_P(" Do you want to save the current weights?"))
  670.       INTERACT_DUMP_WEIGHTS();
  671.     }
  672.  
  673.     /* print out loop stats */
  674.     printf("\n\nTRAINING LOOP STATS\n");
  675.     LIST_PARAMETERS();
  676.     printf("\n Victories: %d, Defeats: %d, \n", vics, defs);
  677.     printf("   Training Epochs - Min: %d, Avg: %d,  Max: %d,\n", 
  678.        min_epochs, (total_epochs / total_trials), max_epochs);
  679.     printf("   Hidden Units -    Min: %d, Avg: %4.1f,  Max: %d,\n", 
  680.        min_units,((float)total_units /total_trials), max_units);
  681.  
  682.   }while((interact) && Y_OR_N_P("Do you want to run more trials?"));
  683.  
  684.   /* Test the sucker. */
  685.   if((interact) && Y_OR_N_P("Do you want to test the last network?"))
  686.     TEST_EPOCH(ScoreThreshold);
  687.   return(TRUE);
  688. }
  689.  
  690. #else                /* PREDICT_ONLY */
  691.  
  692. main(int argc, char *argv[])
  693. {
  694.   int i,j;
  695.   char nfname[LINELEN+1], wfname[LINELEN+1], dfname[LINELEN+1];
  696.   BOOLEAN interact = FALSE;
  697.   void GET_INPUT_DATA(char *dfname);
  698.   /***************/
  699.  
  700.   if((argc != 1) && (argc != 4)){ /* wrong number of args */
  701.     printf("Usage: castest NetFile WeightFile DataFile\n");
  702.     printf("   or  castest\n");
  703.     return;
  704.   }
  705.   else if(argc == 1)
  706.     interact = TRUE;
  707.  
  708.   INITIALIZE_GLOBALS();
  709.  
  710.   /* Get network */
  711.   if(interact){
  712.     printf ("Enter name of network file: "); scanf ("%s", nfname);
  713.     printf ("Enter name of weight file: "); scanf ("%s", wfname);
  714.     printf ("Enter name of data file: "); scanf ("%s", dfname);
  715.     }
  716.   else{
  717.     strcpy(nfname, argv[1]);
  718.     strcpy(wfname, argv[2]);
  719.     strcpy(dfname, argv[3]);
  720.   }
  721.  
  722.   GET_NETWORK_CONFIGURATION(nfname);
  723.   UseCache = FALSE;        /* no reason to use cache for prediction only */
  724.  
  725.   INIT_NET();
  726.  
  727.   GET_WEIGHTS(wfname);
  728.  
  729.   GET_INPUT_DATA(dfname);
  730.  
  731.   for(i=0; i<NTrainingPatterns; i++){
  732.     FULL_FORWARD_PASS(TrainingInputs[i], TrainingBreaks[i]);
  733.  
  734.     printf("Prediction for input %d: ", i+1);
  735.     for(j=0;  j<Noutputs; j++)
  736.       printf("%6.4f ", Outputs[j]);
  737.     printf("\n");
  738.   } 
  739.     
  740. }
  741.  
  742.  
  743. /* Read the next NTrainingPattern number of lines into the TrainingInput 
  744.  * This is for prediction only run, so there are no target outputs read.
  745.  */
  746. void GET_INPUT_DATA(char *dfname)
  747. {
  748.  int i,j;
  749.  FILE *infile;
  750.  char peek, foo[LINELEN+1];
  751.  /**************/
  752.  
  753.   add_extension(dfname, "dat");
  754.   if((infile = fopen (dfname, "r")) == NULL){
  755.     perror(dfname);
  756.     return;            /* back out if the file can't be opened */
  757.   }
  758.  
  759.  for (i=0; i<NTrainingPatterns; i++){
  760.    /* look at 1st char of next line. */
  761.    peek = fgetc(infile); ungetc(peek, infile); 
  762.    if(peek == '#' || peek == '\n'){
  763.      /* Throw away the line if it is a comment or blank. */
  764.      fgets(foo, LINELEN, infile); 
  765.      i--;
  766.    }
  767.    else
  768.      for (j=0; j<Ninputs; j++)
  769.        fscanf (infile, "%f", &TrainingInputs[i][j]);
  770.        if (UseTrainingBreaks){       /* RCC */
  771.            fscanf (infile,"%s",foo);
  772.        TrainingBreaks[i] = TYPE_CONVERT(foo);   
  773.      }
  774.        else TrainingBreaks[i] = FALSE;
  775.  }
  776. }
  777.   
  778. #endif                /* PREDICT_ONLY */
  779.  
  780. /*********************************************************************/
  781. /*  C specific functions                                             */
  782. /*********************************************************************/
  783.  
  784. /* Initialize all globals that are not problem dependent.  Put this function 
  785.  * in a seperate file to make changing parameters less painful.
  786.  */
  787.  
  788.  
  789. void INITIALIZE_GLOBALS(void)
  790. {
  791.   UnitType = SIGMOID;    
  792.   OutputType = SIGMOID;
  793.   SigmoidMin = -0.5;
  794.   SigmoidMax = 0.5;
  795.  
  796.   WeightRange = 1.0;
  797.   SigmoidPrimeOffset = 0.1;
  798.   WeightMultiplier = 1.0;
  799.  
  800.   OutputMu = 2.0;
  801.   OutputShrinkFactor = OutputMu /(1.0 + OutputMu);
  802.   OutputEpsilon = 0.35;
  803.   OutputDecay = 0.0001;
  804.   OutputPatience = 8;
  805.   OutputChangeThreshold = 0.01;
  806.  
  807.   InputMu = 2.0;
  808.   InputShrinkFactor = InputMu /(1.0 + InputMu);
  809.   InputEpsilon = 1.0;
  810.   InputDecay = 0.0;
  811.   InputPatience = 8;
  812.   InputChangeThreshold = 0.03;
  813.  
  814.   TrueError = 0.0;
  815.   ScoreThreshold = 0.35;
  816.   ErrorBits = 0;
  817.   BestCandidateScore = 0.0;
  818.   BestCandidate = 0;
  819.   UseCache = FALSE;
  820.   NonRandomSeed = FALSE;
  821.   Epoch = 0;
  822.   Trial = 0;
  823.   Graphics = FALSE;
  824.   Test = FALSE;
  825.   SinglePass = FALSE;
  826.   SingleEpoch = FALSE;
  827.   Step = FALSE;
  828.  
  829.   NTrainingPatterns = 0;
  830.   NTestPatterns = 0;
  831.  
  832.   UseTrainingBreaks = FALSE;  /* RCC */
  833.   UseTestBreaks = FALSE;      /* RCC */
  834.  
  835.   MaxUnits = 60;
  836.   Ninputs = 0;
  837.   Noutputs = 0;
  838.   Ncandidates = 8;
  839.  
  840.   signal(SIGINT, TRAP_CONTROL_C); /* initialize interrupt handler */
  841.   InterruptPending = FALSE;
  842.  
  843.   NtrainingOutputValues = 0;
  844.   NtestOutputValues = 0;
  845.   TrainingStdDev = 1.0;
  846.   TestStdDev = 1.0;
  847.   ErrorIndex = 0.0;
  848.   ErrorIndexThreshold = 0.2;
  849.   ErrorMeasure = BITS;
  850.   DumpWeights = FALSE;
  851. }
  852.  
  853.  
  854. /*
  855.  *  Get and initialize a network. 
  856.  */
  857. void GET_NETWORK_CONFIGURATION(char *fname)
  858. {
  859.   FILE  *infile;
  860.   char line[LINELEN+1];
  861.   /********/
  862.  
  863.   /* open network configuration file */
  864.   add_extension(fname, "net");
  865.   if((infile = fopen (fname, "r")) == NULL){
  866.     perror(fname);
  867.     exit(BOMB);
  868.   }
  869.  
  870.   /* process file one line at a time */
  871.   while((fgets(line,80,infile)) != NULL){
  872.     switch(PROCESS_LINE(line)){
  873.     case NEXTLINE:
  874.       break;
  875.     case GETTRAINING:
  876.       BUILD_NET(); /* have all the info we need by now */
  877.       GET_TRAINING_DATA(infile);  /* network must be built before the data */
  878.       break;              /* is read into the data structures */
  879.     case GETTEST:
  880.       GET_TEST_DATA(infile);
  881.       break;
  882.     case GETTRAININGFILE:
  883.       BUILD_NET();
  884.       GET_TRAINING_DATA_FILE();
  885.       break;
  886.     case GETTESTFILE:
  887.       GET_TEST_DATA_FILE();
  888.       break;
  889.     default:
  890.       break;
  891.     }
  892.   }
  893.   fclose(infile);
  894. }
  895.  
  896.  
  897. /* Protected memory allocation function for arrays.  Give the number of  */
  898. /* elements and the size of the elements.  If enough storage is available*/
  899. /* a void pointer is returned, else the program terminates.              */
  900. VOIDP GET_ARRAY_MEM(unsigned elt_count, unsigned elt_size, char *fun_name)
  901. {
  902.   VOIDP foo;
  903. /*********/
  904.  
  905.   if(!elt_count)elt_count = 1;    /* don't allocate a 0 element array */
  906.   foo = calloc(elt_count, elt_size);
  907.  
  908.   if(foo == NULL){
  909.     sprintf(ErrMsg, 
  910.         "Program ran out of memory.  Allocator called from %s\n", 
  911.         fun_name);
  912.     ERROR(FATAL, ErrMsg);
  913.   }
  914.   else
  915.     return(foo);
  916. }
  917.  
  918.  
  919. void ERROR(int type, char *message)
  920. {
  921.   fprintf(stderr, "%s\n", message);
  922.   if(type == FATAL)
  923.     abort(BOMB);
  924. }
  925.  
  926. /***********************************************************************/
  927. /*                                                                     */
  928. /*  Network-building utilities.                                        */
  929. /*                                                                     */
  930. /***********************************************************************/
  931.  
  932. /* Create the network data structures, given the number of input and output
  933.  * units.  Get the MaxUnits value from a variable.
  934.  */
  935. void BUILD_NET(void)
  936. {
  937.   int i;
  938.   char *fn = "BUILD_NET";
  939. /***************/
  940.  
  941.   if(NTrainingPatterns>NTestPatterns)
  942.     MaxCases = NTrainingPatterns;
  943.   else
  944.     MaxCases = NTestPatterns;
  945.   Ncases = NTrainingPatterns;
  946.   FirstCase = 0;
  947.   Nunits = 1 + Ninputs;
  948.  
  949.   /* setup for ErrorIndex */
  950.   NtrainingOutputValues = Noutputs * NTrainingPatterns; 
  951.   NtestOutputValues = Noutputs * NTestPatterns;
  952.   if(Nunits>MaxUnits)
  953.     ERROR(FATAL, "MaxUnits must be greater than Ninputs.");
  954.  
  955.   /* allocate memory for outer arrays */
  956.   ValuesCache = (float **)GET_ARRAY_MEM(MaxCases, sizeof(float *), fn);
  957.   ExtraValues = (float *)GET_ARRAY_MEM(MaxUnits, sizeof(float), fn);
  958.   Values = ExtraValues;
  959.   PrevValues = (float *)GET_ARRAY_MEM(MaxUnits, sizeof(float), fn);
  960.  
  961.   Nconnections = (int *)GET_ARRAY_MEM(MaxUnits, sizeof(int), fn);
  962.   Connections = (int **)GET_ARRAY_MEM(MaxUnits, sizeof(int *), fn);
  963.   Weights = (float **)GET_ARRAY_MEM(MaxUnits, sizeof(float *), fn);
  964.  
  965.   ErrorsCache = (float **)GET_ARRAY_MEM(MaxCases, sizeof(float *), fn);
  966.   ExtraErrors = (float *)GET_ARRAY_MEM(Noutputs, sizeof(float), fn);
  967.   SumErrors = (float *)GET_ARRAY_MEM(Noutputs, sizeof(float), fn);
  968.   DummySumErrors = (float *)GET_ARRAY_MEM(Noutputs, sizeof(float), fn);
  969.   Errors = ExtraErrors;
  970.     
  971.   Outputs = (float *)GET_ARRAY_MEM(Noutputs, sizeof(float), fn);
  972.   OutputWeights = (float **)GET_ARRAY_MEM(Noutputs, sizeof(float *), fn);
  973.   OutputDeltas = (float **)GET_ARRAY_MEM(Noutputs, sizeof(float *), fn);
  974.   OutputSlopes = (float **)GET_ARRAY_MEM(Noutputs, sizeof(float *), fn);
  975.   OutputPrevSlopes = (float **)GET_ARRAY_MEM(Noutputs, sizeof(float *), fn);
  976.  
  977.   CandValues = (float *)GET_ARRAY_MEM(Ncandidates, sizeof(float), fn);
  978.   CandSumValues = (float *)GET_ARRAY_MEM(Ncandidates, sizeof(float), fn);
  979.   CandCor = (float **)GET_ARRAY_MEM(Ncandidates, sizeof(float *), fn);
  980.   CandPrevCor = (float **)GET_ARRAY_MEM(Ncandidates, sizeof(float *), fn);
  981.   CandWeights = (float **)GET_ARRAY_MEM(Ncandidates, sizeof(float *), fn);
  982.   CandDeltas = (float **)GET_ARRAY_MEM(Ncandidates, sizeof(float *), fn);
  983.   CandSlopes = (float **)GET_ARRAY_MEM(Ncandidates, sizeof(float *), fn);
  984.   CandPrevSlopes = (float **)GET_ARRAY_MEM(Ncandidates, sizeof(float *), fn);
  985.  
  986.  
  987.   /* Allocate memory for RCC */
  988.   CandPrevValues = (float *)GET_ARRAY_MEM(Ncandidates, sizeof(float),fn); 
  989.   CandDvDw   = (float **)GET_ARRAY_MEM(Ncandidates, sizeof(float *), fn); 
  990.   TrainingBreaks = (BOOLEAN *)GET_ARRAY_MEM(NTrainingPatterns, sizeof(BOOLEAN),fn);
  991.   TestBreaks = (BOOLEAN *)GET_ARRAY_MEM(NTestPatterns, sizeof(BOOLEAN),fn);
  992.   
  993.  
  994.   TrainingInputs = (float **)GET_ARRAY_MEM(NTrainingPatterns,
  995.                        sizeof(float *), fn);
  996.   TrainingOutputs = (float **)GET_ARRAY_MEM(NTrainingPatterns, 
  997.                         sizeof(float *), fn);
  998.   if(NTestPatterns){
  999.     TestInputs = (float **)GET_ARRAY_MEM(NTestPatterns, sizeof(float *), fn);
  1000.     TestOutputs = (float **)GET_ARRAY_MEM(NTestPatterns, sizeof(float *), fn);
  1001.   }
  1002.   else{         /* no test patterns so just point at training set */
  1003.     TestInputs = TrainingInputs;
  1004.     TestOutputs = TrainingOutputs;
  1005.   }
  1006.  
  1007. /* Only create the caches if UseCache is on -- may not always have room. */
  1008.   if(UseCache){
  1009.     for(i=0; i<MaxCases; i++){
  1010.       ValuesCache[i] = (float *)GET_ARRAY_MEM(MaxUnits, sizeof(float), fn);
  1011.       ErrorsCache[i] = (float *)GET_ARRAY_MEM(Noutputs, sizeof(float), fn);
  1012.     }
  1013.   }
  1014.  
  1015.   /* Allocate per unit data arrays */
  1016.   for(i=0; i<Noutputs; i++){
  1017.     OutputWeights[i] = (float *)GET_ARRAY_MEM(MaxUnits, sizeof(float), fn);
  1018.     OutputDeltas[i] = (float *)GET_ARRAY_MEM(MaxUnits, sizeof(float), fn);
  1019.     OutputSlopes[i] = (float *)GET_ARRAY_MEM(MaxUnits, sizeof(float), fn);
  1020.     OutputPrevSlopes[i] = (float *)GET_ARRAY_MEM(MaxUnits, sizeof(float), fn);
  1021.   }
  1022.   for(i=0; i<Ncandidates; i++){
  1023.     CandCor[i] = (float *)GET_ARRAY_MEM(Noutputs, sizeof(float), fn);
  1024.     CandPrevCor[i] = (float *)GET_ARRAY_MEM(Noutputs, sizeof(float), fn);
  1025.     CandWeights[i] = (float *)GET_ARRAY_MEM(MaxUnits, sizeof(float), fn);
  1026.     CandDeltas[i] = (float *)GET_ARRAY_MEM(MaxUnits, sizeof(float), fn);
  1027.     CandSlopes[i] = (float *)GET_ARRAY_MEM(MaxUnits, sizeof(float), fn);
  1028.     CandPrevSlopes[i] = (float *)GET_ARRAY_MEM(MaxUnits, sizeof(float), fn);
  1029.     CandDvDw[i] = (float *)GET_ARRAY_MEM(MaxUnits, sizeof(float), fn);  /* RCC */
  1030. }
  1031.           
  1032.  
  1033.   /* Allocate per case data arrays */
  1034.   for(i=0; i<NTrainingPatterns; i++){
  1035.     TrainingInputs[i] = (float *)GET_ARRAY_MEM(Ninputs, sizeof(float), fn);
  1036.     TrainingOutputs[i] = (float *)GET_ARRAY_MEM(Noutputs, sizeof(float), fn);
  1037.   }
  1038.   for(i=0; i<NTestPatterns; i++){
  1039.     TestInputs[i] = (float *)GET_ARRAY_MEM(Ninputs, sizeof(float), fn);
  1040.     TestOutputs[i] = (float *)GET_ARRAY_MEM(Noutputs, sizeof(float), fn);
  1041.   }
  1042.  
  1043.   /* Allocate generic connection vector */
  1044.   AllConnections = (int *)GET_ARRAY_MEM(MaxUnits, sizeof(int), fn);
  1045. }
  1046.  
  1047.  /*
  1048.  * Return a float between -range and +range.
  1049.  */
  1050. float RANDOM_WEIGHT(void)
  1051. {
  1052.   return ( (float) (WeightRange * (rand()%1000 / 500.0)) - WeightRange);
  1053. }
  1054.  
  1055.  
  1056. /* Set up the network for a learning problem.  Clean up all the data
  1057.  * structures.  Initialize the output weights to random values controlled by
  1058.  * WeightRange.
  1059.  */
  1060. void INIT_NET(void)
  1061. {
  1062.   int i,j;
  1063.   char *fn = "INIT_NET";
  1064. /**********/
  1065.  
  1066.   /* Set up the AllConnections vector. */
  1067.   for(i=0; i<MaxUnits; i++)
  1068.     AllConnections[i] = i;
  1069.  
  1070.  
  1071.   /* Initialize the active unit data structures. */
  1072.   for(i=0; i<MaxUnits; i++){
  1073.     ExtraValues[i] = 0.0;
  1074.     PrevValues[i] = 0.0;  /* RCC */
  1075.     Nconnections[i] = 0;
  1076.     Connections[i] = NULL;
  1077.     Weights[i] = NULL;
  1078.   }
  1079.   /* Initialize the per-output data structures. */
  1080.   for(i=0; i<Noutputs; i++){
  1081.     Outputs[i] = 0.0;
  1082.     ExtraErrors[i] = 0.0;
  1083.     for(j=0; j<MaxUnits; j++){
  1084.       OutputWeights[i][j] = 0.0;
  1085.       OutputDeltas[i][j] = 0.0;
  1086.       OutputSlopes[i][j] = 0.0;
  1087.       OutputPrevSlopes[i][j] = 0.0;
  1088.     }
  1089.     /* Set up initial random weights for the input-to-output connections. */
  1090.     for(j=0; j<(Ninputs+1); j++)
  1091.       OutputWeights[i][j] = RANDOM_WEIGHT();
  1092.   }
  1093.  
  1094.   /* Initialize the caches if they are in use. */
  1095.   if(UseCache)
  1096.     for(j=0; j<MaxCases; j++){
  1097.       for(i=0; i<MaxUnits; i++)
  1098.     ValuesCache[j][i] = 0.0;
  1099.       for(i=0; i<Noutputs; i++)
  1100.     ErrorsCache[j][i] = 0.0;
  1101.     }
  1102.  
  1103.   /* Candidate units get initialized in a separate routine. */
  1104.   INIT_CANDIDATES();
  1105.  
  1106.   ExtraValues[0] = 1.0;        /* bias unit */
  1107.   Epoch = 0;
  1108.   Nunits = Ninputs + 1;  
  1109.   ErrorBits = 0;
  1110.   TrueError = 0.0;
  1111.   for(i=0; i<Noutputs; i++){
  1112.     SumErrors[i] = 0.0;
  1113.     DummySumErrors[i] = 0.0;
  1114.   }
  1115.   SumSqError = 0.0;
  1116.   BestCandidateScore = 0.0;
  1117.   BestCandidate = 0;
  1118. #ifdef CONNX
  1119.   conx = 0l;
  1120. #endif
  1121.  
  1122.   if(ErrorMeasure == INDEX){
  1123.     /* ErrorIndex initialization */
  1124.     ErrorIndex = 0.0;
  1125.     TrainingStdDev = STANDARD_DEV(TrainingOutputs, NTrainingPatterns, 
  1126.                   NtrainingOutputValues);
  1127.     TestStdDev = STANDARD_DEV(TestOutputs, NTestPatterns, 
  1128.                   NtestOutputValues);
  1129.   }
  1130. }
  1131.  
  1132. /***********************************************************************/
  1133. /* Learning Utilities                                                  */
  1134. /***********************************************************************/
  1135.  
  1136. /*
  1137.  * Given the sum of weighted inputs, compute the unit's activation value.
  1138.  * Defined unit types are SIGMOID, VARSIGMOID, and GAUSSIAN.
  1139.  */
  1140. float ACTIVATION(float sum)
  1141. {
  1142.   float temp;
  1143.  
  1144.   switch(UnitType){
  1145.   case SIGMOID: 
  1146.     /* Sigmoid function in range -0.5 to 0.5. */
  1147.     if (sum < -15.0) 
  1148.       return(-0.5);
  1149.     else if (sum > 15.0) 
  1150.       return(0.5);
  1151.     else 
  1152.       return (1.0 /(1.0 + exp(-sum)) - 0.5);
  1153.   case GAUSSIAN:
  1154.     /* Gaussian activation function in range 0.0 to 1.0. */
  1155.     temp = -0.5 * sum * sum;
  1156.     if (temp < -75.0) 
  1157.       return(0.0);
  1158.     else 
  1159.       return (exp(temp));
  1160.   case ASYMSIGMOID: 
  1161.     /* asymmetrical sigmoid function in range 0.0 to 1.0. */
  1162.     if (sum < -15.0) 
  1163.       return(0.0);
  1164.     else if (sum > 15.0) 
  1165.       return(1.0);
  1166.     else 
  1167.       return (1.0 /(1.0 + exp(-sum)));
  1168.   case VARSIGMOID: 
  1169.     /* Sigmoid function in range SigmoidMin to SigmoidMax. */
  1170.     if (sum < -15.0) 
  1171.       return(SigmoidMin);
  1172.     else if (sum > 15.0) 
  1173.       return(SigmoidMax);
  1174.     else 
  1175.       return ((SigmoidMax - SigmoidMin)/ (1.0 + exp(-sum)) + SigmoidMin);
  1176.   }
  1177. }
  1178.  
  1179.  
  1180. /*
  1181.  * Given the unit's activation value and sum of weighted inputs, compute
  1182.  * the derivative of the activation with respect to the sum.  Defined unit
  1183.  * types are SIGMOID, VARSIGMOID, and GAUSSIAN.
  1184.  *
  1185.  * Note: do not use sigmoid prime offset here, as it confuses the
  1186.  * correlation machinery.  But do use it in output-prime.
  1187.  * 
  1188.  */
  1189. float ACTIVATION_PRIME(float value, float sum)
  1190. {
  1191.   switch(UnitType){
  1192.   case SIGMOID: 
  1193.     /* Symmetrical sigmoid function. */
  1194.     return (0.25 -  value*value);
  1195.   case GAUSSIAN:
  1196.     /* Gaussian activation function. */
  1197.     return (sum * (- value));
  1198.   case ASYMSIGMOID: 
  1199.     /* asymmetrical sigmoid function in range 0.0 to 1.0. */
  1200.     return (value * (1.0 - value));
  1201.   case VARSIGMOID: 
  1202.     /* Sigmoid function with range SigmoidMin to SigmoidMax. */
  1203.     return ((value - SigmoidMin) * (1.0 - (value - SigmoidMin) / 
  1204.                     (SigmoidMax - SigmoidMin)));
  1205.   }
  1206. }
  1207.  
  1208. /* Compute the value of an output, given the weighted sum of incoming values.
  1209.  * Defined output types are SIGMOID, ASYMSIGMOID, and LINEAR.
  1210.  */
  1211. float OUTPUT_FUNCTION(float sum)
  1212. {
  1213.   switch(OutputType){
  1214.   case SIGMOID: 
  1215.     /* Symmetrical sigmoid function, used for binary functions. */
  1216.     if (sum < -15.0) 
  1217.       return(-0.5);
  1218.     else if (sum > 15.0) 
  1219.       return(0.5);
  1220.     else 
  1221.       return (1.0 /(1.0 + exp(-sum)) - 0.5);
  1222.   case LINEAR:
  1223.     /* Linear output function, used for continuous functions. */
  1224.     return (sum);
  1225.   case ASYMSIGMOID: 
  1226.     /* asymmetrical sigmoid function in range 0.0 to 1.0. */
  1227.     if (sum < -15.0) 
  1228.       return(0.0);
  1229.     else if (sum > 15.0) 
  1230.       return(1.0);
  1231.     else 
  1232.       return (1.0 /(1.0 + exp(-sum)));
  1233.   case VARSIGMOID: 
  1234.     /* Sigmoid function in range SigmoidMin to SigmoidMax. */
  1235.     if (sum < -15.0) 
  1236.       return(SigmoidMin);
  1237.     else if (sum > 15.0) 
  1238.       return(SigmoidMax);
  1239.     else 
  1240.       return ((SigmoidMax - SigmoidMin)/ (1.0 + exp(-sum))
  1241.           + SigmoidMin);
  1242.   }
  1243. }
  1244.  
  1245. /* Compute the value of an output, given the weighted sum of incoming values.
  1246.  * Defined output types are SIGMOID, ASYMSIGMOID, and LINEAR.
  1247.  *
  1248.  * Sigmoid_Prime_Offset used to keep the back-prop error value from going to 
  1249.  * zero.
  1250.  */
  1251. float OUTPUT_PRIME(float output)
  1252. {
  1253.   switch(OutputType){
  1254.   case SIGMOID: 
  1255.     /* Symmetrical sigmoid function, used for binary functions. */
  1256.     return (SigmoidPrimeOffset + 0.25 -  output*output);
  1257.   case LINEAR:
  1258.     /* Linear output function, used for continuous functions. */
  1259.     return (1.0);
  1260.   case ASYMSIGMOID: 
  1261.     /* asymmetrical sigmoid function in range 0.0 to 1.0. */
  1262.     return (SigmoidPrimeOffset + output * (1.0 - output));
  1263.   case VARSIGMOID: 
  1264.     /* Sigmoid function with range SigmoidMin to SigmoidMax. */
  1265.     return (SigmoidPrimeOffset + 
  1266.         (output - SigmoidMin) * (1.0 - (output - SigmoidMin) / 
  1267.                      (SigmoidMax - SigmoidMin)));
  1268.   }
  1269. }
  1270.  
  1271.  
  1272. /* The basic routine for doing quickprop-style update of weights, given a
  1273.  * pair of slopes and a delta.
  1274.  *
  1275.  * Given arrays holding weights, deltas, slopes, and previous slopes,
  1276.  * and an index i, update weight[i] and delta[i] appropriately.  Move
  1277.  * slope[i] to prev[i] and zero out slope[i].  Add weight decay term to
  1278.  * each slope before doing the update.
  1279.  */
  1280. void QUICKPROP_UPDATE(int i, float weights[], float deltas[], float slopes[], 
  1281.               float prevs[], float epsilon, float decay, float mu, 
  1282.               float shrink_factor)
  1283. {
  1284.   float w,d,s,p, next_step;
  1285.   /********/
  1286.  
  1287.   w = weights[i];
  1288.   d = deltas[i];
  1289.   s = slopes[i] +  decay * w;
  1290.   p = prevs[i];
  1291.   next_step = 0.0;
  1292.  
  1293.   /* The step must always be in direction opposite to the slope. */
  1294.  
  1295.   if(d < 0.0){            
  1296.     /* If last step was negative...  */  
  1297.     if(s > 0.0)      
  1298.       /*  Add in linear term if current slope is still positive.*/
  1299.       next_step -= epsilon * s;
  1300.     /*If current slope is close to or larger than prev slope...  */
  1301.     if(s >= (shrink_factor*p)) 
  1302.       next_step += mu * d;    /* Take maximum size negative step. */
  1303.     else
  1304.       next_step += d * s / (p - s); /* Else, use quadratic estimate. */
  1305.   }
  1306.   else if(d > 0.0){
  1307.     /* If last step was positive...  */
  1308.     if(s < 0.0)      
  1309.       /*  Add in linear term if current slope is still negative.*/
  1310.       next_step -= epsilon * s;
  1311.     /* If current slope is close to or more neg than prev slope... */
  1312.     if(s <= (shrink_factor*p)) 
  1313.       next_step += mu * d;    /* Take maximum size negative step. */
  1314.     else
  1315.       next_step += d * s / (p - s); /* Else, use quadratic estimate. */
  1316.   }
  1317.   else
  1318.     /* Last step was zero, so use only linear term. */
  1319.     next_step -= epsilon * s;
  1320.   
  1321.   /* update global data arrays */
  1322.   deltas[i] = next_step;
  1323.   weights[i] = w + next_step;
  1324.   prevs[i] = s;
  1325.   slopes[i] = 0.0;
  1326. }
  1327. /* Set up all the inputs from the INPUT vector as the first few entries in
  1328.    in the values vector.
  1329. */
  1330. void SETUP_INPUTS(float inputs[])
  1331. {
  1332.  
  1333.   int i;
  1334. /*********/
  1335.  
  1336.   Values[0]  = 1.0;        /* bias unit */
  1337.   for(i=0; i<Ninputs; i++)
  1338.     Values[i+1] = inputs[i];
  1339. }
  1340.  
  1341. /* Assume the values vector has been set up.  Just compute the output
  1342.    values.
  1343. */
  1344. void OUTPUT_FORWARD_PASS(void)
  1345. {
  1346.   int i,j;
  1347.   float sum;
  1348.   float *ow;
  1349. /********/
  1350.  
  1351.   for(j=0; j<Noutputs; j++){
  1352.     sum = 0.0;
  1353.     ow  = OutputWeights[j];
  1354.  
  1355.     for(i=0; i<Nunits; i++)
  1356.       sum += Values[i] * ow[i];
  1357.  
  1358. #ifdef CONNX
  1359.       conx += Nunits;
  1360. #endif
  1361.  
  1362.     Outputs[j] = OUTPUT_FUNCTION(sum);
  1363.   }
  1364.  
  1365. }
  1366.  
  1367. /* Assume that values vector has been set up for units with index less
  1368.    than J.  Compute and record the value for unit J.
  1369. */
  1370. void COMPUTE_UNIT_VALUE(int j, BOOLEAN reset)
  1371. {
  1372.   int i;
  1373.   int   *c;        /* pointer to unit's connections array */
  1374.   float *w,        /* pointer to unit's weights array*/
  1375.         sum = 0.0;
  1376. /********/
  1377.   
  1378.   c = Connections[j];
  1379.   w = Weights[j];
  1380.  
  1381.   for(i=0; i<Nconnections[j]-1; i++) 
  1382.           sum += Values[c[i]] * w[i];
  1383.   if(!reset)
  1384.      sum += PrevValues[j] * w[i]; /* RCC: autorecurrent connx */
  1385.  
  1386. #ifdef CONNX
  1387.     conx += Nconnections[j];
  1388. #endif
  1389.    
  1390.   Values[j] = ACTIVATION(sum); 
  1391.   PrevValues[j] = Values[j];  /* RCC */
  1392. }
  1393.  
  1394. /* Set up the inputs from the INPUT vector, then propagate activation values
  1395.    forward through all hidden units and output units.
  1396. */
  1397. void  FULL_FORWARD_PASS(float input[],BOOLEAN reset)
  1398. {
  1399.   int j;
  1400. /********/
  1401.  
  1402.   SETUP_INPUTS(input);
  1403.  
  1404.   /* Unit values must be calculated in order because the activations */
  1405.   /* cascade down through the hidden layers */
  1406.  
  1407.   for(j= 1+Ninputs; j<Nunits; j++) /* For each hidden unit J, compute the */
  1408.     COMPUTE_UNIT_VALUE(j,reset);    /* activation value. */
  1409.    
  1410.   OUTPUT_FORWARD_PASS();    /* Now compute outputs. */
  1411. }
  1412.  
  1413. /*  Goal is a vector of desired values for the output units.  Compute and
  1414.  *  record the output errors for the current training case.  Record error
  1415.  *  values and related statistics.  If output_slopesp is TRUE, then use errors
  1416.  *  to compute slopes for output weights.  If statsp is TRUE, accumulate error
  1417.  *  statistics. 
  1418.  */
  1419.  
  1420. void COMPUTE_ERRORS(float goal[], BOOLEAN output_slopesp, BOOLEAN statsp)
  1421. {
  1422.   int i,j;
  1423.   float out = 0.0,
  1424.         dif = 0.0,
  1425.         err_prime = 0.0;
  1426.   float *os;        /* pointer to unit's output slopes array */
  1427. /********/
  1428.  
  1429.   for(j=0; j<Noutputs; j++){
  1430.     out = Outputs[j];
  1431.     dif = out - goal[j];
  1432.     err_prime = dif * OUTPUT_PRIME(out);
  1433.     os = OutputSlopes[j];
  1434.  
  1435.     Errors[j] = err_prime;
  1436.  
  1437.     if (statsp){
  1438.       if (fabs(dif) > ScoreThreshold) ErrorBits++;
  1439.       TrueError += dif * dif;
  1440.       SumErrors[j] += err_prime;
  1441.       SumSqError += err_prime * err_prime;
  1442.     }
  1443.  
  1444.     if (output_slopesp)
  1445.       for(i=0; i<Nunits; i++)
  1446.     os[i] += err_prime * Values[i];
  1447.  
  1448.   }                /* end for unit j */
  1449. }
  1450.  
  1451. /* Update the output weights, using the pre-computed slopes, prev-slopes,
  1452.  * and delta values.
  1453.  */
  1454. void UPDATE_OUTPUT_WEIGHTS(void)
  1455. {
  1456.   int i,j;
  1457.   float eps;            /* epsilon scaled by fan-in */
  1458. /********/
  1459.  
  1460.   eps = OutputEpsilon / Ncases;
  1461.  
  1462.   for(j=0; j<Noutputs; j++)
  1463.     for(i=0; i<Nunits; i++)
  1464.       QUICKPROP_UPDATE(i, OutputWeights[j], OutputDeltas[j],
  1465.                OutputSlopes[j], OutputPrevSlopes[j], eps,
  1466.                OutputDecay, OutputMu, OutputShrinkFactor);
  1467.  
  1468. }
  1469.  
  1470. /***********************************************************************/
  1471. /*                                                                     */
  1472. /* The outer loops for training output weights.                        */
  1473. /*                                                                     */
  1474. /***********************************************************************/
  1475.  
  1476.  
  1477. /* Perform forward propagation once for each set of weights in the
  1478.  * training vectors, computing errors and slopes.  Then update the output
  1479.  * weights.
  1480.  */
  1481.  
  1482.  
  1483. void TRAIN_OUTPUTS_EPOCH(void)
  1484. {
  1485.   int i;
  1486. /********/
  1487.  
  1488.   /* zero error accumulators */
  1489.  
  1490.   
  1491.  
  1492.   ErrorBits = 0;
  1493.   TrueError = 0.0;
  1494.   for(i=0; i<Noutputs; i++)
  1495.     SumErrors[i] = 0.0;
  1496.  
  1497.   SumSqError = 0.0;
  1498.  
  1499.   
  1500.   /* User may have changed mu between epochs, so fix shrink-factor. */
  1501.   OutputShrinkFactor = OutputMu / (1.0 + OutputMu);
  1502.  
  1503.   for(i= FirstCase; i<(FirstCase+Ncases); i++){
  1504.     Goal = TrainingOutputs[i];
  1505.  
  1506.     if(UseCache){
  1507.       Values = ValuesCache[i];
  1508.       Errors = ErrorsCache[i];
  1509.       OUTPUT_FORWARD_PASS();
  1510.     }
  1511.     else{
  1512.       Values = ExtraValues;
  1513.       Errors = ExtraErrors;
  1514.       FULL_FORWARD_PASS(TrainingInputs[i], TrainingBreaks[i]);
  1515.     }
  1516.     COMPUTE_ERRORS(Goal, TRUE, TRUE);
  1517.     OUT_PASS_USER_INTERFACE();
  1518.   }
  1519.  
  1520.   switch (ErrorMeasure){
  1521.   case BITS:
  1522.     /* Do not change weights or count epoch if this run was a winner. */
  1523.     if(ErrorBits > 0){
  1524.       UPDATE_OUTPUT_WEIGHTS();
  1525.       Epoch++;
  1526.     }
  1527.     break;
  1528.   case INDEX:
  1529.     /* Compute index and don't change weights if we have a winner. */
  1530.     ErrorIndex = ERROR_INDEX(TrainingStdDev, NtrainingOutputValues);
  1531.     if(ErrorIndex > ErrorIndexThreshold){
  1532.       UPDATE_OUTPUT_WEIGHTS();
  1533.       Epoch++;
  1534.     }
  1535.     break;
  1536.   }
  1537.     
  1538.   OUT_EPOCH_USER_INTERFACE(); 
  1539. }
  1540.  
  1541. /* Train the output weights.  If we exhaust max_epochs, stop with value
  1542.  * TIMEOUT.  If there are zero error bits, stop with value WIN.  Else,
  1543.  * keep going until the true error has changed by a significant amount,
  1544.  * and then until it does not change significantly for Patience epochs.
  1545.  * Then return STAGNANT.  If Patience is zero, we do not stop until victory
  1546.  * or until max_epochs is used up.
  1547.  */
  1548.  
  1549. int TRAIN_OUTPUTS(int max_epochs)
  1550. {
  1551.   int i, o;
  1552.   int retval = TIMEOUT;      /* will be reset within loop for other conditions */
  1553.   float last_error = 0.0;
  1554.   int quit_epoch = Epoch + OutputPatience;
  1555.   BOOLEAN first_time = TRUE;
  1556. /********/
  1557.  
  1558.   for(i=0; i<max_epochs; i++){
  1559.     TRAIN_OUTPUTS_EPOCH();
  1560.  
  1561.     if((ErrorMeasure == BITS) && 
  1562.        (ErrorBits == 0)){
  1563.     retval = WIN;
  1564.     break;
  1565.       }
  1566.     else if((ErrorMeasure == INDEX) &&
  1567.         (ErrorIndex <= ErrorIndexThreshold)){
  1568.     retval = WIN;
  1569.     break;
  1570.       }
  1571.     else if(OutputPatience == 0)
  1572.       continue;            /* continue training until victory */
  1573.     else if(first_time){
  1574.       first_time = FALSE;
  1575.       last_error = TrueError;
  1576.     }
  1577.     else if(fabs(TrueError - last_error) > /* still getting better */
  1578.         (last_error * OutputChangeThreshold)){
  1579.       last_error = TrueError;
  1580.       quit_epoch = Epoch + OutputPatience;
  1581.     }
  1582.     else if(Epoch >= quit_epoch){ /* haven't gotten better for a while */
  1583.       retval = STAGNANT;
  1584.       break;
  1585.     }
  1586.   }
  1587.  
  1588.   /* tell user about the output weights of new unit */
  1589.   for(o=0; o<Noutputs; o++){
  1590.     printf("  Output %d Weights: ", o);
  1591.     for(i=0; i<Nunits; i++)
  1592.       printf("%6f ", OutputWeights[o][i]);
  1593.     printf("\n");
  1594.   }
  1595.  
  1596.   /* return result,  will be TIMEOUT unless reset in loop */
  1597.   return(retval);
  1598.  
  1599. }
  1600.  
  1601. /***********************************************************************/
  1602. /*                                                                     */
  1603. /*  Machinery for Training and selecting candidate units.              */
  1604. /*                                                                     */
  1605. /***********************************************************************/
  1606.  
  1607. /* Give new random weights to all of the candidate units.  Zero the other
  1608.  * candidate-unit statistics.
  1609.  */
  1610. void INIT_CANDIDATES(void)
  1611. {
  1612.   int i,j,o;
  1613. /********/
  1614.  
  1615.   for(i=0; i<Ncandidates; i++){
  1616.     CandValues[i] = 0.0;
  1617.     CandPrevValues[i] = 0.0;         /* RCC */
  1618.     CandSumValues[i] = 0.0;
  1619.     for(j=0; j<Nunits+1; j++){            /*  +1 for RCC  */
  1620.       CandWeights[i][j] = RANDOM_WEIGHT(); 
  1621.       CandDeltas[i][j] = 0.0;
  1622.       CandSlopes[i][j] = 0.0;
  1623.       CandPrevSlopes[i][j] = 0.0;
  1624.       CandDvDw[i][j] = 0.0;        /* RCC */
  1625.     }                                    
  1626.     for(o=0; o<Noutputs; o++){
  1627.       CandCor[i][o] = 0.0;
  1628.       CandPrevCor[i][o] = 0.0;
  1629.     }
  1630.   }
  1631. }
  1632.  
  1633. /* Add the candidate-unit with the best correlation score to the active
  1634.  * network.  Then reinitialize the candidate pool.
  1635.  */
  1636. void INSTALL_NEW_UNIT(void)
  1637. {
  1638.   int i,o;
  1639.   float wm;            /* temporary weight multiplier */
  1640.   float *w;            /* temporary weight array */
  1641.   float *cw;
  1642.   char *fn = "INSTALL_NEW_UNIT";
  1643. /********/
  1644.  
  1645.   if(Nunits >= MaxUnits)
  1646.     ERROR(FATAL, "Cannot add any more units. ");
  1647.  
  1648.   Nconnections[Nunits] = Nunits+1; 
  1649.   /* RCC: +1 => Connect Cand unit to itself */
  1650.   Connections[Nunits] = AllConnections;
  1651.   /* Set up the weight vector for the new unit. */
  1652.   w = (float *)GET_ARRAY_MEM(Nunits+1, sizeof(float),fn);
  1653.   cw = CandWeights[BestCandidate];
  1654.   for(i=0; i<Nunits+1; i++)  /* +1 for RCC */
  1655.     w[i] = cw[i];
  1656.   Weights[Nunits] = w;
  1657.  
  1658.   /* Tell user about the new unit. */
  1659.   printf(" Add unit %d: ", (Nunits+1));
  1660.   for(i=0; i<Nunits+1; i++)  /* +1 for RCC */
  1661.     printf("%6f ", Weights[Nunits][i]);
  1662.   printf("\n");
  1663.  
  1664.   /* Fix up output weights for candidate unit.  Use minus the           */
  1665.   /* correlation times the WeightMultiplier as an initial guess.        */
  1666.  
  1667.   if(ErrorMeasure == BITS)
  1668.     wm = WeightMultiplier;
  1669.   else                /* ErrorMeasure == INDEX */
  1670.     wm = WeightMultiplier / (float)Nunits;
  1671.  
  1672.   for(o=0; o<Noutputs; o++)
  1673.     OutputWeights[o][Nunits] = -CandPrevCor[BestCandidate][o] * wm;
  1674.  
  1675.   /* If using cache, run an epoch to compute this unit's values.        */
  1676.   if(UseCache)
  1677.     for(i=0; i<NTrainingPatterns; i++){
  1678.       Values = ValuesCache[i];
  1679.       COMPUTE_UNIT_VALUE(Nunits, TrainingBreaks[i]);
  1680.       
  1681.     }
  1682.  
  1683.   /* Reinitialize candidate units with random weights.                  */
  1684.   Nunits++;
  1685.   INIT_CANDIDATES();    
  1686.  
  1687. }
  1688.  
  1689.  
  1690. /* Note: Ideally, after each adjustment of the candidate weights, we would  */
  1691. /* run two epochs.  The first would just determine the correlations         */
  1692. /* between the candidate unit outputs and the residual error.  Then, in a   */
  1693. /* second pass, we would adjust each candidate's input weights so as to     */
  1694. /* maximize the absolute value of the correlation.  We need to know the     */
  1695. /* direction to tune the input weights.                                     */
  1696. /*                                                                          */
  1697. /* Since this ideal method doubles the number of epochs required for        */
  1698. /* training candidates, we cheat slightly and use the correlation values    */
  1699. /* computed BEFORE the most recent weight update.  This combines the two    */
  1700. /* epochs, saving us almost a factor of two.  To bootstrap the process, we  */
  1701. /* begin with a single epoch that computes only the correlation.            */
  1702. /*                                                                          */
  1703. /* Since we look only at the sign of the correlation after the first ideal  */
  1704. /* epoch and since that sign should change very infrequently, this probably */
  1705. /* is OK.  But keep a lookout for pathological situations in which this     */
  1706. /* might cause oscillation.                                                 */
  1707.  
  1708. /* For the current training pattern, compute the value of each candidate
  1709.  * unit and begin to compute the correlation between that unit's value and
  1710.  * the error at each output.  We have already done a forward-prop and
  1711.  * computed the error values for active units.
  1712.  */
  1713. void COMPUTE_CORRELATIONS(BOOLEAN reset)
  1714. {
  1715.   int i,o,u;
  1716.   float sum=0.0;
  1717.   float v=0.0;
  1718. /*********/
  1719.  
  1720.   for(u=0; u<Ncandidates; u++){
  1721.     sum = 0.0;
  1722.     v = 0.0;
  1723.     /* Determine activation value of each candidate unit. */
  1724.  
  1725.     for(i=0; i<Nunits; i++)           
  1726.       sum += CandWeights[u][i] * Values[i];
  1727.  
  1728.     if(!reset)
  1729.     sum += CandWeights[u][Nunits] * CandPrevValues[u];
  1730.  
  1731.  
  1732. #ifdef CONNX                              
  1733.     conx += Nunits+1; /* RCC: +1 */
  1734. #endif
  1735.   
  1736.  
  1737.     v = ACTIVATION(sum);
  1738.     CandValues[u] = v; 
  1739.     CandSumValues[u] += v;
  1740.     /* Accumulate value of each unit times error at each output. */
  1741.     for(o=0; o<Noutputs; o++)
  1742.       CandCor[u][o] += v * Errors[o];
  1743.   }
  1744. }
  1745.  
  1746.  
  1747. /* NORMALIZE each accumulated correlation value, and stuff the normalized
  1748.  * form into the CandPrevCor data structure.  Then zero CandCor to
  1749.  * prepare for the next round.  Note the unit with the best total
  1750.  * correlation score.
  1751.  */
  1752. void ADJUST_CORRELATIONS(void)
  1753. {
  1754.   int o,u;
  1755.   float cor, offset, score, csv;
  1756.   float *cc, *cpc;
  1757.   float avg_value;
  1758. /*********/
  1759.  
  1760.  
  1761.  
  1762.   BestCandidate = 0;
  1763.   BestCandidateScore = 0.0;
  1764.   for(u=0; u<Ncandidates; u++){
  1765.     avg_value = CandSumValues[u] / Ncases;
  1766.     cor = 0.0;
  1767.     score = 0.0;
  1768.     cc = CandCor[u];
  1769.     cpc = CandPrevCor[u];
  1770.     for(o=0; o<Noutputs; o++){
  1771.       cor = (cc[o] - avg_value * SumErrors[o]) / SumSqError;
  1772.       cpc[o] = cor;
  1773.       cc[o] = 0.0;
  1774.       score += fabs(cor);
  1775.     }
  1776.  
  1777.  
  1778.  
  1779.     /* zero CandSumValues for next epoch */
  1780.     CandSumValues[u] = 0.0;
  1781.     /* Keep track of the candidate with the best overall correlation. */
  1782.     if(score > BestCandidateScore){
  1783.       BestCandidateScore = score;
  1784.       BestCandidate = u;
  1785.     }
  1786.   }
  1787. }
  1788.  
  1789.  
  1790. /* After the correlations have been computed, we do a second pass over
  1791.  * the training set and adjust the input weights of all candidate units.
  1792.  */
  1793. void COMPUTE_SLOPES(BOOLEAN reset)
  1794. {
  1795.   int i,o,u;
  1796.   float sum, value, actprime, direction, error, change;
  1797.   float dsum;    /* RCC: holder for calculating dv/dw */
  1798. /*********/
  1799.  
  1800.   for(u=0; u<Ncandidates; u++){
  1801.     dsum = 0.0;
  1802.     sum = 0.0;
  1803.     value = 0.0;
  1804.     actprime = 0.0;
  1805.     direction = 0.0;
  1806.     change = 0.0;
  1807.     /* Forward pass through each candidate unit to compute activation-prime. */
  1808.  
  1809.     for(i=0; i< Nunits; i++)        
  1810.       sum += CandWeights[u][i] * Values[i];
  1811.     if(!reset)   /* RCC */
  1812.       sum += CandWeights[u][Nunits] * CandPrevValues[u]; 
  1813.  
  1814. #ifdef CONNX 
  1815.     conx += Nunits+1;                 /* RCC + 1 */
  1816. #endif
  1817.   
  1818.   
  1819.     value = ACTIVATION(sum);
  1820.     actprime = ACTIVATION_PRIME(value, sum);
  1821.     CandSumValues[u] += value;
  1822.     /* Now try to adjust the inputs so as to maximize the absolute value */
  1823.     /* of the correlation. */
  1824.     for(o=0; o<Noutputs; o++){
  1825.       error = Errors[o];
  1826.       direction = (CandPrevCor[u][o] < 0.0) ? -1.0 : 1.0;
  1827.       change -= direction *  ((error -SumErrors[o])/SumSqError);  
  1828.       CandCor[u][o] += error * value;         
  1829.  
  1830.     }                                         
  1831. /* Compute derivative of activation sum wrt
  1832.    all weights except recurrent one
  1833. */
  1834.  
  1835.     for(i=0; i<Nunits; i++){
  1836.       if (reset) CandDvDw[u][i] = 0.0;
  1837.       dsum = actprime * (Values[i] + (CandWeights[u][Nunits] * CandDvDw[u][i]));
  1838.       CandSlopes[u][i] += change * dsum;
  1839.       CandDvDw[u][i] = dsum;
  1840.       }
  1841.  
  1842. /**  RCC: Compute derivative of activation sum wrt
  1843.      the unit's auto-recurrent weight 
  1844. **/
  1845.       if (!reset) {
  1846.       dsum  = actprime * (CandPrevValues[u] + (CandWeights[u][Nunits] * CandDvDw[u][Nunits]));
  1847.       CandSlopes[u][Nunits] += change * dsum;
  1848.       CandDvDw[u][Nunits] = dsum;
  1849.     }
  1850.       CandPrevValues[u]= value;
  1851.   }
  1852.       
  1853. }
  1854.  
  1855. /* Update the input weights, using the pre-computed slopes, prev-slopes,
  1856.  * and delta values.
  1857.  */
  1858. void UPDATE_INPUT_WEIGHTS(void)
  1859. {
  1860.   int i,u;
  1861.   float eps;
  1862.   float *cw, *cd, *cs, *cp;
  1863. /*********/
  1864.  
  1865.   eps = InputEpsilon / (float)(Ncases * Nunits);
  1866.   for(u=0; u<Ncandidates; u++){
  1867.     cw = CandWeights[u];
  1868.     cd = CandDeltas[u];
  1869.     cs = CandSlopes[u];
  1870.     cp = CandPrevSlopes[u];
  1871.     for(i=0; i<Nunits+1; i++)  /* +1 for RCC */
  1872.       QUICKPROP_UPDATE(i, cw, cd, cs, cp, eps, InputDecay, InputMu, 
  1873.                InputShrinkFactor);
  1874.   }
  1875. }
  1876.  
  1877. /* For each training pattern, perform a forward pass and compute correlations.
  1878.  * Then perform a second forward pass and compute input slopes for the 
  1879.  * candidate units.  Finally, use quickprop update to adjust the input weights.
  1880.  */
  1881.  
  1882. void TRAIN_INPUTS_EPOCH(void)
  1883. {
  1884.   int i;
  1885. /********/
  1886.  
  1887.   for(i=FirstCase; i<(Ncases+FirstCase); i++){
  1888.     Goal = TrainingOutputs[i];
  1889.     if(UseCache){
  1890.       Values = ValuesCache[i];
  1891.       Errors = ErrorsCache[i];
  1892.     }
  1893.     else {
  1894.       Values = ExtraValues;
  1895.       Errors = ExtraErrors;
  1896.       FULL_FORWARD_PASS(TrainingInputs[i], TrainingBreaks[i]);
  1897.       COMPUTE_ERRORS(Goal, FALSE, FALSE);
  1898.      }
  1899.     COMPUTE_SLOPES(TrainingBreaks[i]);
  1900.   }
  1901.   /*  User may have changed mu between epochs, so fix shrink-factor.*/
  1902.   InputShrinkFactor = InputMu / (1.0 + InputMu);
  1903.  
  1904.   /* Now tweak the candidate unit input weights. */
  1905.   UPDATE_INPUT_WEIGHTS();
  1906.  
  1907.   /*  Fix up the correlation values for the next epoch.*/
  1908.   ADJUST_CORRELATIONS();
  1909.   Epoch++;
  1910.   IN_EPOCH_USER_INTERFACE();
  1911. }
  1912.  
  1913. /* Do an epoch through all active training patterns just to compute the
  1914.  * correlations.  After this one pass, we will update the correlations as we
  1915.  * train.
  1916.  */
  1917. void CORRELATIONS_EPOCH(void)
  1918. {
  1919.   int i;
  1920. /********/
  1921.  
  1922.   for(i=FirstCase; i<(Ncases+FirstCase); i++){
  1923.     Goal = TrainingOutputs[i];
  1924.     if(UseCache){
  1925.       Values = ValuesCache[i];
  1926.       Errors = ErrorsCache[i];
  1927.     }
  1928.     else {
  1929.       Values = ExtraValues;
  1930.       Errors = ExtraErrors;
  1931.       FULL_FORWARD_PASS(TrainingInputs[i], TrainingBreaks[i]);
  1932.       COMPUTE_ERRORS(Goal, FALSE, FALSE);
  1933.     }
  1934.     COMPUTE_CORRELATIONS(TrainingBreaks[i]);
  1935.   }
  1936.   /*  Fix up the correlation values for the next epoch. */
  1937.   ADJUST_CORRELATIONS();
  1938.   Epoch++;
  1939.   IN_EPOCH_USER_INTERFACE();
  1940. }
  1941.  
  1942. /* Train the input weights of all candidates.  If we exhaust max_epochs,
  1943.  * stop with value TIMEOUT.  Else, keep going until the best candidate unit's
  1944.  * score has changed by a significant amount, and then
  1945.  * until it does not change significantly for Patience epochs.  Then return
  1946.  * STAGNANT.  If Patience is zero, we do not stop until victory or until
  1947.  * max_epochs is used up.
  1948.  */
  1949. int TRAIN_INPUTS(int max_epochs)
  1950. {
  1951.   int i;
  1952.   float last_score = 0.0;
  1953.   int quit = max_epochs;
  1954.   BOOLEAN first_time = TRUE;
  1955. /**********/
  1956.  
  1957.   for(i=0; i<Noutputs; i++)    /* Convert to the average error for use in */
  1958.     SumErrors[i]  /=  Ncases;    /* calculation of the correlation. */
  1959.  
  1960.   CORRELATIONS_EPOCH();
  1961.  
  1962.   for(i=0; i<max_epochs; i++){
  1963.     TRAIN_INPUTS_EPOCH();
  1964.  
  1965.     if(InputPatience == 0)
  1966.       continue;            /* continue training until victory */
  1967.     else if(first_time){
  1968.       first_time = FALSE;
  1969.       last_score = BestCandidateScore;
  1970.     }
  1971.     else if(fabs(BestCandidateScore - last_score) > /* still getting better */
  1972.         (last_score * InputChangeThreshold)){
  1973.       last_score = BestCandidateScore;
  1974.       quit = i + InputPatience;
  1975.     }
  1976.     else if(i >= quit) /* haven't gotten better for a while */
  1977.       return(STAGNANT);
  1978.   }
  1979.  
  1980.   /* didn't return within the loop, so must have run out of time. */
  1981.   return(TIMEOUT);
  1982.  
  1983. }
  1984. /**********************************************************************/
  1985. /*                                                                    */
  1986. /*  The outer loop routines                                           */
  1987. /*                                                                    */
  1988. /**********************************************************************/
  1989.  
  1990.  
  1991. void LIST_PARAMETERS(void)
  1992. {
  1993. #ifdef __STDC__            /* does is compiler conform to the standard? */
  1994.   printf("\nRecurrent Cascor.c Version: %5.2f %s   Compiled: %s  %s\n", 
  1995.      VERSION, REL_DATE, __DATE__, __TIME__);
  1996. #else
  1997.   printf("\nRecurrent Cascor.c Version: %5.2f  %s\n", VERSION, REL_DATE);
  1998. #endif
  1999.   printf("Trial Number %d Parameters\n", Trial);
  2000.   printf("SigOff %4.2f, WtRng %4.2f, WtMul %4.2f\n",
  2001.      SigmoidPrimeOffset, WeightRange, WeightMultiplier);
  2002.   printf("OMu %4.2f, OEps %4.2f, ODcy %7.5f, OPat %d, OChange %4.2f\n",
  2003.       OutputMu, OutputEpsilon, OutputDecay, OutputPatience,
  2004.       OutputChangeThreshold);
  2005.   printf("IMu %4.2f, IEps %4.2f, IDcy %7.5f, IPat %d, IChange %4.2f\n",
  2006.       InputMu, InputEpsilon, InputDecay, InputPatience,
  2007.       InputChangeThreshold);
  2008.   printf("Utype: %s, Otype: %s, Pool %d\n",
  2009.       TYPE_STRING(UnitType), TYPE_STRING(OutputType), Ncandidates);
  2010.   printf("ErrMeas: %s, ScoreThres: %5.3f,   ErrIndThres: %5.3f\n",
  2011.      TYPE_STRING(ErrorMeasure), ScoreThreshold, ErrorIndexThreshold);
  2012. }
  2013.  
  2014.  
  2015.  
  2016. /* Train the output weights until stagnation or victory is reached.  Then
  2017.  * train the input weights to stagnation or victory.  Then install the best
  2018.  * candidate unit and repeat.  OUTLIMIT and INLIMIT are upper limits on the
  2019.  * number of cycles in the output and input phases.  ROUNDS is an upper
  2020.  * limit on the number of unit-installation cycles.
  2021.  */
  2022. int TRAIN(int outlimit, int inlimit, int  rounds, BOOLEAN interact)
  2023. {
  2024.   int i,r;
  2025. /***********/
  2026.  
  2027.   INIT_NET();
  2028.   LIST_PARAMETERS();
  2029.  
  2030.   if(UseCache)
  2031.     for(i=0; i<NTrainingPatterns; i++){
  2032.       Values = ValuesCache[i];
  2033.       SETUP_INPUTS(TrainingInputs[i]);
  2034.     }
  2035.  
  2036.   if(interact)
  2037.     if(Y_OR_N_P("Load weights from file?")) INTERACT_GET_WEIGHTS();
  2038.  
  2039.   for(r=0; r<rounds; r++){
  2040.     switch(TRAIN_OUTPUTS(outlimit)){
  2041.     case WIN:
  2042.       LIST_PARAMETERS();
  2043.       printf(
  2044.         "Victory at %d epochs, %d units, %d hidden, Error %6.4f EI %6.4f.\n",
  2045.          Epoch, Nunits, (Nunits - Ninputs - 1), TrueError, ErrorIndex);
  2046.       return(WIN);
  2047.     case TIMEOUT:      
  2048.       printf("Out Timeout: ");
  2049.       PRINT_SUMMARY(); 
  2050.       printf("\n");
  2051.       break;
  2052.     case STAGNANT:
  2053.       printf("Out Stagnant: ");
  2054.       PRINT_SUMMARY(); 
  2055.       printf("\n");
  2056.       break;
  2057.     default:
  2058.       printf("Bad return from TRAIN_OUTPUTS");
  2059.       break;
  2060.     }
  2061.  
  2062.     if(Test)TEST_EPOCH(0.49);     /* how are we doing? */
  2063.  
  2064.     switch(TRAIN_INPUTS(inlimit)){
  2065.     case TIMEOUT:      
  2066.       printf("Epoch %d: In Timeout  Correlation: %6.4f\n",
  2067.          Epoch, BestCandidateScore);
  2068.       break;
  2069.     case STAGNANT:
  2070.       printf("Epoch %d: In Stagnant  Correlation: %6.4f\n",
  2071.          Epoch, BestCandidateScore);
  2072.       break;
  2073.     default:
  2074.       printf("Bad return from TRAIN_INPUTS");
  2075.       break;
  2076.     }
  2077.  
  2078.     INSTALL_NEW_UNIT();
  2079.   }
  2080.   LIST_PARAMETERS();
  2081.   switch(TRAIN_OUTPUTS(outlimit)){
  2082.     case WIN:
  2083.       printf("Victory at %d epochs, %d units, %d hidden, Error %6.4f EI %6.4f.\n",
  2084.          Epoch, Nunits, (Nunits - Ninputs - 1), TrueError, ErrorIndex);
  2085.       return(WIN);
  2086.     case TIMEOUT: case STAGNANT:      
  2087.       printf("Defeat at %d units, ", Nunits);
  2088.       PRINT_SUMMARY();
  2089.       printf("\n");
  2090.       return(LOSE);
  2091.     default:
  2092.       printf("Bad return from TRAIN_OUTPUTS");
  2093.       break;
  2094.     }
  2095.  
  2096. }
  2097.  
  2098.  
  2099. /* Perform forward propagation once for each set of weights in the
  2100.  * testing vectors, computing errors.  Do not change any weights.
  2101.  */
  2102. void TEST_EPOCH(float test_threshold)
  2103. {
  2104.   int i;
  2105.  
  2106.   /* Globals must be saved from the last training phase. If they are not  */
  2107.   /* saved then the next unit will be training to correlate with the test */
  2108.   /* set error. */
  2109.   BOOLEAN old_UC = UseCache;    /* temporarily turn off cache */
  2110.   float old_ST = ScoreThreshold; /* save global */
  2111.   float old_TE = TrueError;    /* save global */
  2112.   float *old_SE = SumErrors;    /* save global */
  2113.   float old_SSE = SumSqError;    /* save global */
  2114.   /*********/
  2115.  
  2116.   ScoreThreshold = test_threshold;
  2117.   UseCache = FALSE;
  2118.  
  2119.   Values = ExtraValues;
  2120.   Errors = ExtraErrors;
  2121.   /* If no separate test inputs, use training inputs. */
  2122.   if(NTestPatterns == 0){
  2123.     TestInputs = TrainingInputs;    
  2124.     TestOutputs = TrainingOutputs;
  2125.     NTestPatterns = NTrainingPatterns;
  2126.   }
  2127.  
  2128.   /* Zero some accumulators. */
  2129.   ErrorBits = 0;
  2130.   TrueError = 0.0;
  2131.   SumErrors = DummySumErrors;
  2132.   SumSqError = 0.0;
  2133.  
  2134.   /* Now run all test patterns and report the results. */
  2135.   for(i=0; i<NTestPatterns; i++){
  2136.     Goal = TestOutputs[i];
  2137.     FULL_FORWARD_PASS(TestInputs[i], TestBreaks[i]);
  2138.     COMPUTE_ERRORS(Goal, FALSE, TRUE);
  2139.     OUT_PASS_USER_INTERFACE();
  2140.   } 
  2141.   if(ErrorMeasure == INDEX)
  2142.     ErrorIndex = ERROR_INDEX(TestStdDev, NtestOutputValues);
  2143.   printf("  Test set:: ");
  2144.   PRINT_SUMMARY();
  2145.   printf("\n");
  2146.  
  2147.   /* restore globals */
  2148.   UseCache = old_UC;        
  2149.   ScoreThreshold = old_ST;
  2150.   TrueError = old_TE;    
  2151.   SumErrors = old_SE;    
  2152.   SumSqError = old_SSE;
  2153.  
  2154. }
  2155.   
  2156. /* dummy functions until I put in a X interface */
  2157.  
  2158. void OUT_PASS_USER_INTERFACE(void)
  2159. {
  2160.   if(SinglePass){
  2161.     OUT_PASS_OUTPUT();
  2162.     while(TRUE)
  2163.       if(!SinglePass || Step){
  2164.     Step = FALSE;
  2165.     return;
  2166.       }
  2167.       else{
  2168.     if(Y_OR_N_P("Change some parameters?")) INTERACTIVE_PARM_UPDATE();
  2169.     SinglePass = Y_OR_N_P("Keep Stepping?");
  2170.     Step = TRUE;
  2171.       }
  2172.   }
  2173. }
  2174. /* print out epoch stuff
  2175.  */
  2176. void OUT_EPOCH_USER_INTERFACE(void)
  2177. {
  2178.   if(Graphics || SingleEpoch)
  2179.     OUT_EPOCH_OUTPUT();
  2180.  
  2181.   if(SingleEpoch)
  2182.     while(TRUE)
  2183.       if(!SingleEpoch || Step){
  2184.     Step = FALSE;
  2185.     return;
  2186.       }
  2187.       else{
  2188.     if(Y_OR_N_P("Change some parameters?")) INTERACTIVE_PARM_UPDATE();
  2189.     SingleEpoch = Y_OR_N_P("Keep Stepping?");
  2190.     Step = TRUE;
  2191.       }   
  2192.   CHECK_INTERRUPT();
  2193. }
  2194.  
  2195. void IN_EPOCH_USER_INTERFACE(void)
  2196. {
  2197.   if(Graphics || SingleEpoch)
  2198.    IN_EPOCH_OUTPUT();
  2199.  
  2200.   if(SingleEpoch)
  2201.     while(TRUE)
  2202.       if(!SingleEpoch || Step){
  2203.     Step = FALSE;
  2204.     return;
  2205.       }
  2206.       else{
  2207.     if(Y_OR_N_P("Change some parameters?")) INTERACTIVE_PARM_UPDATE();
  2208.     SingleEpoch = Y_OR_N_P("Keep Stepping?");
  2209.     Step = TRUE;
  2210.       }     
  2211.   CHECK_INTERRUPT();
  2212. }
  2213.  
  2214. /* print out the things interesting after a pass.
  2215.  */
  2216. void OUT_PASS_OUTPUT(void)
  2217. {
  2218.   int i;
  2219.  
  2220.   printf(" Outputs: ");
  2221.   for(i=0;  i<Noutputs; i++)
  2222.     printf("%6.4f ", Outputs[i]);
  2223.  
  2224.   printf("\n Errors: ");
  2225.   for(i=0;i<Noutputs;i++)
  2226.     printf("%6.4f ", Errors[i]);
  2227.  
  2228.   printf("\n Values: ");
  2229.   for(i=0;i<Nunits;i++)
  2230.     printf("%6.4f ", Values[i]);
  2231.  
  2232.   printf("\n\n");
  2233. }
  2234.  
  2235.  
  2236. /* print out the things interesting after an in epoch.
  2237.  */
  2238. void IN_EPOCH_OUTPUT(void)
  2239. {
  2240.   int i,j;
  2241.  
  2242.   printf(" Epoch: %d, BestCandidate: %d, BestCandidateScore: %7.5f \n",
  2243.      Epoch, BestCandidate, BestCandidateScore);
  2244.  
  2245.   if(SingleEpoch){
  2246.     printf("Candidate Weights: ");
  2247.     for(i=0;i<Ncandidates;i++){
  2248.       printf("\nCandidate %d::", i+1);
  2249.       for(j=0;j<Nunits;j++)
  2250.     printf("%6.4f ", CandWeights[i][j]);
  2251.     }
  2252.     
  2253.     printf("\n\nCandidateDeltas: ");
  2254.     for(i=0;i<Ncandidates;i++){
  2255.       printf("\nCandidate %d::", i+1);
  2256.       for(j=0;j<Nunits;j++)
  2257.     printf("%6.4f ", CandDeltas[i][j]);
  2258.     }
  2259.     
  2260.     printf("\n\nCandidate Correlations: ");
  2261.     for(i=0;i<Ncandidates;i++){
  2262.       printf("\nCandidate %d::", i+1);
  2263.       for(j=0;j<Noutputs;j++)
  2264.     printf("%6.4f ", CandPrevCor[i][j]);
  2265.     }
  2266.     printf("\n\n");
  2267.   }
  2268. }
  2269.  
  2270.  
  2271. /* print out the things interesting after an out epoch.
  2272.  */
  2273. void OUT_EPOCH_OUTPUT(void)
  2274. {
  2275.   int i,j;
  2276.   
  2277.   PRINT_SUMMARY();
  2278.  
  2279.   if(SingleEpoch){
  2280.     printf("OutputWeights: ");
  2281.     for(i=0;i<Noutputs;i++){
  2282.       printf("\nOutput Unit %d::", i+1);
  2283.       for(j=0;j<Nunits;j++)
  2284.     printf("%6.4f ", OutputWeights[i][j]);
  2285.     }
  2286.     
  2287.     printf("\n\nOutputDeltas: ");
  2288.     for(i=0;i<Noutputs;i++){
  2289.       printf("\nOutput Unit %d::", i+1);
  2290.       for(j=0;j<Nunits;j++)
  2291.     printf("%6.4f ", OutputDeltas[i][j]);
  2292.     }
  2293.     printf("\n\n");
  2294.   }
  2295. }
  2296.  
  2297. /* Print the summary statistics based on the value of ErrorMeasure.
  2298.  */
  2299. void PRINT_SUMMARY(void)
  2300. {
  2301.   switch(ErrorMeasure){
  2302.   case BITS:
  2303.     printf(" Epoch %d, %d bits wrong, error %6.4f.\n\n",
  2304.        Epoch, ErrorBits, TrueError);
  2305.     break;
  2306.   case INDEX:
  2307.     printf(" Epoch %d, ErrorIndex %6.4f, TrueError %6.4f.\n",
  2308.        Epoch, ErrorIndex, TrueError);
  2309.     break;
  2310.   }
  2311.  
  2312. }
  2313.  
  2314.  
  2315. /*********************************************************************/
  2316. /*  interface functions                                              */
  2317. /*********************************************************************/
  2318. #ifndef __STDC__      /* compiler doesn't conform to the standard */
  2319. extern double atof();
  2320. extern char *strtok();
  2321. #endif
  2322.   
  2323. /* Convert '\0' terminated sting to all lower case characters.  This routine
  2324.  * is destructive.
  2325.  */
  2326. void strdncase(char *s)
  2327. {
  2328.   int i;
  2329.   /************/
  2330.  
  2331.   for(i=0; s[i] != EOL; i++)
  2332.     if(isupper(s[i]))
  2333.       s[i] = tolower(s[i]);    /* tolower only guaranteed on upper case */
  2334.     else
  2335.       s[i] = s[i];
  2336.  
  2337. }
  2338.  
  2339. /* Given a keyword string, return the index into the keyword table.
  2340.  * Assumes that the keys are in alphabetacal order.  Keyword comparison
  2341.  * is all lower case.  Return FAILURE when not found.
  2342.  */
  2343. int FIND_KEY(char *searchkey)
  2344. {
  2345.   int lower = 0;
  2346.   int upper = Nparameters - 1; 
  2347.   int m,dif;
  2348.   /************/
  2349.  
  2350.   strdncase(searchkey);        /* convert case for comparison */
  2351.  
  2352.   while(lower <= upper){
  2353.     m = (upper + lower) / 2;
  2354.     dif = strcmp(searchkey, ParmTable[m].keyword);
  2355.     if(dif<0)
  2356.       upper = m - 1;        /* look in lower half */
  2357.     else if(dif == 0)
  2358.       return(m);        /* found it */
  2359.     else if(dif > 0)
  2360.       lower = m + 1;        /* look in upper half */
  2361.   }
  2362.   
  2363.   /* search failed */
  2364.   return(FAILURE);
  2365. }
  2366.  
  2367. /* Parse a line of input into keyword value pairs and reset the given 
  2368.  * parameters to given values.  Comment lines start with the character
  2369.  * '#' and are ignored.  If a bad keyword is given a message is printed,
  2370.  * but processing continues.  The routine returns a value telling the 
  2371.  * calling routine whether to grap another line, read in  the training, 
  2372.  * or read in testing data.  The special keywords "Training", and 
  2373.  * "Testing" signal the changes in status.
  2374.  */
  2375. int PROCESS_LINE(char *line)
  2376. {
  2377.   int k = 0;            /* location in ParmTable */
  2378.   char *keytok;            /* token pointer */
  2379.   char *valtok;            /* token pointer */
  2380.   static char *seperators = " \t\v\f\r\n,"; /* white space plus comma  */
  2381.   /*************/
  2382.  
  2383.   /* check for comment character */
  2384.   if(line[0] == '#' || line[0] == '\n')
  2385.     return(NEXTLINE);        /* skip comment and blank lines */
  2386.   else{
  2387.  
  2388.     keytok = strtok(line, seperators); /* get first token */
  2389.     while(keytok != NULL){
  2390.       k = FIND_KEY(keytok);
  2391.  
  2392.       if(k != FAILURE){
  2393.     /* get value token for this parameter */
  2394.     valtok = strtok(NULL, seperators);
  2395.  
  2396.     /* read value in correct format */
  2397.     switch(ParmTable[k].vartype){ 
  2398.     case INT: case INT_NO:
  2399.       *(int *)ParmTable[k].varptr = atoi(valtok);
  2400.       break;
  2401.     case FLOAT: case FLOAT_NO:
  2402.       *(float *)ParmTable[k].varptr = (float)atof(valtok);
  2403.       break;
  2404.     case ENUM: case ENUM_NO: case BOOLE: case BOOLE_NO:
  2405.       *(int *)ParmTable[k].varptr = TYPE_CONVERT(valtok);
  2406.       break;
  2407.         case GETTRAINING:
  2408.           if (valtok!=NULL) {
  2409.              T_T_files = valtok;
  2410.              return(GETTRAININGFILE); /* get training data from a file */
  2411.              }
  2412.           else
  2413.              return(GETTRAINING); /* return and start getting training data */
  2414.         case GETTEST:
  2415.           if (valtok!=NULL) {
  2416.              T_T_files = valtok;
  2417.              return(GETTESTFILE); /* get test data from a file */
  2418.              }
  2419.           else
  2420.              return(GETTEST);        /* return and start getting test data */
  2421.     case INITFILE:
  2422.       INIT_DUMP_FILES(valtok);
  2423.       break;
  2424.     case GO: case VALUE: case BOMB: case SAVE:
  2425.       sprintf(ErrMsg, 
  2426.           "%s keyword only legal in interactive mode.", keytok);
  2427.       ERROR(WARN, ErrMsg);
  2428.       break;
  2429.     default:
  2430.       sprintf(ErrMsg, 
  2431.           "%d: bad vartype for parameter %s.  No update performed.", 
  2432.           ParmTable[k].vartype, keytok);
  2433.       ERROR(WARN, ErrMsg);
  2434.       break;
  2435.     }
  2436.       }
  2437.       else{            /* bad key */
  2438.     sprintf(ErrMsg, 
  2439.         "%s: not in parameter table.  No update performed.", keytok);
  2440.     ERROR(WARN, ErrMsg);
  2441.       }
  2442.       /* get next keyword token */
  2443.       keytok = strtok(NULL, seperators);    
  2444.     }                /* end while still keytok */
  2445.     return(NEXTLINE);
  2446.   }                /* end if comment */
  2447. }
  2448.  
  2449.  
  2450. /* Allow the user to interactively change parameters.  First they enter a 
  2451.  * parameter name, then the new value.  "GO" causes the function
  2452.  * to return.
  2453.  */
  2454. void INTERACTIVE_PARM_UPDATE(void)
  2455. {
  2456.   int k = 0;            /* location in ParmTable */
  2457.   char keytok[LINELEN];
  2458.   /*************/
  2459.  
  2460.   /* clear interrupt */
  2461.   InterruptPending = FALSE;    
  2462.  
  2463.   printf("Type <parameter name> to inspect or change the current value \n");
  2464.   printf("  of <parameter name>.\n");
  2465.   printf("Type 'go' to continue simulation or 'quit' to stop.\n");
  2466.   printf("Type 'values' to inspect the current values of all parameters\n");
  2467.  
  2468.   printf("Enter Parameter: "); scanf("%s", keytok);
  2469.   
  2470.   while(strcmp(keytok, "")){
  2471.     if(keytok[0] == '?'){
  2472.       printf("Type <parameter name> to inspect or change the current value \n");
  2473.       printf("  of <parameter name>.\n");
  2474.       printf("Type 'go' to continue simulation or 'quit' to stop.\n");
  2475.       printf("Type 'values' to inspect the current values of all parameters\n");
  2476.     }      
  2477.     else{
  2478.       k = FIND_KEY(keytok);
  2479.       if(k != FAILURE){
  2480.     /* read value in correct format */
  2481.     switch(ParmTable[k].vartype){ 
  2482.     case INT: case FLOAT: case ENUM: case BOOLE:
  2483.       PROMPT_FOR_VALUE(k);
  2484.       break;
  2485.     case GO:
  2486.       return;
  2487.     case VALUE:
  2488.       LIST_ALL_VALUES();
  2489.       break;
  2490.     case INT_NO: case FLOAT_NO: case ENUM_NO: case BOOLE_NO:
  2491.       printf("%s can only be changed in the .net file.\n",
  2492.          ParmTable[k].keyword);
  2493.       break;
  2494.     case BOMB:
  2495.       exit(FALSE);
  2496.     case SAVE:
  2497.       INTERACT_SAVE_FILES();
  2498.       break;
  2499.     case INITFILE:
  2500.       printf(" Enter name of dump files: "); scanf("%s", keytok);
  2501.       INIT_DUMP_FILES(keytok);
  2502.       break;
  2503.     default:
  2504.       sprintf(ErrMsg, 
  2505.           "%d: bad vartype for variable %s.  No update performed.", 
  2506.           ParmTable[k].vartype, keytok);
  2507.       ERROR(WARN, ErrMsg);
  2508.       break;
  2509.     }
  2510.       }
  2511.       else{            /* bad key */
  2512.     sprintf(ErrMsg, 
  2513.         "%s: not in parameter table.  Try again.", keytok);
  2514.     ERROR(WARN, ErrMsg);
  2515.       }
  2516.     }
  2517.     /* get next keyword token */
  2518.     printf("Enter Parameter: "); scanf("%s", keytok);
  2519.   }                /* end while still keytok */
  2520. }                
  2521.  
  2522. void PROMPT_FOR_VALUE(int k)
  2523. {
  2524.   char valtok[LINELEN];
  2525.   /***************/
  2526.  
  2527.   /* read value in correct format */
  2528.   switch(ParmTable[k].vartype){ 
  2529.   case INT:
  2530.     printf("%s[%d]: ", ParmTable[k].keyword, 
  2531.        *(int *)ParmTable[k].varptr);
  2532.     scanf("%d", (int *)ParmTable[k].varptr);
  2533.     break;
  2534.   case FLOAT:
  2535.     printf("%s[%6.4f]: ", ParmTable[k].keyword, 
  2536.        *(float *)ParmTable[k].varptr);
  2537.     scanf("%f", (float *)ParmTable[k].varptr);
  2538.     break;
  2539.   case ENUM:
  2540.     printf("%s[%s]: ", ParmTable[k].keyword, 
  2541.        TYPE_STRING(*(int *)ParmTable[k].varptr));
  2542.     scanf("%s", valtok);
  2543.     *(int *)ParmTable[k].varptr = TYPE_CONVERT(valtok);
  2544.     break;
  2545.   case BOOLE:
  2546.     printf("%s[%s]: ", ParmTable[k].keyword, 
  2547.        BOOLE_STRING(*(int *)ParmTable[k].varptr));
  2548.     scanf("%s", valtok);
  2549.     *(int *)ParmTable[k].varptr = TYPE_CONVERT(valtok);
  2550.     break;
  2551.   default:
  2552.     break;
  2553.   }
  2554. }
  2555.  
  2556. void LIST_ALL_VALUES(void)
  2557. {
  2558.   int i;
  2559.   for (i=0; i<Nparameters; ++i)
  2560.     PRINT_VALUE(i);
  2561. }
  2562.  
  2563. void PRINT_VALUE(int k)
  2564. {
  2565.   switch(ParmTable[k].vartype){ 
  2566.   case INT: case INT_NO:
  2567.     printf(" %s[%d]\n", ParmTable[k].keyword, 
  2568.        *(int *)ParmTable[k].varptr);
  2569.     break;
  2570.   case FLOAT: case FLOAT_NO:
  2571.     printf(" %s[%6.4f]\n", ParmTable[k].keyword, 
  2572.        *(float *)ParmTable[k].varptr);
  2573.     break;
  2574.   case ENUM: case ENUM_NO:
  2575.     printf(" %s[%s]\n", ParmTable[k].keyword, 
  2576.        TYPE_STRING(*(int *)ParmTable[k].varptr));
  2577.     break;
  2578.   case BOOLE: case BOOLE_NO:
  2579.     printf(" %s[%s]\n", ParmTable[k].keyword, 
  2580.        BOOLE_STRING(*(int *)ParmTable[k].varptr));
  2581.     break;
  2582.   case INITFILE:
  2583.     printf(" %s[%s]\n", ParmTable[k].keyword, 
  2584.        BOOLE_STRING(DumpWeights));
  2585.     break;
  2586.   default:
  2587.     break;            /* skip anything else */
  2588.   }
  2589. }
  2590.  
  2591. int TYPE_CONVERT(char *input)
  2592. {
  2593.   char ErrorMessage[80];
  2594.     strdncase(input);
  2595.   
  2596.   if(!strcmp(input,"true"))
  2597.     return(TRUE);
  2598.   else if(!strcmp(input,"1"))    /* allow backward compatiple input */
  2599.     return(TRUE);
  2600.   else if(!strcmp(input,"false"))
  2601.     return(FALSE);
  2602.   else if(!strcmp(input,"0"))    /* allow backward compatiple input */
  2603.     return(FALSE);
  2604.   else if(!strcmp(input,"sigmoid"))
  2605.     return(SIGMOID);
  2606.   else if(!strcmp(input,"gaussian"))
  2607.     return(GAUSSIAN);
  2608.   else if(!strcmp(input,"linear"))
  2609.     return(LINEAR);
  2610.   else if(!strcmp(input,"asymsigmoid"))
  2611.     return(ASYMSIGMOID);
  2612.   else if(!strcmp(input,"varsigmoid"))
  2613.     return(VARSIGMOID);
  2614.   else if(!strcmp(input,"bits"))
  2615.     return(BITS);
  2616.   else if(!strcmp(input,"index"))
  2617.     return(INDEX);
  2618.   else {
  2619.     sprintf(ErrorMessage, "Bad string sent to TYPE_CONVERT %s", input);
  2620.     ERROR(FATAL, ErrorMessage);
  2621.   }
  2622. }
  2623.  
  2624. /* Input of the type variables and return a string showing its value.  This
  2625.  * is only used as a output routine for the user's convenience. 
  2626.  */
  2627. char *TYPE_STRING(int var)
  2628. {
  2629.   switch (var) {
  2630.   case SIGMOID:
  2631.     return("SIGMOID");
  2632.   case GAUSSIAN:
  2633.     return("GAUSSIAN");
  2634.   case LINEAR:
  2635.     return("LINEAR");
  2636.   case ASYMSIGMOID:
  2637.     return("ASYMSIGMOID");
  2638.   case VARSIGMOID:
  2639.     return("VARSIGMOID");
  2640.   case WIN:
  2641.     return("WIN");
  2642.   case STAGNANT:
  2643.     return("STAGNANT");
  2644.   case TIMEOUT:
  2645.     return("TIMEOUT");
  2646.   case LOSE:
  2647.     return("LOSE");
  2648.   case BITS:
  2649.     return("BITS");
  2650.   case INDEX:
  2651.     return("INDEX");
  2652.   default: 
  2653.     return("Bad type");
  2654.  
  2655.  }
  2656. }
  2657.  
  2658. char *BOOLE_STRING(int var)
  2659. {
  2660.   switch (var) {
  2661.   case FALSE:
  2662.     return("FALSE");
  2663.   case TRUE:
  2664.     return("TRUE");
  2665.   default: 
  2666.     return("Bad BOOLEAN type");
  2667.  }
  2668. }
  2669.   
  2670. BOOLEAN Y_OR_N_P(char *prompt)
  2671. {
  2672.   char response[LINELEN+1];
  2673.   /*************/
  2674.  
  2675.   printf ("%s (y or n) ", prompt);
  2676.   scanf("%s", response);
  2677.  
  2678.   if((response[0] == 'y') || (response[0] == 'Y'))
  2679.     return(TRUE);
  2680.   else 
  2681.     return(FALSE);
  2682. }
  2683.  
  2684. /********************************************************************/
  2685. /*   interrupt handling routines                                    */
  2686. /*   Thanks to Dimitris Michailidis for this code.                  */
  2687. /********************************************************************/
  2688.  
  2689. /* allow user to change parameters if they have hit Control-C 
  2690.  */
  2691. void CHECK_INTERRUPT(void)
  2692. {
  2693.   if (InterruptPending){
  2694.     printf("  Simulation interrupted at epoch %d\n", Epoch);
  2695.     INTERACTIVE_PARM_UPDATE();
  2696.   }
  2697. }
  2698.  
  2699. /* Record an interrupt whenever the user presses Control-C 
  2700.  */
  2701. void TRAP_CONTROL_C(int sig)
  2702. {
  2703.   InterruptPending = TRUE;
  2704.   signal(SIGINT, TRAP_CONTROL_C);
  2705. }
  2706.  
  2707.  
  2708.  
  2709. /* Convert the target output value to SigmoidMax or SigmoidMin given 
  2710.  * "max" or "min".  Otherwise assume float value.  Thanks to Dimitris
  2711.  *  Michailidis for this code.
  2712.  */
  2713. float convert(char *foo)
  2714. {
  2715.   if (!strcmp(foo, "min"))
  2716.     return(SigmoidMin);
  2717.   if (!strcmp(foo, "max"))
  2718.     return(SigmoidMax);
  2719.   return((float)atof(foo));
  2720. }
  2721.  
  2722. /* Read the next NTrainingPattern number of lines into the TrainingInput and
  2723.  * TrainingOutput data structures.
  2724.  */
  2725. void GET_TRAINING_DATA(FILE *infile)
  2726. {
  2727.  int i,j;
  2728.  char peek, foo[LINELEN+1];
  2729.  /**************/
  2730.  
  2731.     for (i=0; i<NTrainingPatterns; i++){
  2732.       /* look at 1st char of next line. */
  2733.       peek = fgetc(infile); ungetc(peek, infile); 
  2734.       if(peek == '#' || peek == '\n'){
  2735.     /* Throw away the line if it is a comment or blank. */
  2736.     fgets(foo, LINELEN, infile); 
  2737.     i--;
  2738.       }
  2739.       else{
  2740.     for (j=0; j<Ninputs; j++)
  2741.       fscanf (infile, "%f", &TrainingInputs[i][j]);
  2742.     for (j=0; j<Noutputs; j++){
  2743.       fscanf (infile, "%s", foo);
  2744.       TrainingOutputs[i][j] = convert(foo);
  2745.     }
  2746.     if (UseTrainingBreaks){       /* RCC */
  2747.            fscanf (infile,"%s",foo);
  2748.        TrainingBreaks[i] = TYPE_CONVERT(foo);   
  2749.      }
  2750.         else TrainingBreaks[i] = FALSE;
  2751.      }
  2752.     }
  2753. }
  2754.  
  2755.  
  2756. /* Read the next NTestPattern number of lines into the TestInput and
  2757.  * TestOutput data structures.
  2758.  */
  2759. void GET_TEST_DATA(FILE *infile)
  2760. {
  2761.   int i,j;
  2762.   char peek, foo[LINELEN+1];
  2763.   /**************/
  2764.  
  2765.  
  2766.     for (i=0; i<NTestPatterns; i++){
  2767.       /* look at 1st char of next line. */
  2768.       peek = fgetc(infile); ungetc(peek, infile); 
  2769.       if(peek == '#' || peek == '\n'){
  2770.     /* Throw away the line if it is a comment or blank. */
  2771.     fgets(foo, LINELEN, infile); 
  2772.     i--;
  2773.       }
  2774.       else{
  2775.     for (j=0; j<Ninputs; j++)
  2776.       fscanf (infile, "%f", &TestInputs[i][j]);
  2777.     for (j=0; j<Noutputs; j++){
  2778.       fscanf (infile, "%s", foo);
  2779.       TestOutputs[i][j] = convert(foo);
  2780.     }
  2781.     if (UseTestBreaks){         /* RCC */
  2782.            fscanf (infile,"%s",foo);
  2783.        TestBreaks[i] = TYPE_CONVERT(foo);   
  2784.      }
  2785.         else TestBreaks[i] = FALSE;
  2786.       }
  2787.     }
  2788. }
  2789.  
  2790. /* Get the training data from a seperate file.  Open the file and 
  2791.  * call GET_TRAINIING_DATA.  Uses global T_T_files for file name.
  2792.  */
  2793. void GET_TRAINING_DATA_FILE(void)
  2794. {
  2795.   FILE  *infile;
  2796.   char realfname[LINELEN+1];
  2797.   /********/
  2798.  
  2799.   /* open training data file */
  2800.   sprintf (realfname, "%s.dat", T_T_files);
  2801.   if((infile = fopen (realfname, "r")) == NULL){
  2802.     perror(realfname);
  2803.     exit(BOMB);
  2804.   }
  2805.  
  2806.   GET_TRAINING_DATA(infile);
  2807.  
  2808.   fclose(infile);
  2809. }
  2810.  
  2811. /* Get the test data from a seperate file.  Open the file and 
  2812.  * call GET_TRAINIING_DATA.  Uses global T_T_files for file name.
  2813.  */
  2814. void GET_TEST_DATA_FILE(void)
  2815. {
  2816.   FILE  *infile;
  2817.   char realfname[LINELEN+1];
  2818.   /********/
  2819.  
  2820.   /* open test data file */
  2821.   sprintf (realfname, "%s.dat", T_T_files);
  2822.   if((infile = fopen (realfname, "r")) == NULL){
  2823.     perror(realfname);
  2824.     exit(BOMB);
  2825.   }
  2826.  
  2827.   GET_TEST_DATA(infile);
  2828.  
  2829.   fclose(infile);
  2830. }
  2831.  
  2832. /* Check to see add extension to file name if it is not already there.
  2833.  */
  2834. void add_extension(char *fname, char *ext)
  2835. {
  2836.   if(strchr(fname, '.') == NULL) /* add extension if it isn't there */
  2837.     sprintf (fname, "%s.%s", fname, ext);
  2838. }
  2839. /*********************************************************************/
  2840. /*  interface functions                                              */
  2841. /*********************************************************************/
  2842. void INTERACT_SAVE_FILES(void)
  2843. {
  2844.   if(Y_OR_N_P(" Do you want to save the current settings?"))
  2845.     SAVE_NET_FILE();
  2846.  
  2847.   if(Y_OR_N_P(" Do you want to save the current weigths?"))
  2848.     INTERACT_DUMP_WEIGHTS();
  2849. }
  2850.  
  2851. /* Ask the user for a file name. Then save all parameters and the training set 
  2852.  * so that they can rerun the simulation.
  2853.  */
  2854. void SAVE_NET_FILE(void)
  2855. {
  2856.   FILE *fout;
  2857.   long tt;
  2858.   char fname[LINELEN+1];
  2859.   /***************/
  2860.  
  2861.   printf(" Name of file to write .net info into: "); scanf ("%s", fname);
  2862.   add_extension(fname, "net");
  2863.  
  2864.   if((fout = fopen (fname, "w")) == NULL){
  2865.     perror(fname);
  2866.     return;            /* back out if the file can't be opened */
  2867.   }
  2868.  
  2869.   time(&tt);
  2870.   fprintf(fout,"# Net file saved from Cascor Version %5.2f\n", VERSION);
  2871.   fprintf(fout,"# Saved at %s#\n", ctime(&tt));
  2872.  
  2873.   SAVE_ALL_PARMS(fout);
  2874.  
  2875.   if(Y_OR_N_P("Do you want to save the training set in the .net file?"))
  2876.     SAVE_TRAINING_SET(fout);
  2877.  
  2878.   if(Y_OR_N_P("Do you want to save the test set too?"))
  2879.     SAVE_TEST_SET(fout);
  2880. }
  2881.  
  2882.  
  2883. void SAVE_ALL_PARMS(FILE *fout)
  2884. {
  2885.   int i;
  2886.   for (i=0; i<Nparameters; ++i){
  2887.     SAVE_PARM_VALUE(fout, i);
  2888.   }
  2889. }
  2890.  
  2891. /* Save the settable parameters to a file for latter use.  This will look
  2892.  * just like a .net file.
  2893.  */
  2894. void SAVE_PARM_VALUE(FILE *fout, int k)
  2895. {
  2896.   static int numprinted;
  2897.   /********/
  2898.  
  2899.   if(k == 0)
  2900.     numprinted = 0;
  2901.  
  2902.   switch(ParmTable[k].vartype){ 
  2903.   case INT: case INT_NO:
  2904.     fprintf(fout, "%s %d   ", ParmTable[k].keyword, 
  2905.         *(int *)ParmTable[k].varptr);
  2906.     numprinted++;
  2907.     if((numprinted%3) == 0)
  2908.       fprintf(fout,"\n");
  2909.     break;
  2910.   case FLOAT: case FLOAT_NO:
  2911.     fprintf(fout, "%s %f   ", ParmTable[k].keyword, 
  2912.         *(float *)ParmTable[k].varptr);
  2913.     numprinted++;
  2914.     if((numprinted%3) == 0)
  2915.       fprintf(fout,"\n");
  2916.     break;
  2917.   case ENUM: case ENUM_NO:
  2918.     fprintf(fout, "%s %s   ", ParmTable[k].keyword, 
  2919.         TYPE_STRING(*(int *)ParmTable[k].varptr));
  2920.     numprinted++;
  2921.     if((numprinted%3) == 0)
  2922.       fprintf(fout,"\n");
  2923.     break;
  2924.   case BOOLE: case BOOLE_NO:
  2925.     fprintf(fout, "%s %s   ", ParmTable[k].keyword, 
  2926.         BOOLE_STRING(*(int *)ParmTable[k].varptr));
  2927.     numprinted++;
  2928.     if((numprinted%3) == 0)
  2929.       fprintf(fout,"\n");
  2930.     break;
  2931.   default:
  2932.     break;            /* skip anything else */
  2933.   }
  2934. }
  2935.  
  2936.  
  2937. /* Write the Training data into the given file.
  2938.  */
  2939. void SAVE_TRAINING_SET(FILE *fout)
  2940. {
  2941.   int i,j;
  2942.   /**************/
  2943.   
  2944.   fprintf(fout, "Training\n");    /* give keyword */
  2945.   for (i=0; i<NTrainingPatterns; i++)
  2946.     {
  2947.       for (j=0; j<Ninputs; j++)
  2948.     fprintf (fout, "%8.6g ", TrainingInputs[i][j]);
  2949.  
  2950.       fprintf(fout, "\t");    /* make it easy for humans to read */
  2951.  
  2952.       for (j=0; j<Noutputs; j++)
  2953.     fprintf (fout, "%8.6g ", TrainingOutputs[i][j]);
  2954.       
  2955.       fprintf(fout, "\n");    /* make it easy for humans to read */
  2956.    }
  2957. }
  2958.  
  2959. /* Write the Test data into the given file.
  2960.  */
  2961. void SAVE_TEST_SET(FILE *fout)
  2962. {
  2963.   int i,j;
  2964.   /**************/
  2965.   
  2966.   fprintf(fout, "Testing\n");    /* give keyword */
  2967.   for (i=0; i<NTestPatterns; i++)
  2968.     {
  2969.       for (j=0; j<Ninputs; j++)
  2970.     fprintf (fout, "%8.6g ", TestInputs[i][j]);
  2971.  
  2972.       fprintf(fout, "\t");    /* make it easy for humans to read */
  2973.  
  2974.       for (j=0; j<Noutputs; j++)
  2975.     fprintf (fout, "%8.6g ", TestOutputs[i][j]);
  2976.  
  2977.       fprintf(fout, "\n");    /* make it easy for humans to read */
  2978.     }
  2979. }
  2980.  
  2981. /* Dump all the parameter values to a file.  File is binary.
  2982.  */
  2983.  
  2984. /* Open a file named by the user, then call DUMP_WEIGHTS.
  2985.  */
  2986. void INTERACT_DUMP_WEIGHTS(void)
  2987. {
  2988.   FILE *fout;
  2989.   char fname[LINELEN+1];
  2990.   /***************/
  2991.  
  2992.   printf(" Name of file to write weights into: "); scanf ("%s", fname);
  2993.   add_extension(fname, "wgt");
  2994.  
  2995.   if((fout = fopen (fname, "w")) == NULL){
  2996.     perror(fname);
  2997.     return;            /* back out if the file can't be opened */
  2998.   }
  2999.  
  3000.   DUMP_WEIGHTS(fout);
  3001.  
  3002.   fclose(fout);
  3003. }
  3004.  
  3005. /* Dump the weights for the current net into the given file.
  3006.  * The file will contain Nunits, Noutputs, Nconnections, Weights, and 
  3007.  * OutputWeights.
  3008.  *
  3009.  * It is assumed that each hidden unit is connect to all lower numbered 
  3010.  * units.  Therefore, Connections does not need to be saved.  The network
  3011.  * will be rebuilt using AllConnectionns.
  3012.  */
  3013. void DUMP_WEIGHTS(FILE *fout)
  3014. {
  3015.   int i,j;
  3016.   long tt;
  3017.   /***************/
  3018.  
  3019.   time(&tt);
  3020.   fprintf(fout,"# Weight file saved from Cascor Version %5.2f\n", VERSION);
  3021.   fprintf(fout,"# Saved at %s#\n", ctime(&tt));
  3022.  
  3023.   fprintf(fout, "%d %d\n", Nunits, Noutputs);
  3024.   /* Dump Nconnections */
  3025.   for(i=0; i<Nunits; i++)
  3026.     fprintf(fout, "%d ", Nconnections[i]);
  3027.   fprintf(fout, "\n");
  3028.   /* Dump Input Weights */
  3029.   for(i=0; i<Nunits; i++)
  3030.     if(Nconnections[i]){
  3031.       for(j=0; j<Nconnections[i]; j++)
  3032.     fprintf(fout, "%17.15g ", Weights[i][j]);
  3033.       fprintf(fout, "\n");
  3034.     }
  3035.   /* Dump Output Weights */
  3036.   for(i=0; i<Noutputs; i++){
  3037.     for(j=0; j<Nunits; j++)
  3038.       fprintf(fout, "%17.15g ", OutputWeights[i][j]);
  3039.     fprintf(fout, "\n");
  3040.   }
  3041. }
  3042.  
  3043. /* get the weight file name from the user.  Then call GET_WEIGHT.
  3044.  */
  3045. void INTERACT_GET_WEIGHTS(void)
  3046. {
  3047.   char realfname[LINELEN+1];
  3048.   /***************/
  3049.  
  3050.   printf("Enter name of weight file: "); scanf ("%s", realfname);
  3051.  
  3052.   GET_WEIGHTS(realfname);
  3053. }
  3054.  
  3055. /* Read a .wgt file and do limited consistency checking with the input
  3056.  * from the .net file.  Space must be allocated for the Weight vectors in 
  3057.  * this routine.  During normal training the space is allocated in 
  3058.  * INSTALL_NEW_UNIT.
  3059.  */
  3060. void GET_WEIGHTS(char *realfname)
  3061. {
  3062.   int i,j, noutputs, nunits;
  3063.   float *w=NULL;            /* temporary weight array */
  3064.   char peek, junk[1025];
  3065.   FILE *fwgt;
  3066.   char *fn = "GET_WEIGHTS";
  3067.   /***************/
  3068.  
  3069.   /* open network configuration file */
  3070.   add_extension(realfname, "wgt");
  3071.   if((fwgt = fopen (realfname, "r")) == NULL){
  3072.     perror(realfname);
  3073.     return;
  3074.   }
  3075.  
  3076.   /* loop through comment lines */
  3077.   while(TRUE){
  3078.     /* look at 1st char of next line. */
  3079.     peek = fgetc(fwgt); ungetc(peek, fwgt); 
  3080.     if(peek == '#' || peek == '\n'){
  3081.       /* Throw away the line if it is a comment or blank. */
  3082.       fgets(junk, 1024, fwgt); 
  3083.     }
  3084.     else
  3085.       break;
  3086.   }
  3087.  
  3088.   fscanf(fwgt, "%d %d", &nunits, &noutputs);
  3089.   /* check to see if this matches the .net file inputs. */
  3090.   if(noutputs != Noutputs){
  3091.     sprintf(ErrMsg, 
  3092.       "noutputs in .wgt file does not match Noutputs in .net.\n  Training will start from scratch.");
  3093.     ERROR(WARN, ErrMsg);
  3094.     return;
  3095.   }
  3096.   if(nunits > MaxUnits){
  3097.     sprintf(ErrMsg, 
  3098.       "nunits(%d) in .wgt file is greater than MaxUnits in .net\n  Please change MaxUnits and try again.", nunits);
  3099.     ERROR(FATAL, ErrMsg);
  3100.   }
  3101.  
  3102.   /* Set globals from input. */
  3103.   Nunits = nunits;
  3104.   Noutputs = noutputs;
  3105.  
  3106.   /* Get Nconnections */
  3107.   for(i=0; i<Nunits; i++)
  3108.     fscanf(fwgt, "%d ", &Nconnections[i]);
  3109.  
  3110.   /* Get Input Weights */
  3111.   for(i=0; i<Nunits; i++)
  3112.     if(Nconnections[i]){
  3113.       w = (float *)GET_ARRAY_MEM(Nconnections[i], sizeof(float),fn);   
  3114.       for(j=0; j<Nconnections[i]; j++)
  3115.     fscanf(fwgt, "%f", &w[j]);
  3116.       Weights[i] = w;
  3117.       Connections[i] = AllConnections;
  3118.     }
  3119.  
  3120.   /* Get Output Weights */
  3121.   for(i=0; i<Noutputs; i++)
  3122.     for(j=0; j<Nunits; j++)
  3123.       fscanf(fwgt, "%f", &OutputWeights[i][j]);
  3124.  
  3125.   fclose(fwgt);            /* close the weight file. */
  3126.  
  3127.   /* If using cache, run an epoch to compute hidden units' values.  */
  3128.   if(UseCache)
  3129.     for(i=0; i<NTrainingPatterns; i++){
  3130.       Values = ValuesCache[i];
  3131.  
  3132.       /* Unit values must be calculated in order because the activations */
  3133.       /* cascade down through the hidden layers */
  3134.       for(j= 1+Ninputs; j<Nunits; j++) 
  3135.     COMPUTE_UNIT_VALUE(j, TrainingBreaks[i]);
  3136.     }
  3137. }
  3138.  
  3139. void INIT_DUMP_FILES(char *fname)
  3140. {
  3141.   strcpy(DumpFileRoot, fname);
  3142.   DumpWeights = TRUE;
  3143. /* open new dump files for every trial.  Close any open files before beginning.
  3144.  * If file opens fail, set DumpWeights to FALSE.
  3145.  */
  3146. void SETUP_DUMP_FILES(void)
  3147. {
  3148.   char rfname[LINELEN+1];    /* buffer to construct full file names into */
  3149.   /***********/
  3150.   
  3151.   DumpWeights = FALSE;        /* reset in case file opens fail */
  3152.  
  3153.   sprintf(rfname, "%s-%d.wgt", DumpFileRoot, Trial);
  3154.   if(WeightFile != NULL)    /* close last trial's file */
  3155.     fclose(WeightFile);
  3156.   if((WeightFile = fopen(rfname, "w")) == NULL){
  3157.     perror(rfname);
  3158.     return;
  3159.   }
  3160.   else
  3161.     DumpWeights = TRUE;
  3162. }
  3163.  
  3164.  
  3165. /* ErrorIndex is the rms TrueError normalized by the standard deviation of the 
  3166.  * goal set.
  3167.  */
  3168. float ERROR_INDEX(float std_dev, int num)
  3169. {
  3170.   return(sqrt( TrueError / (float)num) / std_dev);
  3171. }
  3172.  
  3173.  
  3174. /* Calculate the standard deviation of an entire output set.
  3175.  */
  3176. float STANDARD_DEV(float **outputs, int npatterns, int nvalues)
  3177. {
  3178.   int i,j;
  3179.   float sum_o_sqs = 0.0;
  3180.   float sum = 0.0;
  3181.   float cur = 0.0;
  3182.   float fnum = (float)nvalues;
  3183. /**************/
  3184.  
  3185.   for(i=0;i<npatterns;i++)
  3186.     for(j=0;j<Noutputs;j++){
  3187.       cur = outputs[i][j];
  3188.       sum += cur;
  3189.       sum_o_sqs += cur * cur;
  3190.     }
  3191.  
  3192.   return(sqrt((fnum * sum_o_sqs - sum * sum)/
  3193.           (fnum * (fnum - 1.0))));
  3194. }
  3195.  
  3196. /**************************************************************************/
  3197. /*        TEST example                                                    */
  3198. /*                                                                        */
  3199. /* Create the file morse.c, compile and run it to produce morse.net.      */
  3200. /* This is then used as input to recascor in the manner of an example     */
  3201. /* session that follows.                                                  */
  3202. /*                                                                        */
  3203. /* The example is included within a precompiler #ifdef block so that      */
  3204. /* this source file can be compiled without editing and so that I can     */
  3205. /* include comments within the example source code.  Please do not try    */
  3206. /* to compile this file with the symbol "YOU_WANT_TO_COMPILE_JUNK"        */
  3207. /* defined.  (Yes, someone has tried it.)                                 */
  3208. /**************************************************************************/
  3209. #ifdef YOU_WANT_TO_COMPILE_JUNK
  3210.  
  3211. Running the code with this example looks like this:
  3212.  
  3213. > % recascor
  3214. > Enter name of network: morse.net
  3215. > Number of epochs to train inputs: 150
  3216. > Number of epochs to train outputs: 150
  3217. > Maximum number of new units: 25
  3218. > Trials for this problem: 1
  3219. > Change some parameters? (y or n) n
  3220. >        ********* progress reports deleted *********
  3221. ;;
  3222. ;;   Hit Control-C to interrupt simulation 
  3223. ;;
  3224. > ^CSimulation interrupted at epoch 215
  3225. > Type <parameter name> to inspect or change the current value 
  3226. >   of <parameter name>.
  3227. > Type 'go' to continue simulation.
  3228. > Type 'values' to inspect the current values of all parameters
  3229. > Enter Parameter: scorethreshold
  3230. > scorethreshold[0.3500]: 0.9
  3231. > Enter Parameter: go
  3232. >        ********* progress reports deleted *********
  3233. > TRAINING LOOP STATS
  3234. > Recurrent Cascor.c Version:  2.00  Sept-25-91
  3235. > Trial Number 1 Parameters
  3236. > SigOff 0.10, WtRng 1.00, WtMul 1.00
  3237. > OMu 2.00, OEps 0.01, ODcy 0.00010, OPat 15, OChange 0.01
  3238. > IMu 2.00, IEps 0.10, IDcy 0.00010, IPat 15, IChange 0.03
  3239. > Utype: SIGMOID, Otype: ASYMSIGMOID, Pool 32
  3240. > ErrMeas: BITS, ScoreThres: 0.400,   ErrIndThres: 0.200
  3241. > Victory at 1310 epochs, 14 units, 12 hidden, Error 0.2089 EI 0.0000 
  3242. >
  3243. >  Victories: 3, Defeats: 0, 
  3244. >    Training Epochs - Min: 1089, Avg: 1321,  Max: 1545,
  3245. >    Hidden Units -    Min: 10, Avg:  12.6,  Max: 14,
  3246. > Do you want to run more trials? (y or n) n
  3247. > Do you want to test the last network? (y or n) n
  3248. > %
  3249.  
  3250.  
  3251. ----------------------start morse RCC example -------------------------------- 
  3252.  
  3253. ----------------------start of morse.c------------ --------------------------- 
  3254. /***********************************************************************/
  3255. /* C code to create morse training sets as described in the RCC paper  */
  3256. /* The program produces a file called morse.net containing training set*/
  3257. /* C Doherty September 25, 1991                                        */
  3258. /***********************************************************************/
  3259. /* The problem is to learn the morse code for all letters in the
  3260.  * alphabet.  Network has a single input for the morse signal and 27
  3261.  * outputs, one for each letter and a strobe.  All inputs and outputs
  3262.  * are treated as boolean values.  During training there is an
  3263.  * additional input called TrainingBreaks which clears the network
  3264.  * state between letters.  After training the strobe output could be
  3265.  * used to clear the network state (This is NOT implemented).
  3266.  * 
  3267.  * The problem encoding is:
  3268.  * Dot is ON-OFF, dash is ON-ON-OFF, and there's an extra OFF at the
  3269.  * end of each letter.  TrainingBreaks is ON for the first pattern in
  3270.  * a letter, OFF otherwise (these may be boolean values of some sort,
  3271.  * rather than +-0.5.)  When that final extra OFF is present, both
  3272.  * the strobe output and one of the letter outputs should be ON.  At
  3273.  * all other times, all outputs should be OFF.
  3274.  ********************************************************************/
  3275.  
  3276. #include <stdio.h>
  3277. #include <math.h>
  3278. #define  NLETTERS  26 /* Number of Letters = number of outputs */
  3279. #define  TRUE 1
  3280. #define  FALSE 0
  3281.  
  3282. /**
  3283.   Given index of the desired letter (A is 0, etc.), get the code string
  3284.   in dots and dashes.  Reserve output 26 for the strobe
  3285. **/
  3286.  
  3287. static char *codeconversions[NLETTERS] = {  ".-",    /* A */
  3288.                         "-...",  /* B */
  3289.                         "-.-.",  /* C */
  3290.                         "-..",   /* D */
  3291.                         ".",     /* E */
  3292.                         "..-.",  /* F */
  3293.                         "--.",   /* G */
  3294.                         "....",  /* H */
  3295.                         "..",    /* I */
  3296.                         ".---",  /* J */
  3297.                         "-.-",   /* K */
  3298.                         ".-..",  /* L */
  3299.                         "--",    /* M */
  3300.                         "-.",    /* N */
  3301.                         "---",   /* O */
  3302.                         ".--.",  /* P */
  3303.                         "--.-",  /* Q */
  3304.                         ".-.",   /* R */
  3305.                         "...",   /* S */
  3306.                         "-",     /* T */
  3307.                         "..-",   /* U */
  3308.                         "...-",  /* V */
  3309.                         ".--",   /* W */
  3310.                         "-..-",  /* X */
  3311.                         "-.--",  /* Y */
  3312.                         "--..",  /* Z */
  3313.                         };
  3314. /**
  3315.   5 Incremental training sequences which are mentioned in the RCC TR.
  3316.   The loop which generates the training data could be modified to 
  3317.   produce them. Used initially for debugging, they are currently redundant.
  3318. **/ 
  3319.  
  3320. static int seg[5][9] ={{4,19,-1},      /* sequence "et" */
  3321.                        {8,0,13,18,-1},      /* "ians" */
  3322.                        {3,17,20,6,7,10,22,12,-1},     /* "drughkwm" */
  3323.                        {1,5,11,14,21,-1},     /* "bflov" */
  3324.                        {2,15,23,25,9,16,24,-1}};  /* "cpxzjqy" */
  3325.  
  3326.  
  3327.  
  3328. void LetterTerminal(int letter);
  3329. void FillOutputs(float  marker);
  3330. void InitOutputs();
  3331.  
  3332. FILE *foo;
  3333.  
  3334. main(argc,argv)
  3335. int argc;
  3336. char *argv[];
  3337. {
  3338.   char   element;
  3339.   int    letter_length;
  3340.   int    i,j,k;
  3341.   int    first_element;
  3342.  
  3343.   foo = fopen("morse.net","w");
  3344.  
  3345.            /* Dummy space required later for writing # of training patterns */
  3346.   fprintf(foo, "                                           \n"); 
  3347.   fprintf(foo, "#Morse Code network file to test Recurrent Cascade Correlation\n");
  3348.   fprintf(foo, "Ninputs %d  Noutputs %d\n", 1, NLETTERS + 1);
  3349.   fprintf(foo, "UnitType SIGMOID     OutputType ASYMSIGMOID\n");
  3350.                            /* ASYMSIGMOID => output units range = 0-1 */
  3351.   fprintf(foo, "UseCache TRUE\n");
  3352.   fprintf(foo, "errormeasure BITS\n");
  3353.   fprintf(foo, "Weightrange 1.00\n");
  3354.   fprintf(foo, "inputepsilon 0.1\n");
  3355.   fprintf(foo, "inputdecay   0.0001\n");
  3356.   fprintf(foo, "inputpatience 15\n");
  3357.   fprintf(foo, "outputpatience 15 \n");
  3358.   fprintf(foo, "inputchangethreshold 0.030\n");
  3359.   fprintf(foo, "scorethreshold 0.4\n");
  3360.   fprintf(foo, "ncandidates 32\n");
  3361.   fprintf(foo, "outputepsilon 0.01\n");
  3362.   fprintf(foo, "usetrainingbreaks TRUE\n");
  3363.   fprintf(foo, "Test FALSE\n"); 
  3364.   fprintf(foo, "Training\n");
  3365.  
  3366. /* Generate a training set consisting of the alphabet */
  3367.  
  3368.   for(i=0, j=0; j< 26; i++, j++){
  3369.         letter_length = strlen(codeconversions[j]);
  3370.         for (k=0, first_element = TRUE; k< letter_length; k++){
  3371.              element = codeconversions[j][k];
  3372.              if (element == '.'){
  3373.                  if (first_element == TRUE){
  3374.            InitOutputs();
  3375.            first_element = FALSE;
  3376.                }
  3377.          else
  3378.                    FillOutputs(0.5);
  3379.          FillOutputs(-0.5);
  3380.                  i += 2;
  3381.            }
  3382.              else if (element == '-'){
  3383.                 if (first_element == TRUE){
  3384.            InitOutputs();
  3385.            first_element = FALSE;
  3386.            }
  3387.         else 
  3388.                    FillOutputs(0.5);
  3389.                 FillOutputs(0.5);
  3390.                    FillOutputs(-0.5);
  3391.                 i += 3;
  3392.            }
  3393.     }
  3394.         LetterTerminal(j);
  3395.    }
  3396.   rewind(foo);
  3397.   fprintf(foo, "NTrainingPatterns %d ",i); 
  3398.   fclose(foo);
  3399. }
  3400.  
  3401. void 
  3402. FillOutputs(float marker)
  3403. {
  3404.   int l;
  3405.  
  3406.   fprintf(foo,"%1.1f ", marker);
  3407.   for(l=0; l< NLETTERS+1; l++)
  3408.      fprintf(foo, "%d ",0);
  3409.   fprintf(foo, "false \n");  /* false required by UseTrainingBreaks */
  3410. }
  3411.  
  3412. void
  3413. InitOutputs()
  3414. {
  3415.   int l;
  3416.  
  3417.   fprintf(foo,"%1.1f ", 0.5);
  3418.   for(l=0; l< NLETTERS+1; l++)
  3419.      fprintf(foo, "%d ",0);
  3420.   fprintf(foo, "true \n");   /* true required by UseTrainingBreaks */
  3421. }                            /* reset the network at the start of a new letter */
  3422.  
  3423. void 
  3424. LetterTerminal(int letter)
  3425. {
  3426.   int l;
  3427.   fprintf(foo,"%1.1f ", -0.5);
  3428.   for(l=0; l< letter; l++)
  3429.      fprintf(foo, "%d ",0);
  3430.   fprintf(foo, "%d ",1);     /* set target letter */
  3431.   for(l=letter; l< NLETTERS-1; l++)
  3432.      fprintf(foo, "%d ", 0);
  3433.   fprintf(foo,"%d ", 1);     /* Set strobe unit # 27 */
  3434.   fprintf(foo, "false \n");  /* false requred by UseTrainingBreaks */
  3435. }
  3436.  
  3437.  
  3438. -------------------------end of morse.c ---------------------------------- 
  3439.  
  3440. #endif                /* YOUWANTTOCOMPILEJUNK */
  3441.  
  3442. /* End of recascor.c */
  3443.