1 /******************************************************************************
2   FILE           : $Source: /projects/higgs1/SNNS/CVS/SNNS/tools/sources/snns2c.c,v $
3   SHORTNAME      : snns2c.c
4   SNNS VERSION   : 4.2
5 
6   PURPOSE        : Converter for SNNS-net -Files to  executable C-Source
7                    only for Feed-Forward- and Elman-nets.
8 
9                    Loads the net with the functions given by the
10                    kernel-interface of the SNNS-kernel.
11                    Groups similar units in layers and sorts the layers
12                    topologically.
13                    Saves the Net as a C function.
14 
15   Updates : TDNN (01.11.94 - 04.01.95)
16             DLVQ (05.01.95 - 10.01.95)
17 	    CPN  (11.01.95 - 30.01.95)
18             generated HeaderFiles         (31.01.95)
19 	    update function with pointers (01.02.95)
20             BBTT (02.02.95 - 20.02.95)
21 	    releasing all memory (23.02.95)
22 
23   AUTHOR         : Bernward Kett
24   DATE           : 31.08.94
25   LAST UPDATE    : 23.02.95 (Bernward Kett)
26 
27   CHANGED BY     :
28   RCS VERSION    : $Revision: 1.19 $
29   LAST CHANGE    : $Date: 1998/04/22 16:48:12 $
30 
31     Copyright (c) 1990-1995  SNNS Group, IPVR, Univ. Stuttgart, FRG
32     Copyright (c) 1996-1998  SNNS Group, WSI, Univ. Tuebingen, FRG
33 
34   used files     : glob_typ.h, kr_ui.h      from kernel/sources
35                    libkernel.a              from kernel/bin/<architecture>
36                    functions.h, templates.h from actual directory
37 ******************************************************************************/
38 #include <config.h>
39 
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <string.h>
43 #include <ctype.h>
44 #ifdef HAVE_LIMITS_H
45 #include <limits.h>
46 #endif
47 #include <time.h>
48 #include <memory.h>
49 #include "glob_typ.h"
50 #include "kr_ui.h"
51 #include "functions.h"
52 #include "templates.h"
53 #include "snns2clib.h"
54 
55 #include "kr_typ.h"
56 #include "kernel.h"  /* should be removed, when the kr_ui.h is updated */
57 
58 #undef debug
59 /*
60 #define debug
61 */
62 
63 /* Macros for calculating the minimum or maximum of two values */
64 #define MAX(a, b) ( (a > b) ? (a) : (b) )
65 #define MIN(a, b) ( (a < b) ? (a) : (b) )
66 
67 /* Macro for releasing memory of units and layers */
68 #define FREE_ALL freeUnits(Units); freeLayers(Layers); free(TDNN_prot);
69 
70 /* Status (Error) Codes : OK = 0 (NO Error), ERR = 1, ...  */
71 typedef enum { OK, ERR, CANT_ADD, CANT_LOAD, MEM_ERR,
72 		   WRONG_PARAM, WRONG_ACT_FUNC, CANT_OPEN,
73 		   ILLEGAL_CYCLES, NO_CPN, NO_TDNN, NOT_SUPPORTED} Status;
74 
75 /* Recordtype for Layers */
76 typedef struct {
77   int   number;			/* of the Layer (not used yet) */
78   pList members;		/* Numbers of all member-units */
79   pList sources;		/* numbers of all sources of the member-units */
80   int   type;			  /* INPUT , OUTPUT ...               */
81   int   ActFunc;		/* No in the ActivationFunctionList */
82   char  *name;			/* Name of the Layer */
83   /* Special entries for TDNN */
84   int   TotalDelay;		/* Total Delay Number of the Layer */
85   int   delay;			/* Delay of the receptive Field  */
86   int   SuccDelay;		/* Delay of the following Layer */
87   char  *readCounter;		/* Name of the DelayPointer      */
88   char  *writeCounter;		/* Name of the WriteDelayPointer */
89 } tLayer, *pLayer;
90 
91 /* Recordtype for Units */
92 typedef struct {
93   int    number;		/* of the Unit                         */
94   pList  members;		/* Units with the same Prototype (TDNN)*/
95   pList  sources;		/* numbers of the source-Units         */
96   float  *weights;	        /* Link-Weights to the Source-Units    */
97   int    ActFunc;		/* No in the ActivationFunctionList    */
98   int    type;			/* INPUT , OUTPUT ...                  */
99   char   *name;			/* Name of the unit, given by the user */
100   float  Bias;			/* Bias of the unit                    */
101   pLayer layer;			/* Pointer to the layer wich contains the unit */
102   /* Special entries for BPTT and Elman/Jordan */
103   float  act;                   /* Initial Activation of the Unit      */
104   /* Special entries for CPN */
105   float *dest;      /* weights from Hidden to Output written in the hidden units */
106   int   NoOfDest;   /* Numbers of the weights to the Output */
107   /* Special entries for TDNN */
108   int    index;			/* Index in the global Array           */
109   int   FeatureWidth;		/* Number of Prototype Source units    */
110   int   DelayLength;		/* Delay Length of the receptive Field */
111   int   **TDNNsources;		/* special Format for TDNNs            */
112   float **TDNNweights;		/* special Format for TDNNs            */
113 } tUnit, *pUnit;
114 
115 /*
116  *  Output-Functions for debug-informations
117  */
118 
printLayer(pLayer layer)119 void printLayer(pLayer layer)
120 {
121   int i;
122   printf("\nLayer %d", layer->number);
123   printf("\nmembers: ");
124   for (i = 0; i < NoOf(layer->members); i++) {
125     printf("%d ", element(layer->members, i) );
126   }
127   printf("\nsources: ");
128   for (i = 0; i < NoOf(layer->sources); i++) {
129     printf("%d ", element(layer->sources, i) );
130   }
131   printf("\n");
132 }
133 
134 
printUnit(pUnit unit)135 void printUnit(pUnit unit)
136 {
137   int i;
138   printf("\nUnit %d", unit->number);
139   printf("\nsources: ");
140   for (i = 0; i < NoOf(unit->sources); i++) {
141     printf("%9d ", element(unit->sources, i) );
142   }
143   printf("\nweights: ");
144   for (i = 0; i < NoOf(unit->sources); i++) {
145     printf("%9f ", unit->weights[i] );
146   }
147   printf("\n");
148 }
149 
150 
printTDNNunit(pUnit unit)151 void printTDNNunit(pUnit unit)
152 {
153   int i, j;
154   printf("\nUnit %d", unit->number);
155   printf("\nmembers : ");
156   for (i = 0; i < NoOf(unit->members); i++) {
157     printf("%d ", element(unit->members, i) );
158   }
159   printf("\nsources: \n");
160   for (i = 0; i < unit->FeatureWidth; i++) {
161     for (j = 0; j < NoOf(unit->sources) / unit->FeatureWidth; j++) {
162       printf("%8d ", unit->TDNNsources[i][j]);
163     }
164     printf("\n");
165   }
166   printf("weights: \n");
167   for (i = 0; i < unit->FeatureWidth; i++) {
168     for (j = 0; j < NoOf(unit->sources) / unit->FeatureWidth; j++) {
169       printf("%8f ", unit->TDNNweights[i][j]);
170     }
171     printf("\n");
172   }
173 }
174 
175 /******************************************************************************
176   void toAlphaNum(char *string)
177   -----------------------------------------------------------------------------
178   replaces all characters in string wich are not alphanumerical with '_'.
179   Furtheron it deletes all characters before first '/'.
180   If the first Character is a digit, it is replaced by 'X'
181   ******************************************************************************/
toAlphaNum(char * string)182 void toAlphaNum(char *string)
183 {
184   char *pointer;
185 
186   pointer = string - 1;		/* because of increment in while-condition */
187   while( *(++pointer) != '\0') { /* to the end of the String                */
188     while (*pointer == '/') {	/* only the tail of Path-names             */
189       strcpy(string, pointer + 1);
190       pointer = string;
191     }
192     if (!isalnum(*pointer) ) *pointer = '_'; /* no special characters */
193   }
194   if (*string == '\0') strcpy (string, "NOTHING"); /* no empty strings      */
195   if (isdigit(*string) ) *string = 'X';	/* no leading digit      */
196 }
197 
198 
199 /******************************************************************************
200   void checkErr(int errCode)
201   -----------------------------------------------------------------------------
202   writes an error message if needed and also stops program if errCode
203   stands for a fatal error
204   -> errCode : code of the actual status
205   ******************************************************************************/
checkErr(int errCode)206 void checkErr(int errCode)
207 {
208   switch(errCode)
209       {
210       case OK          : ;
211 	break;
212       case ERR         : printf("unspecified Error\n");
213 	break;
214       case CANT_ADD    :
215       case MEM_ERR     : printf("not enough memory\n");
216 	break;
217       case CANT_LOAD   : printf("can't load file\n");
218 	break;
219       case WRONG_PARAM : printf("wrong parameters\n");
220 	break;
221       case CANT_OPEN   : printf("can't open file\n");
222 	break;
223       case NO_CPN      : printf("net is not a CounterPropagation network\n");
224 	break;
225       case NO_TDNN     : printf("net is not a Time Delay Neural Network\n");
226 	break;
227       case ILLEGAL_CYCLES : printf("net contains illegal cycles\n");
228 	break;
229       case WRONG_ACT_FUNC : ;
230 	break;
231       case NOT_SUPPORTED  : printf("not supported network type\n");
232 	break;
233       default             : printf("unknown error code : %d\n", errCode);
234       }
235 }
236 
237 
238 /*****************************************************************************
239   bool is_TDNN_net(void)
240   ----------------------------------------------------------------------------
241   checks, if the current Net is a Time Delay Neural Network by testing
242   the learning functions.
243   <- (func) : TRUE  Net is a TDNN Network
244   FALSE otherwise
245   *****************************************************************************/
is_TDNN_net(void)246 bool is_TDNN_net(void)
247 {
248   return (0 == strcmp("TimeDelayBackprop", krui_getLearnFunc() ) );
249 }
250 
251 
252 /*****************************************************************************
253   bool is_DLVQ_net(void)
254   ----------------------------------------------------------------------------
255   checks, if the current Net is a Dynamic LVQ Network by testing
256   the learning functions.
257   <- (func) : TRUE  Net is a TDNN Network
258   FALSE otherwise
259   *****************************************************************************/
is_DLVQ_net(void)260 bool is_DLVQ_net(void)
261 {
262   return (0 == strcmp("Dynamic_LVQ", krui_getLearnFunc() ));
263 }
264 
265 
266 /*****************************************************************************
267   bool is_CPN_net(void)
268   ----------------------------------------------------------------------------
269   checks, if the current Net is a CounterPropagation Network by testing
270   the learning functions.
271   <- (func) : TRUE  Net is a TDNN Network
272   FALSE otherwise
273   *****************************************************************************/
is_CPN_net(void)274 bool is_CPN_net(void)
275 {
276   return (0 == strcmp("Counterpropagation", krui_getLearnFunc() ));
277 }
278 
279 
280 /*****************************************************************************
281   bool is_BPTT_net(void)
282   ----------------------------------------------------------------------------
283   checks, if the current Net is a BPTT, BBPTT or QPTT Network by testing
284   the learning functions.
285   <- (func) : TRUE  Net is a kind of BPTT Network
286   FALSE otherwise
287   *****************************************************************************/
is_BPTT_net(void)288 bool is_BPTT_net(void)
289 {
290   return (   (0 == strcmp("BPTT", krui_getLearnFunc() ))
291 	  || (0 == strcmp("BBPTT", krui_getLearnFunc() ))
292 	  || (0 == strcmp("QPTT", krui_getLearnFunc() )) );
293 }
294 
295 
296 /*****************************************************************************
297   int checkLearnFunc(void)
298   ----------------------------------------------------------------------------
299   checks, if the Learning Function is supported by the snns2c
300   <- Error Code : OK / NOT_SUPPORTED
301   *****************************************************************************/
checkLearnFunc(void)302 int checkLearnFunc(void)
303 {
304   static char *NotSupportedLearnFuncs[] = {
305     "ART1", "ART2", "ARTMAP", "BackPercolation", "Hebbian", "RM_delta",
306     "Kohonen", NULL
307   };
308 
309   char *LearnFunc = krui_getLearnFunc();     /* learning function of the network */
310   char **string   = NotSupportedLearnFuncs;  /* current function name to test */
311 
312   while(*string) {
313     if (!strcmp(*string, LearnFunc)) {	     /* e.g. the same function-name */
314       return(NOT_SUPPORTED);
315     }
316     string++;
317   }
318 
319   return(OK);
320 }
321 
322 
323 /*****************************************************************************
324   bool is_Prototype_Unit(int UnitNr)
325   ----------------------------------------------------------------------------
326   checks, if the current unit is a prototype unit, e.g. if the links are
327   defined in this unit.
328 
329   Note : Function is only needed for TDNN
330 
331   <- (func) : TRUE  unit is a prototype unit
332   FALSE otherwise
333   *****************************************************************************/
is_Prototype_Unit(int UnitNr)334 bool is_Prototype_Unit(int UnitNr)
335 {
336   struct Unit *unit_ptr;
337 
338   if ((unit_ptr = kr_getUnitPtr( UnitNr ) ) == NULL) {
339     return (FALSE);
340   }
341   else {
342     return ( unit_ptr->TD.target_offset == 0);
343   }
344 }
345 
346 
347 /****************************************************************************
348   int get_Prototype_Unit(int(unitNr)
349   ---------------------------------------------------------------------------
350   returns the number of the prototype Unit and 0 if an error occurs
351 
352   Note : Function is only needed for TDNN
353 
354   <- (func) : Number of the Prototype Unit
355               (0 = Unit not found)
356   *****************************************************************************/
get_Prototype_Unit(int UnitNr)357 int get_Prototype_Unit(int UnitNr)
358 {
359   struct Unit *unit_ptr;
360 
361   if ((unit_ptr = kr_getUnitPtr( UnitNr ) ) == NULL) {
362     return (0);
363   }
364   else {
365     return (UnitNr + unit_ptr->TD.target_offset);
366   }
367 }
368 
369 
370 /****************************************************************************
371   pUnit searchUnit(int UnitNr, pUnit global Units, pUnit lastUnit)
372   ---------------------------------------------------------------------------
373   returns a pointer to the Unit wich has the current number UnitNr
374 
375   Note : Function is only needed for TDNN
376 
377   -> UnitNr      : Number of the UNit in the original SNNS network
378   globalUnits : Array of all existing snns2c-units
379   <- index       : index of the unit, found in the Array
380   (func)      : pointer to the unit or NULL if the unit isn't found
381 *****************************************************************************/
searchUnit(int UnitNr,pUnit globalUnits,int * index)382 pUnit searchUnit(int UnitNr, pUnit globalUnits, int *index)
383 {
384   pUnit unit;
385 
386   *index = 0;
387   for (unit = globalUnits; unit->number > 0; unit++, (*index)++) {
388     if (unit->number == UnitNr) return (unit);
389   }
390 
391   return(NULL);
392 }
393 
394 
395 /*****************************************************************************
396   int checkActFunc(char *actName)
397   ----------------------------------------------------------------------------
398   checks, if an activation Function with the name actName is present
399   -> actName : Name of the activation function
400   <- (func)  : number in the function table or -1 if not present
401 *****************************************************************************/
checkActFunc(char * actName)402 int checkActFunc(char *actName)
403 {
404   int i=0;
405 
406   while (**(ACT_FUNC_NAMES + i) ) {
407     if (!strcmp(ACT_FUNC_NAMES[i], actName) ) return (i);
408     i++;
409   }
410   fprintf(stderr, "Can't find the function <%s>\n", actName);
411   return(-1);
412 }
413 
414 
415 /*****************************************************************************
416   int initLayer(pLayer layer, pUnit unit)
417   ----------------------------------------------------------------------------
418   initialize the given layer e.g :
419   - initializes the two lists members and sources
420   - insert the type and the Number of the activation-function of the
421   given Unit in the predefined places.
422   - inserts the sources of the given Unit into the list sources
423 
424   -> layer : pointer to the new Layer
425   unit  : pointer to the first (e.g.prototype-) unit
426   <- (func) : Status (Errorcodes)
427   *****************************************************************************/
initLayer(pLayer layer,pUnit unit)428 int initLayer(pLayer layer, pUnit unit)
429 {
430   layer->members = newList();		   /* a list for member unit */
431   if (!layer->members) return(MEM_ERR);
432 
433   layer->sources = newList();		   /* a list for all predecessor */
434   if (!layer->sources) return(MEM_ERR);	   /* units of all members       */
435 
436   addList(layer->members, unit->number);   /* prototype unit is the first member */
437   if (copyList(layer->sources, unit->sources) ) return(MEM_ERR);
438 
439   layer->ActFunc = unit->ActFunc;
440   layer->type    = unit->type;
441 
442   unit->layer = layer;
443 
444   return(OK);
445 }
446 
447 
448 /******************************************************************************
449   int matchLayer(pLayer layer, pUnit unit)
450   -----------------------------------------------------------------------------
451   checks if the unit could be in the same layer as the other units wich
452   are in the layer yet
453   -> layer : pointer to the (existing) layer
454   unit  : pointer to the unit wich is to be prooved
455   <- (func) TRUE the unit matches with the other units
456   FALSE otherwise
457   ******************************************************************************/
matchLayer(pLayer layer,pUnit unit)458 int matchLayer(pLayer layer, pUnit unit)
459 {
460   static int is_BPTT = 0, first_time = 1;
461 
462   /* a special flag is set to avoid unneeded function calls */
463   if (first_time) {
464     is_BPTT = is_BPTT_net();
465     first_time = 0;
466   }
467 
468   /* input neurons are all treated the same way */
469   if ( (unit->type == INPUT) && (layer->type == INPUT) ) return (TRUE);
470 
471   /* unit should match the attributes of the Layer */
472   if (unit->type != layer->type) return(FALSE);
473   if (unit->ActFunc != layer->ActFunc) return(FALSE);
474 
475   /* BPTT-nets have no topological order */
476   if (is_BPTT) return (TRUE);
477 
478   /* unit must not be a member of the source units */
479   if (isMember(layer->sources, unit->number) ) return (FALSE);
480 
481   /* Neue Version von Matthias Oderdorfer */
482   return ( CompareSources(unit->sources, layer->sources) );
483 
484   /* alte Version */
485   /* a member of the layer must not be a source element of the unit */
486   /* return( !haveIntersection(unit->sources, layer->members) ); */
487 }
488 
489 
490 /******************************************************************************
491   int searchLayer(pUnit unit, pLayer globalLayers)
492   -----------------------------------------------------------------------------
493   searches a Layer with matches the unit (or an empty Layer) and inserts the
494   unit in the layer.
495   -> unit         : actual unit wich searches a friendly layer
496   globalLayers : array of all Layers
497   <- (func) MEM_ERR : not enough Memory
498   OK      : no problems
499   ******************************************************************************/
searchLayer(pUnit unit,pLayer globalLayers)500 int searchLayer(pUnit unit, pLayer globalLayers)
501 {
502   pLayer layer;
503 
504   layer = globalLayers;
505   while(TRUE) {
506     if (layer->members == NULL) {	   /* empty layer found */
507       return(initLayer(layer, unit));	   /* give possible Errors to caller */
508     }
509     else if (matchLayer(layer, unit) ) {   /* matching layer found */
510       if (addList(layer->members, unit->number)) {
511 	return(MEM_ERR);
512       }
513       unit->layer = layer;
514       return(mergeList(layer->sources, unit->sources)); /* returns Status */
515     }
516     layer++;
517   }
518 }
519 
520 
521 /******************************************************************************
522   int divideNet(pUnit globalUnits, pLayer globalLayers, int *TDNN_prot)
523   -----------------------------------------------------------------------------
524   parts a net into groups and prepares the Net for sorting the
525   layers.
526 
527   -> globalUnits  : all the Units are going to be written in this array
528   globalLayers : all the different Layers will be written in this array
529   <- globalUnits  : (the values in the array)
530   globalLayers : (the values in the array)
531   TDNN_prot    : The numbers of the prototype units of each unit
532   <- (func) MEM_ERR : not enough Memory
533   OK      : no problems
534   ******************************************************************************/
divideNet(pUnit globalUnits,pLayer globalLayers,int * TDNN_prot)535 int divideNet(pUnit globalUnits, pLayer globalLayers, int *TDNN_prot)
536 {
537   int       unitNo, sourceNo;		   /* number of the unit and source unit */
538   int       prototypeNo;                   /* number of the prototype unit */
539   pUnit     unit, prot_unit;		   /* unit and prototype unit */
540   FlintType dummy, weight;		   /* link weights */
541   bool      isTDNN;			   /* flag for TDNN networks */
542   int       error;			   /* error code    */
543   char      *string;			   /* free variable */
544   int       pos;			   /* free variable */
545 
546   /* Testing if the network is a TDNN-network */
547   isTDNN = is_TDNN_net();
548 
549   /* --------------------------------------------
550    * loading all Units and group them into Layers
551    */
552   unitNo = krui_getFirstUnit();
553   unit   = globalUnits;
554 
555   while (unitNo) {
556     unit->members = newList();
557     if (!unit->members) return (MEM_ERR);
558 
559     /* TDNN-Units wich are not Prototype-Units are
560      * treated in a special way ...
561      */
562     if (isTDNN && !is_Prototype_Unit(unitNo) ) {
563       prototypeNo = get_Prototype_Unit(unitNo);
564       TDNN_prot[unitNo] = prototypeNo;	         /* fix the Number of the prototype Unit */
565       prot_unit = searchUnit(prototypeNo, globalUnits, &pos);
566       if (!prot_unit) return(ERR);		 /* prototype unit not found */
567       addList(prot_unit->members, unitNo);
568       unitNo = krui_getNextUnit();
569       continue;					 /* nothing else to do */
570     }
571 
572     /*
573      * TDNN Prototype-Units are treated as normal units
574      */
575     unit->number  = unitNo;
576     addList(unit->members, unitNo);	/* the Prototype is also part of the member list */
577     TDNN_prot[unitNo] = unitNo;		/* the prototype unit is his own prototype */
578 
579     /* copy the entries from SNNS to the own format */
580     unit->act     = krui_getUnitActivation(unitNo);
581     unit->type    = krui_getUnitTType(unitNo);
582     unit->Bias    = krui_getUnitBias(unitNo);
583 
584     /* units always have a name (at least its old number) */
585     string = krui_getUnitName(unitNo);
586     if (NULL == string) {
587       unit->name = malloc(12 * sizeof(char));
588       if(! unit->name) {
589 	return (MEM_ERR);
590       }
591       sprintf(unit->name, "Old: %d", unit->number);
592     }
593     else {
594       unit->name = malloc(MAX(1,strlen(string)+1));
595       if(! unit->name) {
596 	return (MEM_ERR);
597       }
598       strcpy(unit->name, string);
599     }
600 
601     unit->ActFunc = checkActFunc(krui_getUnitActFuncName(unitNo) );
602     if (unit->ActFunc < 0) return(WRONG_ACT_FUNC);
603 
604     /* insert all Source units in the list */
605     unit->sources = newList();
606     if (!unit->sources) return (MEM_ERR);
607     sourceNo = krui_getFirstPredUnit(&dummy);
608     while (sourceNo) {
609       /* only special-hidden-neurons may have links to itself */
610       if ( (unit->type != SPECIAL_H) && !is_BPTT_net() ) {
611         if (unit->number == sourceNo) return(ILLEGAL_CYCLES);
612       }
613       if(addList(unit->sources, sourceNo)) return (MEM_ERR);
614       sourceNo = krui_getNextPredUnit(&dummy);
615     }
616     /* now the weights can be written in the right order */
617     /* One more Element is allocated, because the array might have size 0 */
618     unit->weights = (float *)malloc(NoOf(unit->sources) * sizeof(float) + sizeof(float));
619     if (!unit->weights) return(MEM_ERR);
620     sourceNo = krui_getFirstPredUnit(&weight);
621     while (sourceNo) {
622       pos = searchList(unit->sources, sourceNo);
623       unit->weights[pos] = weight;
624       sourceNo = krui_getNextPredUnit(&weight);
625     }
626 #ifdef debug
627     printUnit(unit);
628 #endif
629     error = searchLayer(unit, globalLayers);
630 		if (error) return(error);
631 
632     unit++;
633     unitNo = krui_getNextUnit();
634   }
635 
636   return(OK);
637 }
638 
639 
640 /****************************************************************************
641   int prepareCpnUnits(pUnit globalUnits, pLayer global Layers, int NoOfLayers)
642   ---------------------------------------------------------------------------
643   calculates the entries in the Units, wich are necessary for CPN
644   -> globalUnits  : all units of the net
645      globalLayers : all layers of the net
646   <- (func)  MEM_ERR : Not enough memory
647   ERR     : Error in structure of the Network
648   OK      : No problems found
649   ****************************************************************************/
prepareCpnUnits(pUnit globalUnits,pLayer globalLayers)650 int prepareCpnUnits(pUnit globalUnits, pLayer globalLayers)
651 {
652   pLayer HiddenLayer, OutputLayer;       /* pointer to the hidden and Output layer */
653   int    memberNr, sourceNr, dummy;      /* loop-variables                         */
654 
655   /* CPN-Nets need a fixed architecture : */
656   if (   (globalLayers[0].type != INPUT)
657       || (globalLayers[1].type != HIDDEN)
658       || (globalLayers[2].type != OUTPUT)
659       || (globalLayers[3].members != NULL)  /* there must not exist a forth layer */
660       ) {
661     return(NO_CPN);
662   }
663 
664   /* better to read */
665   HiddenLayer = globalLayers + 1;
666   OutputLayer = HiddenLayer + 1;
667 
668 
669   for (memberNr = 0; memberNr < NoOf(HiddenLayer->members); memberNr++) {
670     pUnit unit = searchUnit(element(HiddenLayer->members, memberNr), globalUnits, &dummy);
671     if (unit == NULL) return (NO_TDNN);
672 
673     if (NULL == (unit->dest = malloc(NoOf(OutputLayer->members))) ) {
674       return(MEM_ERR);
675     }
676   }
677 
678   for (memberNr = 0; memberNr < NoOf(OutputLayer->members); memberNr++) {
679     pUnit dest = searchUnit(element(OutputLayer->members, memberNr), globalUnits, &dummy);
680     if (dest == NULL) return (NO_CPN);
681 
682     /* Hiddenlayer and Outputlayer must be fully connected */
683     if (NoOf(dest->sources) != NoOf(HiddenLayer->members)) {
684       return(NO_CPN);
685     }
686 
687     /* copy the weights to the hidden units */
688     for(sourceNr = 0; sourceNr < NoOf(dest->sources); sourceNr++) {
689       pUnit source = searchUnit(element(dest->sources,sourceNr), globalUnits, &dummy);
690       if (source == NULL) return (NO_CPN);
691       printUnit(source);
692       source->dest[memberNr] = dest->weights[sourceNr];
693       source->NoOfDest = NoOf(OutputLayer->members);
694     }
695   }
696 
697   return(OK);
698 }
699 
700 
701 /****************************************************************************
702   int prepareTDNNunits(pUnit globalUnits, int *TDNN_prot)
703   ---------------------------------------------------------------------------
704   calculates the entries in the Units, wich are necessary for TDNNs
705   -> globalUnits  : all units of the net
706   TDNN_prot    : Array with the numbers of the needed prototypes
707   <- (func)  MEM_ERR : Not enough memory
708   NO_TDNN : Error in structure of the Network
709   MEM_ERR : not enough memory
710   OK      : No problems found
711   ****************************************************************************/
prepareTDNNunits(pUnit globalUnits,int * TDNN_prot)712 int prepareTDNNunits(pUnit globalUnits, int *TDNN_prot)
713 {
714   int   sourceNo;		  /* Unit Number of the current source unit         */
715   int   protNo;			  /* Unit Number of the current prototype Unit      */
716   pUnit unit;			    /* Current examined Unit                          */
717   pList ProtSources;  /* List with the prototype source units           */
718   int   *countArray;	/* Counters for the entries in the raws           */
719   int   raw;			    /* current raw in the weight matrix of a unit     */
720   int   listNo;			  /* Number of a list entry                         */
721   int   i, delay;
722 
723   countArray = malloc(sizeof(int)); /* necessary because of the reallocs */
724 	if(! countArray) {
725 		return MEM_ERR;
726 	}
727 
728   for(unit = globalUnits; unit->number != 0; unit++) { /* e.g. All Units */
729 
730     ProtSources = newList();	/* An own list for each unit */
731 		if(! ProtSources) {
732 			free(countArray);
733 			return MEM_ERR;
734 		}
735 
736     /* finding all Prototype Units in the source Units */
737     for (listNo = 0; listNo < NoOf(unit->sources); listNo++) {
738 
739       sourceNo = element(unit->sources, listNo);
740 
741       if (sourceNo == TDNN_prot[sourceNo]) { /* e.g. his own prototype */
742         addList(ProtSources, sourceNo);
743       }
744 
745     }
746 
747     if (NoOf(unit->sources) == 0) { /* Must be an input unit           */
748       killList(ProtSources);	/* e.g. has no sources and weights */
749       unit->FeatureWidth = 0;
750       unit->DelayLength = 0;
751       continue;			/* so nothing to do                */
752     }
753 
754     /* A simple check (delay * width = Number of Sources) */
755     if ( (NoOf(unit->sources) % NoOf(ProtSources)) != 0 ) {
756       printf("Unit %d has wrong count of Source Units", unit->number);
757       return(NO_TDNN);
758     }
759 
760     unit->FeatureWidth = NoOf(ProtSources);
761     unit->DelayLength  = NoOf(unit->sources) / unit->FeatureWidth;
762 
763     /* get Memory for the new data structures            */
764     /* width := NoOf(ProtSources); Delay Length := delay */
765     countArray        = (int *)realloc(countArray, NoOf(ProtSources) * sizeof(int) );
766     unit->TDNNsources = (int **)malloc(NoOf(ProtSources) * sizeof (int *) );
767     unit->TDNNweights = (float **)malloc(NoOf(ProtSources) * sizeof (float *) );
768 
769     delay = unit->DelayLength;
770     for(i = 0; i < NoOf(ProtSources); i++) {
771       unit->TDNNsources[i] = (int *)malloc(delay * sizeof(int));
772       unit->TDNNweights[i] = (float *)malloc(delay * sizeof(float));
773       if(unit->TDNNweights[i] == NULL) return (MEM_ERR);
774     }
775 
776     /** write New Datas **/
777     /* At first one Prototype Unit for each raw */
778     for(raw = 0; raw < NoOf(ProtSources); raw++) {
779       sourceNo = element(ProtSources, raw);
780       unit->TDNNsources[raw][0] = sourceNo;
781       countArray[raw] = 1;
782     }
783 
784     /* Then writing the other weights and sources */
785     for(i = 0; i < NoOf(unit->sources); i++) {
786       sourceNo = element(unit->sources, i);
787       protNo   = TDNN_prot[sourceNo];
788 
789       /* Searching the raw with the Prototype unit */
790       for(raw = 0; raw < NoOf(ProtSources); raw++) {
791 	if(unit->TDNNsources[raw][0] == protNo) break; /* Prototype Unit found */
792       }
793       if(unit->TDNNsources[raw][0] != protNo) {
794 	printf("Prototype Unit (%d) of (%d) not found", protNo, sourceNo);
795 	free(countArray);
796 	return(NO_TDNN);
797       }
798 
799       /* writing SourceNumber and weight */
800       if (sourceNo == protNo ) {	     /* Prototype Unit */
801 	unit->TDNNweights[raw][0] = unit->weights[i];
802       }
803       else {
804 	unit->TDNNsources[raw][countArray[raw]] = sourceNo;
805 	unit->TDNNweights[raw][countArray[raw]] = unit->weights[i];
806 	countArray[raw]++;		     /* one more entry */
807       }
808     }
809 
810     killList(ProtSources);
811 
812   }
813 
814   free(countArray);
815   return(OK);
816 }
817 
818 /****************************************************************************
819   char checkOrder(pLayer globalLayers, int x, int y)
820   ---------------------------------------------------------------------------
821   checks the order between layer x and layer y
822 
823   SIDE-EFFECT : the entry SuccDelay is set up, if one layer follows
824   immediatly another. (needed by TDNN-networks)
825 
826   -> globalLayers : all layers of the net
827   x, y         : numbers of layer x and y
828   <- (func)    -1       : layer x before layer y
829   0       : indifferent
830   1       : layer x after layer y
831   ILLEGAL_CYCLES : error occured (no order given)
832   ****************************************************************************/
checkOrder(pLayer globalLayers,int x,int y)833 signed char checkOrder(pLayer globalLayers, int x, int y)
834 {
835   /* preference of the unit type : low value means early update */
836   static char pref[12] = {0, 0, 2, 0, 1, 3, 3, 3, 3, 3, 3, 3};
837 
838   signed char order = 0;
839 
840   if (pref[globalLayers[x].type] < pref[globalLayers[y].type]) {
841     order = (signed char)-1;	/* e.g. layer x before layer y */
842   }
843   else if (pref[globalLayers[x].type] > pref[globalLayers[y].type]) {
844     order = 1;			/* e.g. layer x after layer y */
845   }
846 
847 	/* BPTT-Networks may contain any cycles so they must not be checked */
848 	if (is_BPTT_net() ) {
849 		return(order);
850 	}
851 
852   if (haveIntersection(globalLayers[x].sources, globalLayers[y].members) ) {
853     globalLayers[y].SuccDelay = globalLayers[x].delay; /* Side-Effect */
854     if (order == -1) {
855       if (SPECIAL_H != globalLayers[y].type) return (ILLEGAL_CYCLES);
856     }
857     else {
858       order = 1;
859     }
860   }
861   if (haveIntersection(globalLayers[x].members, globalLayers[y].sources) ) {
862     globalLayers[x].SuccDelay = globalLayers[y].delay; /* Side-Effect */
863     if (order == 1) {
864       if (SPECIAL_H != globalLayers[x].type) return (ILLEGAL_CYCLES);
865     }
866     else {
867       order = (signed char)-1;
868     }
869   }
870 
871   return(order);
872 }
873 
874 
875 /*****************************************************************************
876   int sortNet(pLayer globalLayers, int NoOfLayers, int *order)
877   ----------------------------------------------------------------------------
878   calculates the order between the globalLayers an returns it in the array
879   order. So the first number in the array is the first Layer to be updated
880   and so on.
881   -> globalLayers : Array of all layers in the net
882   NoOfLayers   : Number of all layers in the net
883   <- order        : the order for updating the layers
884   (func)    OK : no errors occured
885   MEM_ERR : not enough memory for calculations
886   *****************************************************************************/
sortNet(pLayer globalLayers,int NoOfLayers,int * order)887 int sortNet(pLayer globalLayers, int NoOfLayers, int *order)
888 {
889   char **matrix;		/* precedence matrix        */
890   char  *mask;			/* already chosen layers    */
891   int    i, j, x, y, ord, isSource = TRUE;
892   char   precedence;
893 
894   /* reserve memory for all the arrays and matrices */
895   matrix = (char **)malloc(NoOfLayers * sizeof(char *) );
896   if (!matrix) return (MEM_ERR);
897 
898   for (i = 0; i < NoOfLayers; i++) {
899     matrix[i] = (char *)calloc(NoOfLayers, sizeof(char) );
900     if (!matrix[i]) return (MEM_ERR);
901   }
902 
903   mask  = (char *)calloc(NoOfLayers, sizeof(char) );
904   if (!mask) {
905 		free(matrix);
906 		return (MEM_ERR);
907 	}
908 
909   /** build the precedence matrix of the Layer-Graph */
910   for (y = 0; y < NoOfLayers; y++) {
911     for (x = y + 1; x < NoOfLayers; x++) {
912       precedence = checkOrder(globalLayers, x, y);
913       if (precedence == ILLEGAL_CYCLES) return(ILLEGAL_CYCLES);
914 
915       matrix[x][y] = precedence;
916       matrix[y][x] = -precedence;
917 
918     } /* for x */
919 
920   } /* for y */
921 
922 #ifdef debug
923   printf("\nPrecedence Matrix is:\n");
924   for (y = 0; y < NoOfLayers; y++) {
925     for (x = 0; x < NoOfLayers; x++) {
926       printf("%3d ", matrix[y][x]);
927     }
928     printf("\n");
929   }
930 #endif
931 
932   /** put the Layers in the right order **/
933   for (ord = 0; ord < NoOfLayers; ord++) {
934 
935     for (i = 0; i < NoOfLayers; i++) {
936       if (mask[i]) continue;	/* Layer already chosen */
937 
938       isSource = TRUE;
939       for (j = 0; j < NoOfLayers; j++) {
940         /* exists a layer wich must be updated before ? */
941         if (matrix[i][j] == 1) {
942           isSource = FALSE;
943           break;
944         }
945       }
946 
947       if (isSource) {
948         order[ord] = i;		/* the number of the Layer becomes ord */
949         mask[i] = 1;		/* must not test this Layer again      */
950 
951         for (j = 0; j < NoOfLayers; j++) {
952           matrix[j][i] = 0;	/* clear depencies for other Layers */
953         }
954 
955         break;			/* find next Layer */
956       }
957 
958     } /* for i */
959 
960     if (!isSource) {
961       return(ILLEGAL_CYCLES);
962     }
963 
964   } /* for ord */
965 
966   for (i = 0; i < NoOfLayers; i++) {
967     free(matrix[i]);
968   }
969   free(matrix);
970   free(mask);
971 
972 #ifdef debug
973   printf("\nLayers sorted in following order :\n");
974   for (i = 0; i < NoOfLayers; i++) {
975     printf(" %d", order[i]);
976   }
977   printf("\n");
978 #endif
979 
980   return(OK);
981 }
982 
983 
984 /*****************************************************************************
985   void writeList(pList list, FILE *fOutFile)
986   ----------------------------------------------------------------------------
987   writes a List to a OutputFile in the Form :
988   { <element1>, <element2>, ... }
989   -> list     : pointer to the list wich is to be written
990   fOutFile : appreciated output stream
991   *****************************************************************************/
writeList(pList list,FILE * fOutFile)992 void writeList(pList list, FILE *fOutFile)
993 {
994   int e;			/* (like element) Element counter for the list */
995 
996   fprintf(fOutFile, "{");
997   if (0 == NoOf(list) ) fprintf(fOutFile, "0 /*NO MEMBERS */");
998   for(e = 0; e < NoOf(list); e++) {
999     fprintf(fOutFile, "%d", element(list, e) );
1000     if (e < NoOf(list) - 1) fprintf(fOutFile, ", ");
1001   }
1002   fprintf(fOutFile, "}");
1003 }
1004 
1005 
1006 /*****************************************************************************
1007   void writeLayer(pLayer layer,  FILE *fOutFile)
1008   ----------------------------------------------------------------------------
1009   writes the LayerName and his members as an array of integers to the
1010   given OutputStream
1011   -> layer     : layer wich is to be written
1012   LayerName : a C-identifier for the struct
1013   fOutFile  : appreciated output stream
1014   *****************************************************************************/
writeLayer(pLayer layer,FILE * fOutFile)1015 void writeLayer(pLayer layer, FILE *fOutFile)
1016 {
1017 	int i;
1018 
1019   fprintf(fOutFile, "\n  static pUnit %s[%d] = ",
1020           layer->name, NoOf(layer->members) );
1021 
1022   /* write the Members of the layer */
1023 	fprintf(fOutFile, "{");
1024   for(i = 0; i < NoOf(layer->members); i++) {
1025 		/* write the members as pointer to the member units */
1026     fprintf(fOutFile, "Units + %d", element(layer->members,i) );
1027     if (i < NoOf(layer->members) - 1) fprintf(fOutFile, ", ");
1028   }
1029 
1030   fprintf(fOutFile, "}; /* members */\n");
1031 }
1032 
1033 /*****************************************************************************
1034   void writeUnitNew(pUnit unit, FILE *fOutFile)
1035   ----------------------------------------------------------------------------
1036   writes a Unit ( activation, bias, sources, Linkweights) as a struct to the
1037   Outfile
1038   -> unit   : unit wich is to be written
1039   fOutFile  : appreciated output stream
1040   Autor     : Matthias Oberdorfer
1041   *****************************************************************************/
writeUnitNew(pUnit unit,FILE * fOutFile,int count_links)1042 void writeUnitNew(pUnit unit, FILE *fOutFile, int count_links)
1043  {
1044 
1045   static int first_time = 1, is_Bptt = 0; /* to avoid unneeded procedure calls */
1046 
1047  	/* initialisation of is_Bptt */
1048  	if (first_time) {
1049  		is_Bptt = is_BPTT_net();
1050  		first_time = 0;
1051  	}
1052 
1053   /* write Number and Name of the unit for identification,
1054    * if a user is reading the code
1055    */
1056   fprintf(fOutFile, "    { /* unit %d (%s) */\n", unit->number, unit->name);
1057 
1058   /* write Activation, Bias and number of sources */
1059   if (is_Bptt) {
1060     fprintf(fOutFile, "      {%f, 0.0}, %f, %d,\n",
1061  	    unit->act, unit->Bias, NoOf(unit->sources));
1062    }
1063    else {
1064      fprintf(fOutFile, "      0.0, %f, %d,\n",unit->Bias, NoOf(unit->sources));
1065    }
1066 
1067    /* write the Sources of the unit */
1068    fprintf(fOutFile, "       &Sources[%d] , \n", count_links);
1069    /* write the weights of the units */
1070    fprintf(fOutFile, "       &Weights[%d] , \n", count_links);
1071 
1072    fprintf(fOutFile, "      }");
1073  }
1074 
1075 /*****************************************************************************
1076   void writeUnit(pUnit unit, FILE *fOutFile)
1077   ----------------------------------------------------------------------------
1078   writes a Unit ( activation, bias, sources, Linkweights) as a struct to the
1079   Outfile
1080   -> unit      : unit wich is to be written
1081   fOutFile  : appreciated output stream
1082   *****************************************************************************/
writeUnit(pUnit unit,FILE * fOutFile)1083 void writeUnit(pUnit unit, FILE *fOutFile)
1084  {
1085   int i;
1086   static int first_time = 1, is_Bptt = 0; /* to avoid unneeded procedure calls */
1087 
1088 	/* initialisation of is_Bptt */
1089 	if (first_time) {
1090 		is_Bptt = is_BPTT_net();
1091 		first_time = 0;
1092 	}
1093 
1094   /* write Number and Name of the unit for identification, if a user is reading the code */
1095   fprintf(fOutFile, "    { /* unit %d (%s) */\n", unit->number, unit->name);
1096 
1097   /* write Activation, Bias and number of sources */
1098   if (is_Bptt) {
1099     fprintf(fOutFile, "      {%f, 0.0}, %f, %d,\n",
1100 	    unit->act, unit->Bias, NoOf(unit->sources));
1101   }
1102   else {
1103     fprintf(fOutFile, "      0.0, %f, %d,\n",unit->Bias, NoOf(unit->sources));
1104   }
1105 
1106   /* write the Sources of the unit */
1107   fprintf(fOutFile, "      {");
1108   /* There should be at least one element in the list */
1109   if (NoOf(unit->sources) ==  0) fprintf(fOutFile, "NULL /* no source units */");
1110   for(i = 0; i < NoOf(unit->sources); i++) {
1111     /* write the sources as pointer to the source units */
1112     fprintf(fOutFile, "Units + %d", element(unit->sources,i) );
1113     if (i < NoOf(unit->sources) - 1) fprintf(fOutFile, ", ");
1114   }
1115   fprintf(fOutFile, "},\n");
1116 
1117   /* write the weights of the units */
1118   fprintf(fOutFile, "      {");
1119   /* ANSI-C needs at least one entry in an array */
1120   if (0 == NoOf(unit->sources) ) fprintf(fOutFile, "0.0 /* NO MEMBERS */");
1121 
1122   for(i = 0; i < NoOf(unit->sources); i++) {
1123     fprintf(fOutFile, "%f", unit->weights[i]);
1124     if (i < NoOf(unit->sources) - 1) fprintf(fOutFile, ", ");
1125   }
1126 
1127   fprintf(fOutFile, "}\n    }");
1128 }
1129 
1130 
1131 /*****************************************************************************
1132   void writeCpnUnit(pUnit unit, FILE *fOutFile)
1133   ----------------------------------------------------------------------------
1134   writes a CPN Unit ( activation, bias, sources, Linkweights, dest) as a struct to the
1135   Outfile
1136   -> unit      : unit wich is to be written
1137   fOutFile  : appreciated output stream
1138   *****************************************************************************/
writeCpnUnit(pUnit unit,FILE * fOutFile)1139 void writeCpnUnit(pUnit unit, FILE *fOutFile)
1140 {
1141   int i;
1142 
1143   /* output-units are dummy-units */
1144   if (unit->type == OUTPUT) {
1145     fflush(fOutFile);
1146     fprintf(fOutFile, CpnDummyUnit);
1147     fflush(fOutFile);
1148     return;
1149   }
1150 
1151   /* write Number and Name of the unit for identification, if a user is reading the code */
1152   fprintf(fOutFile, "    { /* unit %d (%s) */\n", unit->number, unit->name);
1153 
1154   /* write Activation, Bias and number of sources */
1155   fprintf(fOutFile, "      0.0, %f, %d,\n",unit->Bias, NoOf(unit->sources));
1156 
1157   /* write the Sources of the unit */
1158   fprintf(fOutFile, "      {");
1159   /* There should be at least one element in the list  */
1160   if ((NoOf(unit->sources) ==  0) || (unit->type == OUTPUT) ){
1161     fprintf(fOutFile, "NULL /* no source units */");
1162   }
1163   for(i = 0; i < NoOf(unit->sources); i++) {
1164 		/* write the sources as pointer to the source units */
1165     fprintf(fOutFile, "Units + %d", element(unit->sources,i) );
1166     if (i < NoOf(unit->sources) - 1) fprintf(fOutFile, ", ");
1167   }
1168 	fprintf(fOutFile, "},\n");
1169 
1170   /* write the weights of the units */
1171   fprintf(fOutFile, "      {");
1172   /* ANSI-C needs at least one entry in an array */
1173   if (0 == NoOf(unit->sources) ) fprintf(fOutFile, "0.0 /* NO MEMBERS */");
1174 
1175   for(i = 0; i < NoOf(unit->sources); i++) {
1176     fprintf(fOutFile, "%f", unit->weights[i]);
1177     if (i < NoOf(unit->sources) - 1) fprintf(fOutFile, ", ");
1178   }
1179   fprintf(fOutFile, "},\n");
1180 
1181   /* write the weights from hidden to the output */
1182   if (unit->type == INPUT) {             /* inputs haven't such weights */
1183     fprintf(fOutFile, "      {0.0}\n");
1184   }
1185   else {
1186     fprintf(fOutFile, "      {");
1187     for(i = 0; i < unit->NoOfDest; i++) {
1188       fprintf(fOutFile, "%f", unit->dest[i]);
1189       if (i < unit->NoOfDest - 1) fprintf(fOutFile, ", ");
1190     }
1191     fprintf(fOutFile, "}\n");
1192   }
1193   fprintf(fOutFile, "    }");
1194 }
1195 
1196 
1197 /*****************************************************************************
1198   void writeTdnnUnit(pUnit unit, FILE *fOutFile)
1199   ----------------------------------------------------------------------------
1200   writes a TdnnUnit ( activation, bias, sources, Linkweights)
1201   as a struct to the Outfile
1202   -> unit      : unit wich is to be written
1203   Units     : pointer to the global UnitArray
1204   fOutFile  : appreciated output stream
1205   *****************************************************************************/
writeTdnnUnit(pUnit unit,pUnit Units,FILE * fOutFile)1206 void writeTdnnUnit(pUnit unit, pUnit Units, FILE *fOutFile)
1207 {
1208   int feature, delay, sourceIndex, pos;
1209 
1210   /* write Number and Name of the unit for identification by a user */
1211   fprintf(fOutFile, "    { /* unit %d (%s) */\n", unit->index, unit->name);
1212 
1213   /* write Activation, Bias and number of sources */
1214   fprintf(fOutFile, "      {");
1215   for (delay = 1; delay < unit->NoOf(members); delay++) fprintf(fOutFile, "0.0, ");
1216   fprintf(fOutFile, "0.0}, %f, %d,",unit->Bias, unit->FeatureWidth);
1217 
1218   /* write the Sources of the Unit */
1219   fprintf(fOutFile, "\n      {");
1220 
1221   /* ANSI-C needs at least one entry in an array */
1222   if (0 == NoOf(unit->sources) ) fprintf(fOutFile, "NULL /* NO SOURCES */");
1223 
1224   for(feature = 0; feature < unit->FeatureWidth; feature++) {
1225     sourceIndex = searchUnit(unit->TDNNsources[feature][0], Units, &pos)->index;
1226     fprintf(fOutFile, "Units + %d", sourceIndex);
1227     if (feature < unit->FeatureWidth - 1) fprintf(fOutFile, ", ");
1228   }
1229   fprintf(fOutFile, "},\n");
1230 
1231 
1232   /* write the weights to the source units */
1233   fprintf(fOutFile, "      {");
1234 
1235   /* ANSI-C needs at least one entry in an array */
1236   if (0 == NoOf(unit->sources) ) fprintf(fOutFile, " {0.0} /* NO WEIGHTS */");
1237 
1238   for(feature = 0; feature < unit->FeatureWidth; feature++) {
1239     fprintf(fOutFile, "\n         {");
1240 
1241     for(delay = 0; delay < unit->DelayLength; delay++) {
1242       fprintf(fOutFile, "%f", unit->TDNNweights[feature][delay]);
1243       if (delay < unit->DelayLength - 1) fprintf(fOutFile, ", ");
1244     }
1245 
1246     fprintf(fOutFile, "}");
1247     if (feature < unit->FeatureWidth - 1) fprintf(fOutFile, ", ");
1248   }
1249   fprintf(fOutFile, "\n      }\n    }");
1250 
1251   fflush(fOutFile);
1252 }
1253 
1254 
1255 
1256 /*****************************************************************************
1257   void writeAllUnitsOld(pUnit Units, int NoOfUnits, FILE *fOutFile)
1258   ----------------------------------------------------------------------------
1259   writes all Units of the Net as an array of structs to the OutputFile
1260   -> pUnits    : array of all units of the net
1261   NoOfUnits : #units in the net
1262   fOutFile  : appreciated output stream
1263   *****************************************************************************/
writeAllUnitsOld(pUnit Units,int NoOfUnits,FILE * fOutFile)1264 void writeAllUnitsOld(pUnit Units, int NoOfUnits, FILE *fOutFile)
1265 {
1266   int nr;
1267 
1268   fprintf(fOutFile, "  /* unit definition section (see also UnitType) */\n");
1269 
1270   /* Writing declaration of the Unit-Array */
1271   /* the 0-Element is left free because the comiler was easier
1272    * to implement this way. The only exeptions are the TDNNs
1273    * because here the Units are rewritten completely */
1274   if (is_TDNN_net()) {
1275     fprintf(fOutFile,
1276 	    "  static UnitType Units[%d] = \n  {\n", NoOfUnits
1277 	    );
1278   }
1279   else if (is_CPN_net() ){
1280     fflush(fOutFile);
1281     fprintf(fOutFile,
1282 	    "  static UnitType Units[%d] = \n  {\n %s,\n",
1283 	    NoOfUnits + 1, CpnDummyUnit
1284 	    );
1285     fflush(fOutFile);
1286   }
1287   else if (is_BPTT_net() ) {
1288     fprintf(fOutFile,
1289 	    "  static UnitType Units[%d] = \n  {\n    %s,\n",
1290 	    NoOfUnits + 1,
1291 	    "{ {0.0, 0.0}, 0.0, 0, {NULL /* NO SOURCES */}, {0.0 /* NO MEMBERS*/} }"
1292 	    );
1293   }
1294   else {
1295     fprintf(fOutFile,
1296 	    "  static UnitType Units[%d] = \n  {\n    %s,\n",
1297 	    NoOfUnits + 1,
1298 	    "{ 0.0, 0.0, 0, {NULL /* NO SOURCES */}, {0.0 /* NO MEMBERS*/} }"
1299 	    );
1300   }
1301 
1302   /* Because of the special requirements of each network-type
1303    * the Unit types are slightly modified for each update-function.
1304    * so they need a special output-template */
1305   if (is_TDNN_net() ) {
1306     for(nr = 0; nr < NoOfUnits; nr++) {
1307      writeTdnnUnit(Units + nr, Units, fOutFile);
1308       if (nr < NoOfUnits -1) fprintf(fOutFile, ",\n");
1309       else                   fprintf(fOutFile, "\n");
1310     }
1311   }
1312   else if(is_CPN_net() ) {
1313     for(nr = 0; nr < NoOfUnits; nr++) {
1314       if (nr != 0) {
1315 	fprintf(fOutFile, ",\n");
1316       }
1317       writeCpnUnit(Units + nr, fOutFile);
1318     }
1319     fprintf(fOutFile, "\n");
1320   }
1321   /* Here also BPTT-units are included, because they are very similar to
1322      the other types */
1323   else {
1324     for(nr = 0; nr < NoOfUnits; nr++) {
1325       writeUnit(Units + nr, fOutFile);
1326       if (nr < NoOfUnits -1) fprintf(fOutFile, ",\n");
1327       else                   fprintf(fOutFile, "\n");
1328     }
1329   }
1330   fprintf(fOutFile, "\n  };\n\n");
1331 }
1332 
1333 /*****************************************************************************
1334   void writeAllUnits(pUnit Units, int NoOfUnits, FILE *fOutFile)
1335   ----------------------------------------------------------------------------
1336   writes all Units of the Net as an array of structs to the OutputFile
1337   -> pUnits    : array of all units of the net
1338   NoOfUnits : #units in the net
1339   fOutFile  : appreciated output stream
1340   Autor     : Matthias Oberdorfer (changed original)
1341   *****************************************************************************/
writeAllUnits(pUnit Units,int NoOfUnits,FILE * fOutFile)1342 void writeAllUnits(pUnit Units, int NoOfUnits, FILE *fOutFile)
1343 {
1344   int nr;
1345   int count_links;  /* to give number to links */
1346 
1347   fprintf(fOutFile, "  /* unit definition section (see also UnitType) */\n");
1348 
1349   /* Writing declaration of the Unit-Array */
1350   /* the 0-Element is left free because the comiler was easier
1351    * to implement this way. The only exeptions are the TDNNs
1352    * because here the Units are rewritten completely */
1353   if (is_TDNN_net()) {
1354     fprintf(fOutFile,
1355 	    "  static UnitType Units[%d] = \n  {\n", NoOfUnits
1356 	    );
1357   }
1358   else if (is_CPN_net() ){
1359     fflush(fOutFile);
1360     fprintf(fOutFile,
1361 	    "  static UnitType Units[%d] = \n  {\n %s,\n",
1362 	    NoOfUnits + 1, CpnDummyUnit
1363 	    );
1364     fflush(fOutFile);
1365   }
1366   else if (is_BPTT_net() ) {
1367     fprintf(fOutFile,
1368 	    "  static UnitType Units[%d] = \n  {\n    %s,\n",
1369 	    NoOfUnits + 1,
1370 	    "{ {0.0, 0.0}, 0.0, 0, {NULL /* NO SOURCES */}, {0.0 /* NO MEMBERS*/} }"
1371 	    );
1372   }
1373   else {
1374 
1375     fprintf(fOutFile,
1376 	    "  static UnitType Units[%d] = \n  {\n    %s,\n",
1377 	    NoOfUnits + 1,
1378 	    "{ 0.0, 0.0, 0, NULL , NULL }"
1379  /* old  "{ 0.0, 0.0, 0, {NULL * NO SOURCES *}, {0.0 * NO MEMBERS*} }" */
1380 	    );
1381   }
1382 
1383   /* Because of the special requirements of each network-type
1384    * the Unit types are slightly modified for each update-function.
1385    * so they need a special output-template */
1386   if (is_TDNN_net() ) {
1387     for(nr = 0; nr < NoOfUnits; nr++) {
1388      writeTdnnUnit(Units + nr, Units, fOutFile);
1389       if (nr < NoOfUnits -1) fprintf(fOutFile, ",\n");
1390       else                   fprintf(fOutFile, "\n");
1391     }
1392   }
1393   else if(is_CPN_net() ) {
1394     for(nr = 0; nr < NoOfUnits; nr++) {
1395       if (nr != 0) {
1396 	fprintf(fOutFile, ",\n");
1397       }
1398       writeCpnUnit(Units + nr, fOutFile);
1399     }
1400     fprintf(fOutFile, "\n");
1401   }
1402   /* Here also BPTT-units are included, because they are very similar to
1403      the other types */
1404    else {
1405     count_links = 0; /* no links yet */
1406 
1407     for(nr = 0; nr < NoOfUnits; nr++) {
1408       writeUnitNew(Units + nr, fOutFile, count_links);
1409       count_links += NoOf((Units+nr)->sources);
1410    /* old  writeUnit(Units + nr, fOutFile); */
1411       if (nr < NoOfUnits -1) fprintf(fOutFile, ",\n");
1412       else                   fprintf(fOutFile, "\n");
1413     }
1414   }
1415   fprintf(fOutFile, "\n  };\n\n");
1416 }
1417 
1418   /*****************************************************************************
1419   void writeForwardDeclarationAllUnits(pUnit Units, int NoOfUnits, FILE *fOutFile)
1420   ----------------------------------------------------------------------------
1421   writes for all Units of the Net an forward decl. array of structs to the OutputFile
1422   -> pUnits    : array of all units of the net
1423   NoOfUnits : #units in the net
1424   fOutFile  : appreciated output stream
1425   Autor     : Matthias Oberdorfer
1426   *****************************************************************************/
writeForwardDeclarationAllUnits(pUnit Units,int NoOfUnits,FILE * fOutFile)1427  void writeForwardDeclarationAllUnits(pUnit Units, int NoOfUnits, FILE *fOutFile)
1428  {
1429 
1430    fprintf(fOutFile, "  /* Forward Declaration for all unit types */\n");
1431 
1432    /* Writing declaration of the Unit-Array */
1433    /* the 0-Element is left free because the comiler was easier
1434     * to implement this way. The only exeptions are the TDNNs
1435     * because here the Units are rewritten completely */
1436    if (is_TDNN_net()) {
1437      fprintf(fOutFile,
1438  	    "  static UnitType Units[%d];\n", NoOfUnits
1439  	    );
1440    }
1441    else if (is_CPN_net() ){
1442      fflush(fOutFile);
1443      fprintf(fOutFile,
1444  	    "  static UnitType Units[%d];\n",
1445  	    NoOfUnits + 1
1446  	    );
1447      fflush(fOutFile);
1448    }
1449    else if (is_BPTT_net() ) {
1450      fprintf(fOutFile,
1451  	    "  static UnitType Units[%d];\n",
1452  	    NoOfUnits + 1
1453  	    );
1454    }
1455    else {
1456      fprintf(fOutFile,
1457  	    "  static UnitType Units[%d];\n",
1458  	    NoOfUnits + 1
1459  	    );
1460    }
1461  }
1462 
1463  /***************************************************************************
1464  int writeSource(pUnit unit, FILE *fOutFile)
1465  ----------------------------------------------------------------------------
1466  help-function for writeAllSources
1467  Autor : Matthias Oberdorfer
1468  ****************************************************************************/
writeSource(pUnit unit,FILE * fOutFile)1469  int writeSource(pUnit unit, FILE *fOutFile)
1470    {
1471      int i;
1472      /* There should be at least one element in the list */
1473      for(i = 0; i < NoOf(unit->sources); i++)
1474       {
1475        /* write the sources as pointer to the source units */
1476        fprintf(fOutFile, "Units + %d, ", element(unit->sources,i) );
1477        if(!((i+1) % 10) )
1478         fprintf(fOutFile, "\n");
1479       }
1480      return i;
1481    }
1482 
1483  /*****************************************************************************
1484    void writeAllSources(pUnit Units, int NoOfUnits, FILE *fOutFile)
1485    ----------------------------------------------------------------------------
1486    writes all Units of the Net as an array of structs to the OutputFile
1487    -> pUnits    : array of all units of the net
1488    NoOfUnits : #units in the net
1489    fOutFile  : appreciated output stream
1490    Autor     : Matthias Oberdorfer
1491    *****************************************************************************/
1492 
writeAllSources(pUnit Units,int NoOfUnits,FILE * fOutFile)1493  void writeAllSources(pUnit Units, int NoOfUnits, FILE *fOutFile)
1494  {
1495    int nr;
1496 
1497    fprintf(fOutFile, "  /* Sources definition section */\n");
1498    fprintf(fOutFile, "  static pUnit Sources[] =  {\n");
1499 
1500    for(nr = 0; nr < NoOfUnits; nr++)
1501    {
1502        if(writeSource(Units + nr, fOutFile))
1503          fprintf(fOutFile, "\n");
1504    }
1505    fprintf(fOutFile, "\n  };\n\n");
1506  }
1507 
1508  /***************************************************************************
1509  int writeWeigths(pUnit unit, FILE *fOutFile)
1510  ---------------------------------------------------------------------------
1511  help-function for writeAllWeigths
1512  Autor: Matthias Oberdorfer
1513  ****************************************************************************/
1514 
writeWeigths(pUnit unit,FILE * fOutFile)1515  int writeWeigths(pUnit unit, FILE *fOutFile)
1516    {
1517      int i;
1518    /* ANSI-C needs at least one entry in an array */
1519    for(i = 0; i < NoOf(unit->sources); i++)
1520      {
1521       fprintf(fOutFile, "%f, ", unit->weights[i]);
1522       if(!((i+1) % 10) )
1523         fprintf(fOutFile, "\n");
1524      }
1525     return i;
1526   }
1527 
1528  /*****************************************************************************
1529    void writeAllWeigths(pUnit Units, int NoOfUnits, FILE *fOutFile)
1530    ----------------------------------------------------------------------------
1531    writes all Units of the Net as an array of structs to the OutputFile
1532    -> pUnits    : array of all units of the net
1533    NoOfUnits : #units in the net
1534    fOutFile  : appreciated output stream
1535    Autor     : Matthias Oberdorfer
1536    *****************************************************************************/
1537 
writeAllWeights(pUnit Units,int NoOfUnits,FILE * fOutFile)1538  void writeAllWeights(pUnit Units, int NoOfUnits, FILE *fOutFile)
1539  {
1540    int nr;
1541 
1542    fprintf(fOutFile, "  /* Weigths definition section */\n");
1543    fprintf(fOutFile, "  static float Weights[] =  {\n");
1544 
1545    for(nr = 0; nr < NoOfUnits; nr++)
1546    {
1547       if( writeWeigths(Units + nr, fOutFile))
1548          fprintf(fOutFile, "\n");
1549    }
1550    fprintf(fOutFile, "\n  };\n\n");
1551  }
1552 
1553 /***************************************************************************
1554   int NameLayers(pLayer globalLayers, int NoOfLayers)
1555   --------------------------------------------------------------------------
1556   name the Layers of the Net
1557   -> globalLayers : all layers of the net
1558   NoOfLayers   : #layers of the net
1559   <- (func) OK      : no errors
1560   MEM_ERR : not enough memory
1561   ***************************************************************************/
NameLayers(pLayer globalLayers,int NoOfLayers)1562 int NameLayers(pLayer globalLayers, int NoOfLayers)
1563 {
1564 #define NAME_LENGTH 11
1565 
1566   int  nr;
1567   int  hcounter = 0, ocounter = 0, scounter =0;
1568   pLayer layer = NULL;
1569 
1570   for(nr = 0; nr < NoOfLayers; nr++) {
1571     layer = (globalLayers + nr);
1572     layer->name = (char *)malloc(NAME_LENGTH * sizeof(char) );
1573     if (!(layer->name)) return(MEM_ERR);
1574 
1575     switch( (globalLayers + nr)->type) {
1576     case INPUT  : sprintf(layer->name, "Input");
1577       break;
1578 
1579     case OUTPUT : sprintf(layer->name, "Output%d", ++ocounter);
1580       break;
1581 
1582     case HIDDEN : sprintf(layer->name, "Hidden%d", ++hcounter);
1583       break;
1584 
1585     default     : sprintf(layer->name, "Special%d", ++scounter);
1586     }
1587 
1588   }
1589 
1590   return(OK);
1591 }
1592 
1593 
1594 /*****************************************************************************
1595   int writeTdnnNet(pLayer globalLayers, pUnit globalUnits,
1596   int NoOfLayers, int NoOfUnits,
1597   int *order, char *OutFile)
1598   ----------------------------------------------------------------------------
1599   writes a Net wich is discribed by globalLayers and globalUnits in the File
1600   named <OutFile>.
1601   The order for updating the Layers is discribed in order and in the single
1602   Layers there is a set of unit-numbers, wich will be updated when its the turn
1603   of the layer.
1604   -> globalLayers : all Layers of the Net
1605   -> globalUnits  : all Units of the Net
1606   -> NoOfLayers   : #Layers in the Net
1607   -> NoOfUnits    : #Units in the Net
1608   -> order        : in wich order the Layers have to be updated
1609   -> OutFile      : Name of the Output-File
1610   <- (func) OK        : no errors occured
1611   MEM_ERR   : not enough memory
1612   CANT_OPEN : could not open the output-file
1613 ******************************************************************************/
writeTdnnNet(pLayer globalLayers,pUnit globalUnits,int NoOfLayers,int NoOfUnits,int * order,char * OutFile,char * ProcName)1614 int writeTdnnNet(pLayer globalLayers, pUnit globalUnits,
1615                  int NoOfLayers, int NoOfUnits,
1616                  int *order, char *OutFile, char *ProcName)
1617 {
1618   pLayer layer, source;
1619   pUnit  unit;
1620   int    nr, layerNo, unitNo, sourceNo, pos, maxSource = 0,
1621   maxFeature = 0, maxDelay = 0, maxTotalDelay = 0;
1622   FILE   *fOutFile, *fHeaderFile;
1623   pList  OutList, FunctionList;
1624   time_t   timer;
1625   char   HeaderFile[50];
1626 
1627   /* calculate time for the date in the header of the output file */
1628   time(&timer);
1629 
1630   /* Preparations for the Header-File */
1631   strcpy(HeaderFile, OutFile);
1632   HeaderFile[strlen(HeaderFile) - 1] = 'h';
1633   fHeaderFile = fopen(HeaderFile, "w");
1634   if (!fHeaderFile) return(CANT_OPEN);
1635 
1636   /* prepare Output Stream */
1637   fOutFile = fopen(OutFile, "w");
1638   if (!fOutFile) return(CANT_OPEN);
1639 
1640   /* maxSource is needed for writing the Unit-array */
1641   for(unit = globalUnits; unit < globalUnits + NoOfUnits; unit++) {
1642     maxSource  = MAX(maxSource, NoOf(unit->sources) );
1643     /* Calculating the Maximum Feature-Width is harmless for non-TDNNs */
1644     maxFeature = MAX(maxFeature, unit->FeatureWidth);
1645   }
1646 
1647   /* TDNN needs the Maximum Receptive Field */
1648   for(layer = globalLayers; layer < globalLayers + NoOfLayers; layer++) {
1649     maxDelay      = MAX(maxDelay, layer->delay);
1650     maxTotalDelay = MAX(maxTotalDelay, layer->TotalDelay);
1651   }
1652 
1653   /* Net-Output may consist of several (output) Layers     */
1654   /* so there must be an extra merge-list : OutList        */
1655   /* FunctionList will contain a set of all used functions */
1656   OutList = newList();
1657   if (!OutList) return (MEM_ERR);
1658 
1659   FunctionList = newList();
1660   if (!FunctionList) return (MEM_ERR);
1661 
1662   for(nr = 0; nr < NoOfLayers; nr ++)
1663    {
1664     layer = globalLayers + nr;
1665     if( layer->type == OUTPUT)
1666      {
1667       if (mergeList(OutList, layer->members) ) return (MEM_ERR);
1668      }
1669     else
1670     if (addList(FunctionList, layer->ActFunc) ) return(MEM_ERR);
1671    }
1672 
1673   /** find Names for the Layers **/
1674   if (NameLayers(globalLayers, NoOfLayers+1)) return(MEM_ERR);
1675 
1676 
1677   /* ------------------------------------------------------------
1678      Beginning of the output-functions
1679      ------------------------------------------------------------ */
1680 
1681   /** write Header-File **/
1682   fprintf(fHeaderFile, TdnnHeaderFileTemplate,
1683 	  HeaderFile, ctime(&timer), ProcName,
1684 	  ProcName, NoOf(globalLayers[order[0]].members),
1685 	  NoOf(OutList), globalLayers[order[0]].TotalDelay,
1686 	  ProcName);
1687   fclose(fHeaderFile);
1688 
1689   /** write the Programm Header and Act-Functions  **/
1690   fprintf(fOutFile, ProgHeader, OutFile, ctime(&timer) );
1691   for(nr = 0; nr < NoOf(FunctionList); nr ++) {
1692     fprintf(fOutFile, "%s\n", ACT_FUNCTIONS[element(FunctionList, nr)]);
1693   }
1694   /* to avoid unneeded include-files */
1695   fprintf(fOutFile, "#ifndef NULL\n");
1696   fprintf(fOutFile, "#define NULL (void *)0\n");
1697   fprintf(fOutFile, "#endif\n");
1698 
1699   /* write Procedure-Header */
1700   fprintf(fOutFile, ProcHeader, ProcName);
1701 
1702   /* if more than one net is included in the application,
1703      the types must be defined local to the procedure. So
1704      it's done generally */
1705   fprintf(fOutFile, TdnnTypeTemplate, maxTotalDelay,
1706 				      maxFeature, maxFeature, maxDelay);
1707 
1708 
1709   /* The Delays of the TDNN are organized as a ring-buffer
1710      e.g they needs a variable for the current number */
1711   for (layerNo = 0; layerNo < NoOfLayers; layerNo++) {
1712     layer = (globalLayers + layerNo);
1713 
1714     /* one variable for the current read Position */
1715     layer->readCounter = malloc( (strlen(layer->name) + 11) * sizeof (char) );
1716     if (NULL == layer->readCounter) return(MEM_ERR);
1717     sprintf(layer->readCounter, "%sReadCounter", layer->name);
1718 
1719     /* and one for the current write position */
1720     layer->writeCounter = malloc( (strlen(layer->name) + 12) * sizeof (char) );
1721     if (NULL == layer->writeCounter) return(MEM_ERR);
1722     sprintf(layer->writeCounter, "%sWriteCounter", layer->name);
1723 
1724     /* write buffer-variables and their initialisation */
1725     fprintf(fOutFile, "  static int %s = %d, %s = %d; \n",
1726 	    layer->readCounter,  layer->TotalDelay - layer->SuccDelay,
1727 	    layer->writeCounter, layer->TotalDelay - 1);
1728   }
1729   /* a counter for the pattern is also needed */
1730   fprintf(fOutFile, "  static int Pattern_counter = 0;\n");
1731 	/* a universal variable for units */
1732 	fprintf(fOutFile, "  pUnit unit;\n");
1733 
1734   /* write the Units, their weights and biases */
1735   writeAllUnits(globalUnits, NoOfUnits, fOutFile);
1736 
1737   /** write  Layers e.g. Member of the layers **/
1738   fprintf(fOutFile,
1739           "\n  /* layer definition section (names & member units) */\n");
1740   for (nr = 0; nr < NoOfLayers; nr++) {
1741     writeLayer( (globalLayers + nr), fOutFile);
1742   }
1743   /* the Output list may be treated as a layer */
1744   fprintf(fOutFile, "\n  static int Output[%d] = ", NoOf(OutList) );
1745   writeList(OutList, fOutFile);
1746   fprintf(fOutFile, ";\n\n");
1747 
1748   /** last not least the Update-Function **/
1749   layer = globalLayers + order[0];     /* first in order e.g. Input-Layer */
1750 
1751   fprintf(fOutFile, TdnnFirstTemplate);
1752   fprintf(fOutFile, TdnnInputTemplate, NoOf(layer->members) );
1753 
1754   for (nr = 1; nr < NoOfLayers; nr++) {
1755     layerNo = order[nr];	/* update Layers in the right order */
1756     layer   = globalLayers + layerNo; /* current Layer                    */
1757 
1758       unitNo = element(layer->members, 0); /* Number of the first member unit */
1759       unit = (globalUnits + unitNo);
1760       sourceNo = element(unit->sources, 0); /* Number of the first source unit */
1761       unit = searchUnit(sourceNo, globalUnits, &pos);
1762       source = unit->layer;	/* layer of the first source unit */
1763 
1764       fprintf(fOutFile, TdnnTemplate,
1765 	      NoOf(layer->members),
1766 	      layer->name,
1767 	      source->readCounter, layer->delay, source->TotalDelay,
1768 	      source->readCounter, source->readCounter, layer->delay,
1769 	      source->readCounter,
1770 	      source->readCounter, source->TotalDelay,
1771 	      source->readCounter,
1772 	      source->readCounter, layer->delay, source->TotalDelay,
1773 	      source->readCounter, source->TotalDelay,
1774 	      layer->writeCounter,  ACT_FUNC_NAMES[layer->ActFunc]);
1775   }
1776 
1777   fprintf(fOutFile, TdnnOutputTemplate, NoOf(OutList) );
1778   /* Updating the counters of the ring-buffers */
1779   for (layer = globalLayers; layer < globalLayers + NoOfLayers; layer++) {
1780     fprintf(fOutFile, "  %s = (++%s) %% %d;\n",
1781 	    layer->readCounter, layer->readCounter, layer->TotalDelay);
1782     fprintf(fOutFile, "  %s = (++%s) %% %d;\n",
1783 	    layer->writeCounter, layer->writeCounter, layer->TotalDelay);
1784   }
1785 
1786   /** the procedure should also have an end **/
1787   fprintf(fOutFile, TdnnExitTemplate, globalLayers[order[0]].TotalDelay);
1788   fprintf(fOutFile, "}\n");
1789 
1790   /** that's all folks, or in German: "Ende gut, alles gut" **/
1791 	killList(OutList);
1792 	killList(FunctionList);
1793   return(OK);
1794 }
1795 
1796 
1797 /*****************************************************************************
1798   int writeNet(pLayer globalLayers, pUnit globalUnits,
1799   int NoOfLayers, int NoOfUnits,
1800   int *order, char *OutFile)
1801   ----------------------------------------------------------------------------
1802   writes a Net wich is discribed by globalLayers and globalUnits in the File
1803   named <OutFile>.
1804   The order for updating the Layers is discribed in order and in the single
1805   Layers there is a set of unit-numbers, wich will be updated when its the turn
1806   of the layer.
1807   -> globalLayers : all Layers of the Net
1808   -> globalUnits  : all Units of the Net
1809   -> NoOfLayers   : #Layers in the Net
1810   -> NoOfUnits    : #Units in the Net
1811   -> order        : in wich order the Layers have to be updated
1812   -> OutFile      : Name of the Output-File
1813   <- (func) OK    : no errors occured
1814   MEM_ERR   : not enough memory
1815   CANT_OPEN : could not open the output-file
1816 ******************************************************************************/
writeNet(pLayer globalLayers,pUnit globalUnits,int NoOfLayers,int NoOfUnits,int * order,char * OutFile,char * ProcName)1817 int writeNet(pLayer globalLayers, pUnit globalUnits,
1818              int NoOfLayers, int NoOfUnits,
1819              int *order, char *OutFile, char *ProcName)
1820 {
1821   pLayer layer;
1822   pUnit  unit;
1823   int    nr, layerNo, maxSource = 0, maxFeature = 0;
1824   FILE   *fOutFile, *fHeaderFile;
1825   pList  OutList, FunctionList;
1826   time_t timer;
1827   char   HeaderFile[50];
1828 
1829   /* calculate time for the date in the header of the output file */
1830   time(&timer);
1831 
1832   /* Preparations for the Header-File */
1833   strcpy(HeaderFile, OutFile);
1834   HeaderFile[strlen(HeaderFile) - 1] = 'h';
1835   fHeaderFile = fopen(HeaderFile, "w");
1836   if (!fHeaderFile) return(CANT_OPEN);
1837 
1838   /* prepare Output Stream */
1839   fOutFile = fopen(OutFile, "w");
1840   if (!fOutFile) return(CANT_OPEN);
1841 
1842   /* maxSource is needed for writing the Unit-array */
1843   for(unit = globalUnits; unit < globalUnits + NoOfUnits; unit++) {
1844     maxSource  = MAX(maxSource, NoOf(unit->sources) );
1845     /* Calculating the Maximum Feature-Width is harmless for non-TDNNs */
1846     maxFeature = MAX(maxFeature, unit->FeatureWidth);
1847   }
1848 
1849   /* Net-Output may consist of several (output) Layers     */
1850   /* so there must be an extra merge-list : OutList        */
1851   /* FunctionList will contain a set of all used functions */
1852   OutList = newList();
1853   if (!OutList) return (MEM_ERR);
1854   FunctionList = newList();
1855   if (!FunctionList) return (MEM_ERR);
1856   for(nr = 0; nr < NoOfLayers; nr ++) {
1857     layer = globalLayers + nr;
1858     if( layer->type == OUTPUT) {
1859       if (mergeList(OutList, layer->members) ) return (MEM_ERR);
1860     }
1861     if (addList(FunctionList, layer->ActFunc) ) return(MEM_ERR);
1862   }
1863 
1864   /** find Names for the Layers **/
1865   if (NameLayers(globalLayers, NoOfLayers)) return(MEM_ERR);
1866 
1867 
1868   /* ------------------------------------------------------------
1869      Beginning of the output-functions
1870      ------------------------------------------------------------ */
1871 
1872   /** write Header-File **/
1873   fprintf(fHeaderFile, HeaderFileTemplate,
1874 	  HeaderFile, ctime(&timer), ProcName,
1875 	  ProcName, NoOf(globalLayers[order[0]].members),
1876 	  NoOf(OutList), ProcName);
1877   fclose(fHeaderFile);
1878 
1879   /** write the Programm Header and Act-Functions **/
1880   fprintf(fOutFile, ProgHeader, OutFile, ctime(&timer) );
1881   for(nr = 0; nr < NoOf(FunctionList); nr ++) {
1882     fprintf(fOutFile, "%s\n", ACT_FUNCTIONS[element(FunctionList, nr)]);
1883   }
1884   /* to avoid unneeded include-files */
1885   fprintf(fOutFile, "#ifndef NULL\n");
1886   fprintf(fOutFile, "#define NULL (void *)0\n");
1887   fprintf(fOutFile, "#endif\n");
1888 
1889 
1890   /* if more than one net is included in the application,
1891      the types must be defined local to the procedure
1892      so it's done generally */
1893   if (is_CPN_net() ) {
1894     fprintf(fOutFile, CpnTypeTemplate, maxSource, maxSource,
1895 			       NoOf(globalLayers[2].members));
1896   }
1897   else if (is_BPTT_net() ) {
1898     fprintf(fOutFile, BpttTypeTemplate, maxSource, maxSource);
1899   }
1900   else {
1901     fprintf(fOutFile, TypeTemplate);
1902   }
1903 
1904   /* write the Units, their weights and biases */
1905    writeForwardDeclarationAllUnits(globalUnits, NoOfUnits, fOutFile);
1906 
1907    if( ! is_CPN_net() && !is_BPTT_net())
1908     {
1909 
1910      /* write the Units, their weights and biases */
1911      writeAllSources(globalUnits, NoOfUnits, fOutFile);
1912 
1913      /* write the Units, their weights and biases */
1914      writeAllWeights(globalUnits, NoOfUnits, fOutFile);
1915     }
1916    if( !is_BPTT_net() )
1917    {
1918     /* write the Units, their weights and biases */
1919     writeAllUnits(globalUnits, NoOfUnits, fOutFile);
1920    }
1921   else
1922   {
1923     /* write the Units, their weights and biases */
1924     writeAllUnitsOld(globalUnits, NoOfUnits, fOutFile);
1925    }
1926 
1927    /* write Procedure-Header */
1928    fprintf(fOutFile, ProcHeader, ProcName);
1929 
1930   /* DLVQ needs the biggest Scalar Product */
1931   if(is_DLVQ_net() ) {
1932     fprintf(fOutFile, "  float maxSum = -1.0;\n");
1933     fprintf(fOutFile, "  pUnit unit;\n\n");  /* variable needed for update */
1934   }
1935   /* CounterPropagation needs a winner Unit */
1936   else if(is_CPN_net() ) {
1937    fprintf(fOutFile, "  float maxSum = -1.0e30;\n"); /* biggest Scalar Product        */
1938    fprintf(fOutFile, "  pUnit winner, unit;\n\n");   /* winner unit and variable unit */
1939   }
1940   else {
1941     fprintf(fOutFile, "  pUnit unit;\n\n");  /* variable needed for update */
1942   }
1943 
1944 
1945   /** write  Layers e.g. Member of the layers **/
1946   fprintf(fOutFile,
1947           "\n  /* layer definition section (names & member units) */\n");
1948   if (is_DLVQ_net() || is_CPN_net() ) {
1949     /* DLVQ and CPN don't need the output layer */
1950     for (nr = 0; nr < NoOfLayers; nr++) {
1951       if (globalLayers[nr].type != OUTPUT) {
1952 				writeLayer( (globalLayers + nr), fOutFile);
1953       }
1954     }
1955     fprintf(fOutFile, "\n");
1956   }
1957   else {     /* not (DLVQ or CPN) */
1958     for (nr = 0; nr < NoOfLayers; nr++) {
1959       writeLayer( (globalLayers + nr), fOutFile);
1960     }
1961     /* the Output list may be treated as a layer */
1962     fprintf(fOutFile, "\n  static int Output[%d] = ", NoOf(OutList) );
1963     writeList(OutList, fOutFile);
1964     fprintf(fOutFile, ";\n\n");
1965   }
1966 
1967   /* BPTT-nets may be inialised by a flag */
1968   if (is_BPTT_net() ) {
1969     fprintf(fOutFile, BpttFirstTemplate, NoOfUnits);
1970   }
1971 
1972   /** last not least the Update-Function **/
1973   layer = globalLayers + order[0];     /* first in order e.g. Input-Layer */
1974 
1975   if (is_BPTT_net() ) {
1976     fprintf(fOutFile, BpttInputTemplate, NoOf(layer->members) );
1977   }
1978   else {
1979     fprintf(fOutFile, InputTemplate, NoOf(layer->members) );
1980   }
1981 
1982   for (nr = 1; nr < NoOfLayers; nr++) {
1983     layerNo = order[nr];	/* update Layers in the right order */
1984     layer   = globalLayers + layerNo; /* current Layer                    */
1985 
1986     if (is_DLVQ_net() ) {
1987       if (layer->type == HIDDEN) {
1988 	fprintf(fOutFile, DlvqTemplate, NoOf(layer->members),
1989 		layer->name);
1990       }
1991       /* Output Layer not needed (see DlvqOutputTemplate) */
1992     }
1993     else if (is_CPN_net() ) {
1994       if (layer->type == HIDDEN) {
1995 				fprintf(fOutFile, CpnTemplate, NoOf(layer->members),
1996 								layer->name);
1997       }
1998       /* Output Layer not needed (see CpnOutputTemplate) */
1999     }
2000 		else if (is_BPTT_net() ) {
2001       fprintf(fOutFile, BpttTemplate, NoOf(layer->members),
2002               layer->name,  ACT_FUNC_NAMES[layer->ActFunc]);
2003 		}
2004     else if (layer->ActFunc >= ActRbfNumber) {
2005       fprintf(fOutFile, RbfTemplate, NoOf(layer->members),
2006               layer->name,  ACT_FUNC_NAMES[layer->ActFunc]);
2007     }
2008     else {
2009       fprintf(fOutFile, NormalTemplate, NoOf(layer->members),
2010               layer->name,  ACT_FUNC_NAMES[layer->ActFunc]);
2011     }
2012   }
2013 
2014   if (is_DLVQ_net() ) {
2015     fprintf(fOutFile, DlvqOutputTemplate);
2016   }
2017   else if (is_CPN_net() ) {
2018     fprintf(fOutFile, CpnOutputTemplate, NoOf(globalLayers[2].members));
2019   }
2020   else if (is_BPTT_net() ) {
2021     fprintf(fOutFile, BpttOutputTemplate, NoOf(OutList) );
2022     fprintf(fOutFile, BpttExitTemplate);
2023   }
2024   else {
2025     fprintf(fOutFile, OutputTemplate, NoOf(OutList) );
2026   }
2027 
2028   /** the procedure should also have an end **/
2029   fprintf(fOutFile, "  return(OK);\n");
2030   fprintf(fOutFile, "}\n");
2031 
2032   /** that's all folks, or in German: "Ende gut, alles gut" **/
2033 	killList(OutList);
2034 	killList(FunctionList);
2035   return(OK);
2036 }
2037 
2038 
2039 /*****************************************************************************
2040   void freeUnits(pUnit Units)
2041   ----------------------------------------------------------------------------
2042 	releases memory of the Unit-array
2043 	-> Units : Arrray which contains all Units of the network.
2044              The last unit must be empty (all entries 0 or NULL)
2045 *****************************************************************************/
freeUnits(pUnit Units)2046 void freeUnits(pUnit Units)
2047 {
2048 	pUnit unit = Units;
2049 
2050 	while(unit->number) {																	 /* e.g. non-empty unit */
2051 		if (unit->members) killList(unit->members);			 /* make sure, that there is */
2052 		if (unit->sources) killList(unit->sources);			 /* memory to release        */
2053 		if (unit->weights) free(unit->weights);
2054 		if (unit->name) free(unit->name);
2055 		if (unit->dest) free(unit->dest);
2056 
2057 		if(unit->FeatureWidth) {
2058 			int i;
2059 			for(i = 0; i < unit->FeatureWidth; i++) {
2060 				if(unit->TDNNsources[i]) free(unit->TDNNsources[i]);
2061 				if(unit->TDNNweights[i]) free(unit->TDNNweights[i]);
2062 			}
2063 			if(unit->TDNNsources) free(unit->TDNNsources);
2064 			if(unit->TDNNweights) free(unit->TDNNweights);
2065 		}
2066 		unit++;
2067 	}
2068 
2069 	free(Units);
2070 }
2071 
2072 
2073 /*****************************************************************************
2074   void freeLayers(pLayer Layers)
2075   ----------------------------------------------------------------------------
2076 	releases memory of the Layer-array
2077 	-> Units : Arrray which contains all Layer of the network.
2078              The last Layer must be empty (all entries 0 or NULL)
2079 *****************************************************************************/
freeLayers(pLayer Layers)2080 void freeLayers(pLayer Layers)
2081 {
2082 	pLayer layer = Layers;
2083 
2084 	while(layer->members) {														 /* e.g. non-empty layer */
2085 		if (layer->members) free(layer->members);				 /* make sure, that there is */
2086 		if (layer->sources) free(layer->sources);				 /* memory to release        */
2087 		if (layer->name) free(layer->name);
2088 		if (layer->readCounter) free(layer->readCounter);
2089 		if (layer->writeCounter) free(layer->writeCounter);
2090 
2091 		layer++;
2092 	}
2093 
2094 	free(Layers);
2095 }
2096 
2097 
2098 /*****************************************************************************
2099   int main(int argc, char **argv)
2100   ----------------------------------------------------------------------------
2101   -> arg c   : must be 2, 3, or 4 e.g. 1 to 3 commandline-parameter
2102      argv[1] : the root of the filename of the network
2103                (e.g. without ".net")
2104   <- (func)  status
2105 *****************************************************************************/
main(int argc,char ** argv)2106 int main(int argc, char **argv)
2107 {
2108   krui_err err;				     /* error code of SNNS - krui */
2109   char     *netname;			     /* internal name of the SNNS-network */
2110   char     NetFileName[200];		     /* input file */
2111   char     CFileName[200];		     /* output file */
2112   pUnit    Units, unit = NULL;		     /* all Units and unit variable */
2113   pLayer   Layers, layer;		     /* all Layers and layer variable */
2114   int      NoOfUnits, NoOfLayers;	     /* Number of units and layers */
2115   int      *order;			     /* array with the order of the sorted layers */
2116   int      nr, pos;			     /* help variables */
2117   int      error;			     /* error code */
2118   pList    HelpList;			     /* needed for exchange */
2119   char     ProcName[50];		     /* function name in the output */
2120 
2121   /* Array with the numbers of the prototype units */
2122   int      *TDNN_prot;
2123 
2124   /* check Params */
2125   if ((argc < 2) || (argc > 4)) {
2126     fprintf(stderr, "usage : %s <netfile> [<output-file> [<function-name>] ]\n",
2127 						argv[0]);
2128     return(WRONG_PARAM);
2129   }
2130   strcpy(NetFileName, argv[1]);
2131   if (argc >= 3) {               /* C-File-Name mentioned in the command-line */
2132     strcpy(CFileName, argv[2]);
2133   }
2134   else {
2135     strcpy(CFileName, argv[1]);  /* taking Netfile Name */
2136     /* if the ending is not ".net" surprising Names may occur */
2137     strcpy(CFileName + strlen(CFileName) - 3, "c\0");
2138   }
2139   if (argc ==4) {               /* Function-Name mentioned in the command-line */
2140     strcpy(ProcName, argv[3]);
2141     toAlphaNum(ProcName);       /* Function Name must not contain special chars */
2142   }
2143   else {
2144     /* define procedure-name for propagate-function */
2145     strncpy(ProcName, CFileName, strlen(CFileName) - 2);
2146     ProcName[strlen(CFileName) -2] = '\0';
2147     toAlphaNum(ProcName);       /* Function Name must not contain special chars */
2148   }
2149 
2150   /* Write a Message (what to do) on screen */
2151   printf(HeadingTemplate, NetFileName, CFileName, ProcName);
2152 
2153   printf("loading net... \n");
2154 
2155   /* load Net */
2156   err = krui_loadNet(NetFileName, &netname);
2157   if (err) {
2158     fprintf(stderr, "%s\n", krui_error(err) );
2159     return(CANT_LOAD);
2160   }
2161 
2162   error = checkLearnFunc();
2163   if (error) {
2164     checkErr(error);
2165     return(error);
2166   }
2167 
2168   NoOfUnits = krui_getNoOfUnits();
2169 
2170   Units  =  (pUnit)calloc((NoOfUnits + 1), sizeof(tUnit) );  /* because of sentinels */
2171 	if (! Units) {
2172 		checkErr(MEM_ERR);
2173 		return(MEM_ERR);
2174 	}
2175 
2176   Layers = (pLayer)calloc((NoOfUnits + 1), sizeof(tLayer) ); /* because of sentinels */
2177 	if (! Layers) {
2178 		free(Units);
2179 		checkErr(MEM_ERR);
2180 		return(MEM_ERR);
2181 	}
2182 
2183   /* TDNN_prot needs one more Element, because the enumeration
2184      of the units starts with one */
2185   TDNN_prot = (int *)malloc((NoOfUnits+1) * sizeof(int) );
2186   if (! TDNN_prot) {
2187 		free(Units);
2188 		free(Layers);
2189 		checkErr(MEM_ERR);
2190 		return(MEM_ERR);
2191 	}
2192 
2193   for (nr = 0; nr <= NoOfUnits; nr++) {
2194     Layers[nr].number  = nr;
2195   }
2196 
2197   printf("dividing net into layers ...\n");
2198 
2199   /* part Net into groups */
2200   error =  divideNet(Units, Layers, TDNN_prot);
2201 	if (error) {
2202 		checkErr(error);
2203 		FREE_ALL;
2204 		return(error);
2205 	}
2206 
2207   /* count the Non-empty Layers */
2208   for (nr = 0; Layers[nr].members != NULL; nr++);
2209   NoOfLayers = nr;
2210   order = (int *)malloc(NoOfLayers * sizeof(int) );
2211 
2212 
2213   /* count the real number of units (e.g. the prototype units in TDNN) */
2214   /* unused units have the number 0 the total Number can't exeed the   */
2215   /* Number of Units given by the SNNS-Interface-Function              */
2216   for(nr = 0; (Units[nr].number != 0) && (nr < NoOfUnits); nr++) {
2217     Units[nr].index = nr;
2218   }
2219   NoOfUnits = nr;
2220 
2221 #ifdef debug
2222   for(nr = 0; nr < NoOfLayers; printLayer(Layers + nr++) );
2223 #endif
2224 
2225   /* the TDNN_units must have a special format */
2226   if ( is_TDNN_net() ) {
2227     prepareTDNNunits(Units, TDNN_prot);
2228 
2229     /* some values are passed to the layers for TDNNs */
2230     for(layer = Layers; layer < Layers + NoOfLayers; layer++) {
2231       unit = searchUnit(element(layer->members, 0), Units, &pos);
2232       layer->delay      = unit->DelayLength;
2233       layer->TotalDelay = NoOf(unit->members);
2234       layer->SuccDelay  = 0;         /* only initalisation (see function checkOrder )*/
2235     }
2236   }
2237 
2238   /* topological sort of the layers */
2239   printf("sorting layers ...\n");
2240   error = sortNet(Layers, NoOfLayers, order);
2241   if (error) {
2242     checkErr(error);
2243     FREE_ALL;
2244     return(error);
2245   }
2246 
2247   if ( is_TDNN_net() ) {
2248     /* Update the entries in the member list of the layer */
2249     /* now the snns2c-indices are valid                   */
2250 
2251     for(layer = Layers; layer < Layers + NoOfLayers; layer++) {
2252       HelpList = newList();
2253       for(nr = 0; nr < NoOf(layer->members); nr++) {
2254 	searchUnit(element(layer->members, nr), Units, &pos);
2255 	addList(HelpList, pos);
2256       }
2257       killList(layer->members);
2258       layer->members = HelpList;
2259     }
2260   }
2261   else if( is_CPN_net() ) {
2262     /* copy the weights from hidden to output
2263        units into hidden units */
2264     error = prepareCpnUnits(Units, Layers);
2265     if (error) {
2266       checkErr(error);
2267       FREE_ALL;
2268       return(error);
2269     }
2270   }
2271 
2272   printf("writing net ...\n");
2273 
2274   /* write the net as a C-source */
2275   if (is_TDNN_net() ) {
2276     error = writeTdnnNet(Layers, Units, NoOfLayers, NoOfUnits, order, CFileName, ProcName);
2277     if (error) {
2278       checkErr(error);
2279       FREE_ALL;
2280       return(error);
2281     }
2282   }
2283   else {
2284     error = writeNet(Layers, Units, NoOfLayers, NoOfUnits, order, CFileName, ProcName);
2285     if (error) {
2286       checkErr(error);
2287       FREE_ALL;
2288       return(error);
2289     }
2290   }
2291 
2292   FREE_ALL;
2293   return(0);
2294 }
2295