home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / misc / volume28 / backprop / part04 / misc.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-02-23  |  17.2 KB  |  782 lines

  1. /* **************************************************** */
  2. /* file misc.c:  contains pattern manipulation routines */
  3. /*               and miscellaneous other functions.     */
  4. /*                                                      */
  5. /* Copyright (c) 1991 by Donald R. Tveter               */
  6. /*                                                      */
  7. /* **************************************************** */
  8.  
  9. #include <stdio.h>
  10.  
  11. #ifdef UNIX
  12. #include <malloc.h>
  13. #else
  14. #include <stdlib.h>
  15. #include <conio.h>
  16. #endif
  17.  
  18. #ifdef INTEGER
  19. #include "ibp.h"
  20. #else
  21. #include "rbp.h"
  22. #endif
  23.  
  24. /* an addition for large data sets */
  25.  
  26. extern INT32 g;
  27.  
  28. /* built-in function */
  29.  
  30. extern int rand();
  31.  
  32. /* homemade functions */
  33.  
  34. #ifdef INTEGER
  35. extern REAL unscale(), unscaleint();
  36. extern WTTYPE scale();
  37. #endif
  38.  
  39. extern short backoutput(), cbackoutput();
  40. extern void backinner(), cbackinner(), saveweights();
  41. extern WTTYPE rdr();
  42. extern void dbd_update(), periodic_update(), qp_update(), supersab();
  43. extern REAL readchar();
  44.  
  45. extern char backprop,emptystring,informat,outstr[],patform,ringbell;
  46. extern char summary, *testfile, update, up_to_date_stats, wtlimithit;
  47. extern int bad, benchmark,bufferptr,lastprint,lastsave,npats;
  48. extern int prevnpats,readerror,readingpattern,right,saverate,testpat;
  49. extern int totaliter,unlearned,wrong,wttotal;
  50. extern WTTYPE dbdeta, error, initialkick, toler, toosmall;
  51. extern REAL errorperunit, pct_right;
  52. extern UNIT *hlayer, *ilayer, *jlayer, *klayer;
  53. extern LAYER *last, *start;
  54. extern short skiprate;
  55. #ifdef INTEGER
  56. extern INT32 totaldiff;
  57. #else
  58. extern REAL totaldiff;
  59. #endif
  60.  
  61. void nullpatterns()  /* dispose of any patterns before reading more */
  62. {
  63. PATLIST *pl, *nextpl;
  64. WTTYPE *p;
  65.  
  66. if (start->patstart != NULL)
  67.  {
  68.   pl = start->patstart;
  69.   while (pl != NULL)
  70.    {
  71.     nextpl = pl->next;
  72.     p = pl->pats;
  73.     free(p);
  74.     pl = nextpl;
  75.    };
  76.   pl = last->patstart;
  77.   while (pl != NULL)
  78.    {
  79.     nextpl = pl->next;
  80.     p = pl->pats;
  81.     free(p);
  82.     pl = nextpl;
  83.    };
  84.  };
  85. start->patstart = NULL;
  86. last->patstart = NULL;
  87. npats = 0;
  88. prevnpats = 0;
  89. }
  90.  
  91. void resetpats()
  92. {
  93. start->currentpat = NULL;
  94. last->currentpat = NULL;
  95. }
  96.  
  97. void findendofpats(layer)  /* purpose is to set all layer->currentpat */
  98. LAYER *layer;              /* fields to end of pattern list so more   */
  99. {                          /* patterns can be added at the end.       */
  100. PATLIST *pl;
  101. pl = (PATLIST *) layer->patstart;
  102. while (pl->next != NULL) pl = pl->next;
  103. layer->currentpat = pl;
  104. }
  105.  
  106. int copyhidden(u,hidden,layerno)
  107. UNIT *u, **hidden;
  108. int layerno;
  109. {
  110. if (hidden == NULL)
  111.  {
  112.   sprintf(outstr,"ran out of hidden units in layer %d\n",layerno);
  113.   pg(outstr);
  114.   return(0);
  115.  }
  116. u->oj = (*hidden)->oj;
  117. *hidden = (*hidden)->next;
  118. return(1);
  119. }
  120.  
  121. int loadpat(command)
  122. char command;
  123. {
  124. UNIT *u, *hunit, *iunit, *junit, *kunit;
  125. hunit = hlayer;
  126. iunit = ilayer;
  127. junit = jlayer;
  128. kunit = klayer;
  129. readingpattern = 1;
  130. u = (UNIT *) start->units;
  131. while (u != NULL)
  132.  {
  133.   if (informat == 'r') u->oj = rdr(GE,(REAL) HCODE,command);
  134.   else u->oj = scale(readchar());
  135.   if (readerror) goto errorexit;
  136.   if (u->oj <= KCODE)
  137.    {
  138.     if (u->oj == HCODE)
  139.        {if (!copyhidden(u,&hunit,2)) goto errorexit;}
  140.     else if (u->oj == ICODE)
  141.        {if (!copyhidden(u,&iunit,3)) goto errorexit;}
  142.     else if (u->oj == JCODE)
  143.        {if (!copyhidden(u,&junit,4)) goto errorexit;}
  144.     else if (!copyhidden(u,&kunit,5)) goto errorexit;
  145.    };
  146.   u = u->next;
  147.  };
  148. readingpattern = 0;
  149. forward();
  150. return(1);
  151.  
  152. errorexit:
  153. readingpattern = 0;
  154. return(0);
  155. }
  156.  
  157. void nextpat()
  158. {
  159. if (start->currentpat == NULL)
  160.  {
  161.   start->currentpat = start->patstart;
  162.   last->currentpat = last->patstart;
  163.  }
  164. else
  165.  {
  166.   start->currentpat = (start->currentpat)->next;
  167.   last->currentpat = (last->currentpat)->next;
  168.  };
  169. }
  170.  
  171. void setoutputpat()
  172. {
  173. register WTTYPE *p;
  174. register UNIT *u;
  175. register short i, answer;
  176. PATLIST *pl;
  177.  
  178. if (patform == 'c' || patform == 'C')
  179.  {
  180.   pl = last->currentpat;
  181.   p = pl->pats;
  182.   answer = *p;
  183.   u = (UNIT *) last->units;
  184.   for (i=1;i<=last->unitcount;i++)
  185.    {
  186.     if (i == answer) u->tj = scale(1.0); else u->tj = scale(0.0);
  187.     u = u->next;
  188.    };
  189.  }
  190. else
  191.  {
  192.   pl = last->currentpat;
  193.   p = pl->pats;
  194.   u = (UNIT *) last->units;
  195.   while (u != NULL)
  196.    {
  197.     u->tj = *p++;
  198.     u = u->next;
  199.    };
  200.  }
  201. }
  202.  
  203. void setinputpat()
  204. {
  205. register WTTYPE *p;
  206. register UNIT *u;
  207. UNIT *hunit, *iunit, *junit, *kunit;
  208. PATLIST *pl;
  209.   
  210. hunit = hlayer;
  211. iunit = ilayer;
  212. junit = jlayer;
  213. kunit = klayer;
  214. pl = start->currentpat;
  215. p = pl->pats;
  216. u = (UNIT *) start->units;
  217. while (u != NULL)
  218.  {
  219.   if (*p > KCODE) u->oj = *p++;
  220.   else if (*p++ == HCODE)
  221.      {if (!copyhidden(u,&hunit,2)) return;}
  222.   else if (*p++ == ICODE)
  223.      {if (!copyhidden(u,&iunit,3)) return;}
  224.   else if (*p++ == JCODE)
  225.      {if (!copyhidden(u,&junit,4)) return;}
  226.   else if (!copyhidden(u,&kunit,5)) {p++; return;};
  227.   u = u->next;
  228.  };
  229. }
  230.  
  231. void setonepat() /* set input and output patterns */
  232. {
  233. register UNIT *u;
  234. register LAYER *innerlayers;
  235.  
  236. setinputpat();
  237. setoutputpat();
  238. innerlayers = start->next;
  239. while (innerlayers->next != NULL)
  240.  {  /* set errors on the inner layer units to 0 */
  241.   u = (UNIT *) innerlayers->units;
  242.   while (u != NULL)
  243.    {
  244.     u->error = 0;
  245.     u = u->next;
  246.    };
  247.   innerlayers = innerlayers->next;
  248.  };
  249. }
  250.  
  251. void clear()
  252. {
  253. LAYER *p;
  254. UNIT *u;
  255. WTNODE *w;
  256. int i;
  257.  
  258. if (toosmall != -1)
  259.  {
  260.   pg("cannot restart with the weights removed\n");
  261.   return;
  262.  };
  263. right = 0;
  264. wrong = npats;
  265. pct_right = 0.0;
  266. unlearned = npats;
  267. wtlimithit = 0;
  268. totaliter = 0;
  269. lastsave = 0;
  270. initialkick = -1;
  271. lastprint = 0;
  272. resetpats();
  273. for (i=1;i<=npats;i++)
  274.  {
  275.   nextpat();
  276.   if (last->currentpat->bypass > 0) last->currentpat->bypass = 0;
  277.   else if (last->currentpat->bypass < 0) last->currentpat->bypass = -1;
  278.  };
  279. p = start->next;
  280. while (p != NULL)
  281.  {
  282.   u = (UNIT *) p->units;
  283.   while (u != NULL)
  284.    {
  285.     w = (WTNODE *) u->wtlist;
  286.     while (w != NULL)
  287.      {
  288. #ifdef SYMMETRIC
  289.       if (w->next != NULL)
  290.        { /* skip threshold weight */
  291.         *(w->weight) = 0;
  292.         *(w->olddw) = 0;
  293.         *(w->eta) = dbdeta;
  294.        };
  295. #else
  296.       w->weight = 0;
  297.       w->olddw = 0;
  298.       w->eta = dbdeta;
  299.       w->slope = 0;
  300. #endif
  301.       w = w->next;
  302.      };
  303.     u = u->next;
  304.    };
  305.   p = p->next;
  306.  };
  307. }
  308.  
  309. #ifndef SYMMETRIC
  310.  
  311. void whittle(amount)    /* removes weights whose absolute */
  312. WTTYPE amount;          /* value is less than amount      */
  313. {LAYER *layer;
  314.  UNIT *u;
  315.  WTNODE *w, *wprev;
  316.  
  317. layer = start->next;
  318. while (layer != NULL)
  319.  {
  320.   u = (UNIT *) layer->units;
  321.   while (u != NULL)
  322.    {
  323.     w = (WTNODE *) u->wtlist;
  324.     wprev = (WTNODE *) NULL;
  325.     while (w->next != (WTNODE *) NULL)
  326.      {
  327.       if ((w->weight) < amount && (w->weight) > -amount)
  328.        {
  329.         if (wprev == NULL) (WTNODE *) u->wtlist = w->next;
  330.         else (WTNODE *) wprev->next = w->next;
  331.         wttotal = wttotal - 1;
  332.        }
  333.       else wprev = w;
  334.       w = w->next;
  335.      }
  336.     u = u->next;
  337.    }
  338.   layer = layer->next;
  339.  }
  340. }
  341.  
  342. #endif
  343.  
  344. void testcheck()  /* checks the testfile */
  345. {
  346. int class, best, count, tcright, tcwrong, testcount, printing;
  347. int tright, twrong, ch2;
  348. REAL pct, testerr, eperunit;
  349. WTTYPE max;
  350. UNIT *u;
  351.  
  352. pushfile(testfile);
  353. testerr = 0.0;
  354. testcount = 0;
  355. tcright = 0;
  356. tcwrong = 0;
  357. tright = 0;
  358. twrong = 0;
  359. if (patform == 'c' || patform == 'g') printing = 0; else printing = 1;
  360. ch2 = readch();
  361. while (ch2 != EOF)
  362.  {
  363.   bufferptr = bufferptr - 1;
  364.   if (!loadpat('t')) if (readerror == 2) goto summarize; else goto exit;
  365.   class = 0;
  366.   if (patform == 'c' || patform == 'C')
  367.    {
  368.     class = readint(1,last->unitcount,'t');
  369.     if (readerror) goto exit;
  370.     count = 0;
  371.     max = -MAXINT;
  372.     best = 0;
  373.    };
  374.   u = (UNIT *) last->units;
  375.   while (u != NULL)
  376.    {
  377.     if (class)
  378.      {
  379.       count = count + 1;
  380.       if (u->oj > max)
  381.        {
  382.         max = u->oj;
  383.         best = count;
  384.        }
  385.       if (count == class) u->tj = scale(1.0); else u->tj = scale(0.0);
  386.      }
  387.     else
  388.      {
  389.       u->tj = rdr(GT,(REAL) KCODE,'t');
  390.       if (readerror) goto exit;
  391.      };
  392.     u = u->next;
  393.    };
  394.   testcount = testcount + 1;
  395.   if (class)
  396.    if (best == class) tcright = tcright + 1; else tcwrong = tcwrong + 1;
  397.   if (printing)
  398.    {
  399.     sprintf(outstr,"%5d",testcount);
  400.     pg(outstr);
  401.    };
  402.   if (printoutunits(printing,last,1))
  403.    {
  404.     popfile();
  405.     return;
  406.    };
  407.   testerr = testerr + unscale(error);
  408.   if (bad) twrong = twrong + 1; else tright = tright + 1;
  409.   do ch2 = readch(); while (ch2 != '\n');
  410.   ch2 = readch();
  411.  };
  412.  
  413. summarize:
  414. pct = 100.0 * (REAL) tright / (REAL) testcount;
  415. if (pg("based on tolerance:\n")) return;
  416. sprintf(outstr,"   %6.2f%%,   (%d right,  %d wrong)",pct,tright,twrong);
  417. pg(outstr);
  418. eperunit = testerr / (REAL) (last->unitcount * testcount);
  419. sprintf(outstr,"   %7.5f error/unit\n",eperunit); pg(outstr);
  420. if (patform == 'c' || patform == 'C')
  421.  {
  422.   pct = 100.0 * (REAL) tcright / (REAL) testcount;
  423.   if (pg("based on maximum value:\n")) return;
  424.   sprintf(outstr,"   %6.2f%%,   %d right,   %d wrong\n",pct,tcright,tcwrong);
  425.   pg(outstr);
  426.  };
  427. popfile();
  428. return;
  429.  
  430. exit:
  431. sprintf(outstr,"error while reading pattern %d\n",testcount+1);
  432. pg(outstr);
  433. popfile();
  434. }
  435.  
  436. void stats(callfromrun)
  437. int callfromrun;
  438. {
  439.  if (callfromrun) wrong = unlearned;
  440.  right = npats - wrong;
  441.  if (testpat) right = right - 1;
  442.  errorperunit =
  443.     unscaleint(totaldiff) / (REAL) ((right + wrong) * last->unitcount);
  444.  pct_right = 100.0 * (REAL) right / (REAL) (right + wrong);
  445. }
  446.  
  447. int patcheck(first,finish,printoutputs,printerrors,sumup,printsumup,skip)
  448. int first,finish,printoutputs,printerrors,sumup,printsumup,skip;
  449. {
  450. int i;
  451.  
  452. if (skip && printoutputs == 0) goto shortcut;
  453. if (sumup)
  454.  {
  455.   totaldiff = 0;
  456.   wrong = 0;
  457.  };
  458. resetpats();
  459. for (i=1;i<first;i++) nextpat();
  460. for (i=first;i<=finish;i++)
  461.  { 
  462.   nextpat();
  463.   setonepat();
  464.   forward();
  465.   if (printoutputs) {sprintf(outstr,"%3d ",i); pg(outstr);};
  466.   if (printoutunits(printoutputs,last,printerrors)) return(1);
  467.   if (i != testpat && sumup)
  468.     {
  469.      wrong = wrong + bad;
  470.      totaldiff = totaldiff + error;
  471.     };
  472.  };
  473. if (printoutputs) lastprint = totaliter;
  474. if (sumup) stats(0);
  475.  
  476. shortcut:
  477. if (printsumup)
  478.  {
  479.   sprintf(outstr,"%5d iterations  ",totaliter); pg(outstr);
  480.   sprintf(outstr,"%6.2f%% right ",pct_right); pg(outstr);
  481.   sprintf(outstr,"(%1d right ",right); pg(outstr);
  482.   sprintf(outstr,"  %1d wrong)   ",wrong); pg(outstr);
  483.   sprintf(outstr,"%7.5f error/unit\n",errorperunit);
  484.   if (pg(outstr)) return(1);
  485.  }
  486. return(0);
  487. }
  488.  
  489. void oneset() /* go through the patterns once and update weights */
  490. int i;
  491. LAYER *layer;
  492. register UNIT *u;
  493. register WTNODE *w;
  494. short numbernotclose, attempted, passed;
  495.  
  496. layer = last;      /* make all b->totals = 0 */
  497. while (layer->backlayer != NULL)
  498.  {
  499.   u = (UNIT *) layer->units;
  500.   while (u != NULL)
  501.    {
  502.     w = (WTNODE *) u->wtlist;
  503.     while (w != NULL)
  504.      {
  505. #ifdef SYMMETRIC
  506.       *(w->total) = 0;
  507. #else
  508.       w->total = 0;
  509. #endif
  510.       w = w->next;
  511.      };
  512.     u = u->next;
  513.    };
  514.   layer = layer->backlayer;
  515.  };
  516. attempted = 0;
  517. passed = 0;
  518. if (testpat) unlearned = npats - 1; else unlearned = npats;
  519. resetpats();
  520. for(i=1;i<=npats;i++)
  521.  {
  522.   nextpat();
  523.   if (last->currentpat->bypass == 0)
  524.    {
  525.     setonepat();
  526.     forward();
  527.     attempted = attempted + 1;
  528.     if (update == 'c') numbernotclose = cbackoutput();
  529.     else numbernotclose = backoutput();
  530.     if (numbernotclose != 0)
  531.      {
  532. #ifndef SYMMETRIC
  533.       if (update == 'c') cbackinner(); else backinner();
  534. #endif
  535.      }
  536.     else /* this one pattern has been learned */
  537.      {
  538.       passed = passed + 1;
  539.       unlearned = unlearned - 1;
  540.       last->currentpat->bypass = skiprate;
  541. #ifndef SYMMETRIC
  542.       if (backprop) if (update == 'c') cbackinner(); else backinner();
  543. #endif
  544.      }
  545.    }
  546.   else last->currentpat->bypass = last->currentpat->bypass - 1;
  547.  };
  548. if (update == 'c') totaliter = totaliter + 1;
  549. if (up_to_date_stats == '+' && update == 'c') patcheck(1,npats,0,0,1,0,0);
  550. if (unlearned == 0) return;
  551. if (skiprate && (attempted == passed))
  552.  {
  553.   resetpats();
  554.   for (i=1;i<=npats;i++)
  555.    {
  556.     nextpat();
  557.     if (last->currentpat->bypass > 0) last->currentpat->bypass = 0;
  558.    };
  559.  };
  560. if (update == 'c') return;
  561. else if (update == 'd') dbd_update();
  562. else if (update == 'p') periodic_update();
  563. else if (update == 'q') qp_update();
  564. else if (update == 's') supersab();
  565. if (up_to_date_stats == '+') patcheck(1,npats,0,0,1,0,0);
  566. totaliter = totaliter + 1;
  567. }
  568.  
  569. void kick(size,amount) /* give the network a kick */
  570. WTTYPE size, amount;
  571. LAYER *layer;
  572. UNIT *u;
  573. WTNODE *w;
  574. WTTYPE value;
  575. WTTYPE delta;
  576. int sign;
  577.  
  578. layer = start->next;
  579. while (layer != NULL)
  580.  {
  581.   u = (UNIT *) layer->units;
  582.   while (u != NULL)
  583.    {
  584.     w = (WTNODE *) u->wtlist;
  585.     while (w != NULL)
  586.      {
  587. #ifdef SYMMETRIC
  588.       value = *(w->weight);
  589. #else
  590.       value = w->weight;
  591. #endif
  592.       if (value != 0) sign = 1;
  593.       else if ((rand() & 32767) > 16383) sign = -1;
  594.       else sign = 1;
  595.       delta = (INT32) sign * amount * (rand() & 32767) / 32768;
  596.       if (value >= size) value = value - delta;
  597.       else if (value < -size) value = value + delta;
  598. #ifdef SYMMETRIC
  599.       if (((UNIT *) w->backunit)->unitnumber != u->unitnumber &&
  600.          w->next != NULL)
  601.          *(w->weight) = value;
  602. #else
  603.       w->weight = value;
  604. #endif
  605.       w = w->next;
  606.      }
  607.     u = u->next;
  608.    }
  609.   layer = layer->next;
  610.  } 
  611. }
  612.  
  613. void newoneset() /* go through the patterns once and update weights */
  614. { int i;
  615.   LAYER *layer;
  616.   register UNIT *u;
  617.   register WTNODE *w;
  618.   short numbernotclose, attempted, passed;
  619.  
  620. begin:
  621.  layer = last;      /* make all b->totals = 0 */
  622.  while (layer->backlayer != NULL)
  623.   {
  624.    u = (UNIT *) layer->units;
  625.    while (u != NULL)
  626.     {
  627.      w = (WTNODE *) u->wtlist;
  628.      while (w != NULL)
  629.       {
  630. #ifdef SYMMETRIC
  631.        *(w->total) = 0;
  632. #else
  633.        w->total = 0;
  634. #endif
  635.        w = w->next;
  636.       };
  637.      u = u->next;
  638.     };
  639.    layer = layer->backlayer;
  640.   };
  641.  attempted = 0;
  642.  passed = 0;
  643.  unlearned = npats;
  644.  resetpats();
  645.  for(i=1;i<=npats;i++)
  646.   {
  647.    nextpat();
  648.    if (last->currentpat->bypass == 0)
  649.     {
  650.      setonepat();
  651.      forward();
  652.      attempted = attempted + 1;
  653.      if (update == 'c') numbernotclose = cbackoutput();
  654.      else numbernotclose = backoutput();
  655.      if (numbernotclose != 0)
  656.       {
  657. #ifndef SYMMETRIC
  658.        if (update == 'c') cbackinner(); else backinner();
  659. #endif
  660.       }
  661.      else /* this one pattern has been learned */
  662.       {
  663.        passed = passed + 1;
  664.        unlearned = unlearned - 1;
  665.        last->currentpat->bypass = skiprate;
  666. #ifndef SYMMETRIC
  667.        if (backprop) if (update == 'c') cbackinner(); else backinner();
  668. #endif
  669.       }
  670.     }
  671.    else last->currentpat->bypass = last->currentpat->bypass - 1;
  672.    if (g && (i % g == 0 || i == npats))
  673.     {
  674.      if (update == 'd') dbd_update();
  675.      else if (update == 'p') periodic_update();
  676.      layer = last;      /* make all b->totals = 0 */
  677.      while (layer->backlayer != NULL)
  678.       {
  679.        u = (UNIT *) layer->units;
  680.        while (u != NULL)
  681.         {
  682.          w = (WTNODE *) u->wtlist;
  683.          while (w != NULL)
  684.           {
  685.            w->total = 0;
  686.            w = w->next;
  687.           };
  688.          u = u->next;
  689.         };
  690.        layer = layer->backlayer;
  691.       }; /* end while */
  692.     };  /* end if g */
  693. }; /* end for i */
  694. if (update == 'c'|| g != 0) totaliter = totaliter + 1;
  695. if (up_to_date_stats == '+' && update == 'c') patcheck(1,npats,0,0,1,0,0);
  696. if (unlearned == 0) return;
  697. if (skiprate && (attempted == passed))
  698.  {
  699.   resetpats();
  700.   for (i=1;i<=npats;i++)
  701.    {
  702.     nextpat();
  703.     last->currentpat->bypass = 0;
  704.    };
  705.   goto begin;
  706.  };
  707. if (g == 0)
  708.  {
  709.   if (update == 'c') return;
  710.   else if (update == 'd') dbd_update();
  711.   else if (update == 'p') periodic_update();
  712.   else if (update == 'q') qp_update();
  713.   else if (update == 's') supersab();
  714.  };
  715. if (up_to_date_stats == '+') patcheck(1,npats,0,0,1,0,0);
  716. if (g == 0) totaliter = totaliter + 1;
  717. }
  718.  
  719. int run(n,prpatsrate)
  720. int n;            /* the number of iterations to run */
  721. int prpatsrate;   /* rate at which to print output patterns */
  722. {
  723. int i, wtlimitbefore;
  724. #ifndef UNIX
  725. int chx;
  726. #endif
  727.  
  728. if (pg("running . . .\n")) return(1);
  729. for (i=1;i<=n;i++)
  730.  {
  731.   totaldiff = 0;
  732.   wtlimitbefore = wtlimithit;
  733.   if (g == 0) oneset(); else newoneset();
  734.   stats(1);
  735.   if (wtlimitbefore == 0 && wtlimithit == 1)
  736.    {
  737.     sprintf(outstr,">>>>> WEIGHT LIMIT HIT <<<<< at %d\n",totaliter);
  738.     if (pg(outstr)) return(1);
  739.    };
  740.   if (unlearned == 0) /* training finished */
  741.    {
  742.     if (benchmark && testpat)
  743.      {
  744.       sprintf(outstr,"S  %d iterations",totaliter); pg(outstr);
  745.       sprintf(outstr," %9.5f error/unit\n",errorperunit); pg(outstr);
  746.       if (patcheck(testpat,testpat,1,1,0,0,0)) return(1);
  747.      };
  748.     if ((prpatsrate > 0 && lastprint != totaliter))
  749.      if (patcheck(1,npats,summary == '-',summary == '-',1,1,0)) return(1);
  750.     sprintf(outstr,"patterns learned to within %4.2f",unscale(toler));
  751.     pg(outstr);
  752.     pg(" at iteration");
  753.     if (ringbell == '+') putchar(7);
  754.     sprintf(outstr," %d\n",totaliter);
  755.     if (pg(outstr)) return(1);
  756.     if (benchmark && *testfile != emptystring) testcheck();
  757.     return(0);
  758.    };
  759.   if (benchmark && testpat && (prpatsrate > 0 && i % prpatsrate == 0))
  760.    {
  761.     if (unlearned == 1) pg("S"); else pg("F");
  762.     sprintf(outstr," %d iterations",totaliter); pg(outstr);
  763.     sprintf(outstr," %7.5f error/unit\n",errorperunit);
  764.     if (pg(outstr)) return(1);
  765.     if (patcheck(testpat,testpat,1,1,0,0,0)) return(1);
  766.    }
  767.   if (totaliter % saverate == 0) saveweights();
  768.   if ((prpatsrate > 0) && ((i % prpatsrate == 0) || (i == n)))
  769.    {
  770.     if (patcheck(1,npats,summary == '-',summary == '-',1,1,
  771.              up_to_date_stats == '-')) return(1);
  772.     if (benchmark && (*testfile != emptystring)) testcheck();
  773.    };
  774. #ifndef UNIX
  775.   if (kbhit() && getch() == 27 /* escape key */) return(1);
  776. #endif
  777.  };
  778. return(0);
  779.