1 /******************************************************************************
2 FILE : $Source: /projects/higgs1/SNNS/CVS/SNNS/tools/sources/linknets.c,v $
3 SHORTNAME : snnslinknets.c
4 SNNS VERSION : 4.2
5
6 PURPOSE : Combination of multiple SNNS feedforward networks to one
7 combined net
8
9 AUTHOR : Michael Vogt
10 DATE : 09.05.97
11 LAST UPDATE : 09.05.97
12
13 CHANGED BY :
14 RCS VERSION : $Revision: 1.11 $
15 LAST CHANGE : $Date: 1998/05/25 16:01:45 $
16
17 Copyright (c) 1990-1995 SNNS Group, IPVR, Univ. Stuttgart, FRG
18 Copyright (c) 1996-1998 SNNS Group, WSI, Univ. Tuebingen, FRG
19
20 used files : glob_typ.h, kr_ui.h from kernel/sources
21 libkernel.a from kernel/bin/<architecture>
22 functions.h, templates.h from actual directory
23 ******************************************************************************/
24 #include <config.h>
25
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <ctype.h>
30 #ifdef HAVE_LIMITS_H
31 #include <limits.h>
32 #endif
33 #include <time.h>
34 #include <memory.h>
35 #include "glob_typ.h"
36 #include "kr_ui.h"
37 #include "functions.h"
38 #include "snns2clib.h"
39
40 #include "kr_typ.h"
41 #include "kernel.h"
42
43 #undef debug
44
45 #define MAX_NO_OF_NETWORKS 20
46 #define KR_ERROR_RETURN(x) { fprintf(stderr, "%s\n", krui_error(x)); return ERR; }
47
48 /* Macros for calculating the minimum or maximum of two values */
49 #define MAX(a, b) ( (a > b) ? (a) : (b) )
50 #define MIN(a, b) ( (a < b) ? (a) : (b) )
51
52 /* Status (Error) Codes : OK = 0 (NO Error), ERR = 1, ... */
53 typedef enum { OK=0, ERR, CANT_ADD, CANT_LOAD, MEM_ERR,
54 WRONG_PARAM, WRONG_ACT_FUNC, CANT_OPEN,
55 ILLEGAL_CYCLES, NO_CPN, NO_TDNN, NOT_SUPPORTED} Status;
56
57 /* Recordtype for Layers */
58 typedef struct {
59 int number; /* of the Layer (not used yet) */
60 pList members; /* Numbers of all member-units */
61 pList sources; /* numbers of all sources of the member-units */
62 int type; /* INPUT , OUTPUT ... */
63 int ActFunc; /* No in the ActivationFunctionList */
64 char *name; /* Name of the Layer */
65 } tLayer, *pLayer;
66
67 /* Recordtype for Units */
68 typedef struct {
69 int number; /* of the Unit */
70 pList sources; /* numbers of the source-Units */
71 float *weights; /* Link-Weights to the Source-Units */
72 int ActFunc; /* No in the ActivationFunctionList */
73 int type; /* INPUT , OUTPUT ... */
74 char *name; /* Name of the unit, given by the user */
75 float Bias; /* Bias of the unit */
76 pLayer layer; /* Pointer to the layer containing the unit */
77 float act; /* Initial Activation of the Unit */
78 char *ActFuncName; /* Name of ActivationFunction */
79 char *OutFuncName; /* Name of OutputFunction */
80 int xpos; /* unit position */
81 int ypos; /* unit position */
82 int zpos; /* unit position */
83
84 int kernel_nr; /* kernel internal unit number */
85 } tUnit, *pUnit;
86
87 #define DEFAULT_INPUT_UNIT_INITIALIZER \
88 { 0, NULL, NULL, 0, INPUT, "input", 0.0, NULL, 0.0, "Act_Logistic", "Out_Identity", 0, 0, 0, 0 }
89
90 #define DEFAULT_OUTPUT_UNIT_INITIALIZER \
91 { 0, NULL, NULL, 0, OUTPUT, "output", 0.0, NULL, 0.0, "Act_Logistic", "Out_Identity", 0, 0, 0, 0 }
92
93 #define IsInputUnit(x) ((x).type == INPUT || (x).type == SPECIAL_I)
94 #define IsOutputUnit(x) ((x).type == OUTPUT || (x).type == SPECIAL_O)
95 #define IsSpecialIHOUnit(x) ((x).type == SPECIAL_I || (x).type == SPECIAL_H || (x).type == SPECIAL_O)
96
97 typedef struct {
98 int maxx;
99 int maxy;
100 int minx;
101 int miny;
102 int no_of_inputs;
103 int no_of_outputs;
104 } tNet, *pNet;
105
106 static char *Act_Identity_String = "Act_IdentityPlusBias";
107
108 /*
109 * Output-Functions for debug-informations
110 */
111
printLayer(pLayer layer)112 void printLayer(pLayer layer)
113 {
114 int i;
115 printf("\nLayer %d", layer->number);
116 printf("\nmembers: ");
117 for (i = 0; i < NoOf(layer->members); i++) {
118 printf("%d ", element(layer->members, i) );
119 }
120 printf("\nsources: ");
121 for (i = 0; i < NoOf(layer->sources); i++) {
122 printf("%d ", element(layer->sources, i) );
123 }
124 printf("\n");
125 }
126
127
printUnit(pUnit unit)128 void printUnit(pUnit unit)
129 {
130 int i;
131 printf("\nUnit %d", unit->number);
132 printf("\nsources: ");
133 for (i = 0; i < NoOf(unit->sources); i++) {
134 printf("%9d ", element(unit->sources, i) );
135 }
136 printf("\nweights: ");
137 for (i = 0; i < NoOf(unit->sources); i++) {
138 printf("%9f ", unit->weights[i] );
139 }
140 printf("\n");
141 }
142
143
144 /*****************************************************************************
145 FUNCTION : getpUnit
146
147 PURPOSE : Return the array element for the unit with a given number
148 RETURNS :
149 NOTES :
150
151 UPDATE :
152 ******************************************************************************/
getpUnit(pUnit Units,int NoOfUnits,int number)153 pUnit getpUnit(pUnit Units, int NoOfUnits, int number)
154 {
155 int i;
156
157 for (i=0; i<NoOfUnits && Units[i].number != number; i++)
158 ;
159
160 if (i>=NoOfUnits)
161 return NULL;
162 else
163 return &Units[i];
164 }
165
166
167 /*****************************************************************************
168 FUNCTION : checkErr
169
170 PURPOSE : writes an error message if needed and also stops program if
171 errCode stands for a fatal error
172 RETURNS :
173 NOTES :
174
175 UPDATE :
176 ******************************************************************************/
checkErr(int errCode)177 void checkErr(int errCode)
178 {
179 switch(errCode)
180 {
181 case OK : ;
182 break;
183 case ERR : printf("unspecified Error\n");
184 break;
185 case CANT_ADD :
186 case MEM_ERR : printf("not enough memory\n");
187 break;
188 case CANT_LOAD : printf("can't load file\n");
189 break;
190 case WRONG_PARAM : printf("wrong parameters\n");
191 break;
192 case CANT_OPEN : printf("can't open file\n");
193 break;
194 case NO_CPN : printf("net is not a CounterPropagation network\n");
195 break;
196 case NO_TDNN : printf("net is not a Time Delay Neural Network\n");
197 break;
198 case ILLEGAL_CYCLES : printf("net contains illegal cycles\n");
199 break;
200 case WRONG_ACT_FUNC : ;
201 break;
202 case NOT_SUPPORTED : printf("not supported network type\n");
203 break;
204 default : printf("unknown error code : %d\n", errCode);
205 }
206 }
207
208
209 /*****************************************************************************
210 FUNCTION : is_BPTT_net
211
212 PURPOSE : checks, if the current Net is a BPTT, BBPTT or QPTT Network by
213 testing the learning functions.
214 RETURNS : TRUE if net is a kind of BPTT network, FALSE otherwise
215 NOTES :
216
217 UPDATE :
218 ******************************************************************************/
is_BPTT_net(void)219 bool is_BPTT_net(void)
220 {
221 return ( (0 == strcmp("BPTT", krui_getLearnFunc() ))
222 || (0 == strcmp("BBPTT", krui_getLearnFunc() ))
223 || (0 == strcmp("QPTT", krui_getLearnFunc() )) );
224 }
225
226
227 /*****************************************************************************
228 FUNCTION : checkLearnFunc
229
230 PURPOSE : checks, if the Learning Function is supported by linknets
231 RETURNS : Error Code : OK / NOT_SUPPORTED
232 NOTES :
233
234 UPDATE :
235 ******************************************************************************/
checkLearnFunc(void)236 int checkLearnFunc(void)
237 {
238 static char *NotSupportedLearnFuncs[] = {
239 "ART1", "ART2", "ARTMAP", "BackPercolation", "Hebbian", "RM_delta",
240 "Kohonen", NULL
241 };
242
243 char *LearnFunc = krui_getLearnFunc(); /* learning function of the network */
244 char **string = NotSupportedLearnFuncs; /* current function name to test */
245
246 while(*string) {
247 if (!strcmp(*string, LearnFunc)) { /* e.g. the same function-name */
248 return(NOT_SUPPORTED);
249 }
250 string++;
251 }
252
253 return(OK);
254 }
255
256
257 /*****************************************************************************
258 FUNCTION : checkActFunc
259
260 PURPOSE : checks, if an activation Function with the name actName is present
261 RETURNS : number in the function table or -1 if not present
262 NOTES :
263
264 UPDATE :
265 ******************************************************************************/
checkActFunc(char * actName)266 int checkActFunc(char *actName)
267 {
268 int i=0;
269
270 while (**(ACT_FUNC_NAMES + i) ) {
271 if (!strcmp(ACT_FUNC_NAMES[i], actName) ) return (i);
272 i++;
273 }
274 fprintf(stderr, "Can't find the function <%s>\n", actName);
275 return(-1);
276 }
277
278
279 /*****************************************************************************
280 FUNCTION : initLayer
281
282 PURPOSE : initialize the given layer e.g :
283 - initializes the two lists members and sources
284 - insert the type and the Number of the activation-function of the
285 given Unit in the predefined places.
286 - inserts the sources of the given Unit into the list sources
287
288 RETURNS : error code
289 NOTES :
290
291 UPDATE :
292 ******************************************************************************/
initLayer(pLayer layer,pUnit unit)293 int initLayer(pLayer layer, pUnit unit)
294 {
295 layer->members = newList(); /* a list for member unit */
296 if (!layer->members) return(MEM_ERR);
297
298 layer->sources = newList(); /* a list for all predecessor */
299 if (!layer->sources) return(MEM_ERR); /* units of all members */
300
301 addList(layer->members, unit->number); /* prototype unit is first member */
302 if (copyList(layer->sources, unit->sources) ) return(MEM_ERR);
303
304 layer->ActFunc = unit->ActFunc;
305 layer->type = unit->type;
306
307 unit->layer = layer;
308
309 return(OK);
310 }
311
312
313 /*****************************************************************************
314 FUNCTION : matchLayer
315
316 PURPOSE : checks if the unit could be in the same layer as the other units
317 which are in the layer yet
318 RETURNS : TRUE the unit matches with the other units, FALSE otherwise
319 NOTES :
320
321 UPDATE :
322 ******************************************************************************/
matchLayer(pLayer layer,pUnit unit)323 int matchLayer(pLayer layer, pUnit unit)
324 {
325 static int is_BPTT = 0, first_time = 1;
326
327 /* a special flag is set to avoid unneeded function calls */
328 if (first_time) {
329 is_BPTT = is_BPTT_net();
330 first_time = 0;
331 }
332
333 /* input neurons are all treated the same way */
334 if ( (unit->type == INPUT) && (layer->type == INPUT) ) return (TRUE);
335
336 /* unit should match the attributes of the Layer */
337 if (unit->type != layer->type) return(FALSE);
338 if (unit->ActFunc != layer->ActFunc) return(FALSE);
339
340 /* BPTT-nets have no topological order */
341 if (is_BPTT) return (TRUE);
342
343 /* unit must not be a member of the source units */
344 if (isMember(layer->sources, unit->number) ) return (FALSE);
345
346 /* Neue Version von Matthias Oderdorfer */
347 return ( CompareSources(unit->sources, layer->sources) );
348
349 /* alte Version */
350 /* a member of the layer must not be a source element of the unit */
351 /* return( !haveIntersection(unit->sources, layer->members) ); */
352 }
353
354
355 /*****************************************************************************
356 FUNCTION : searchLayer
357
358 PURPOSE : searches a layer with matches the unit (or an empty Layer) and
359 inserts the unit in the layer.
360 RETURNS : MEM_ERR : not enough Memory / OK: no problems
361 NOTES :
362
363 UPDATE :
364 ******************************************************************************/
searchLayer(pUnit unit,pLayer globalLayers)365 int searchLayer(pUnit unit, pLayer globalLayers)
366 {
367 pLayer layer;
368
369 layer = globalLayers;
370 while(TRUE) {
371 if (layer->members == NULL) { /* empty layer found */
372 return(initLayer(layer, unit)); /* give possible Errors to caller */
373 }
374 else if (matchLayer(layer, unit) ) { /* matching layer found */
375 if (addList(layer->members, unit->number)) {
376 return(MEM_ERR);
377 }
378 unit->layer = layer;
379 return(mergeList(layer->sources, unit->sources)); /* returns Status */
380 }
381 layer++;
382 }
383 }
384
385
386 /*****************************************************************************
387 FUNCTION : divideNet
388
389 PURPOSE : parts a net into groups and prepares the Net for sorting the
390 layers.
391 RETURNS : MEM_ERR : not enough Memory / OK: no problems
392 NOTES :
393
394 UPDATE :
395 ******************************************************************************/
divideNet(pUnit globalUnits,pLayer globalLayers,int netnumber)396 int divideNet(pUnit globalUnits, pLayer globalLayers, int netnumber)
397 {
398 int unitNo, sourceNo; /* number of the unit and source unit */
399 pUnit unit; /* unit and prototype unit */
400 FlintType dummy, weight; /* link weights */
401 int error; /* error code */
402 char *string; /* free variable */
403 int pos; /* free variable */
404 struct PosType unitpos;
405
406
407 /* loading all Units and group them into Layers */
408 unitNo = krui_getFirstUnit();
409 unit = globalUnits;
410
411 while (unitNo) {
412 unit->number = unitNo;
413
414 /* copy the entries from SNNS to the own format */
415 unit->act = krui_getUnitActivation(unitNo);
416 unit->type = krui_getUnitTType(unitNo);
417 unit->Bias = krui_getUnitBias(unitNo);
418
419 unit->ActFuncName = strdup(krui_getUnitActFuncName(unitNo));
420 unit->OutFuncName = strdup(krui_getUnitOutFuncName(unitNo));
421 krui_getUnitPosition(unitNo, &unitpos);
422 unit->xpos = unitpos.x;
423 unit->ypos = unitpos.y;
424 unit->zpos = unitpos.z;
425
426 /* units always have a name (at least its old number) */
427 string = krui_getUnitName(unitNo);
428 if (NULL == string) {
429 unit->name = malloc(12 * sizeof(char));
430 if(! unit->name) {
431 return (MEM_ERR);
432 }
433 sprintf(unit->name, "N%dU%d", netnumber, unit->number);
434 }
435 else {
436 unit->name = malloc(MAX(1,strlen(string)+1));
437 if(! unit->name) {
438 return (MEM_ERR);
439 }
440 strcpy(unit->name, string);
441 }
442
443 unit->ActFunc = checkActFunc(krui_getUnitActFuncName(unitNo) );
444 if (unit->ActFunc < 0) return(WRONG_ACT_FUNC);
445
446 /* insert all Source units in the list */
447 unit->sources = newList();
448 if (!unit->sources) return (MEM_ERR);
449 sourceNo = krui_getFirstPredUnit(&dummy);
450 while (sourceNo) {
451 /* only special-hidden-neurons may have links to itself */
452 if ( (unit->type != SPECIAL_H) && !is_BPTT_net() ) {
453 if (unit->number == sourceNo) return(ILLEGAL_CYCLES);
454 }
455 if(addList(unit->sources, sourceNo)) return (MEM_ERR);
456 sourceNo = krui_getNextPredUnit(&dummy);
457 }
458 /* now the weights can be written in the right order */
459 /* One more Element is allocated, because the array might have size 0 */
460 unit->weights = (float *)malloc(NoOf(unit->sources) *
461 sizeof(float) + sizeof(float));
462 if (!unit->weights) return(MEM_ERR);
463 sourceNo = krui_getFirstPredUnit(&weight);
464 while (sourceNo) {
465 pos = searchList(unit->sources, sourceNo);
466 unit->weights[pos] = weight;
467 sourceNo = krui_getNextPredUnit(&weight);
468 }
469 #ifdef debug
470 printUnit(unit);
471 #endif
472 error = searchLayer(unit, globalLayers);
473 if (error) return(error);
474
475 unit++;
476 unitNo = krui_getNextUnit();
477 }
478
479 return(OK);
480 }
481
482
483 /*****************************************************************************
484 FUNCTION : checkOrder
485
486 PURPOSE : checks the order between layer x and layer y
487 RETURNS : -1 : layer x before layer y
488 0 : indifferent
489 1 : layer x after layer y
490 ILLEGAL_CYCLES : error occured (no order given)
491
492 NOTES : SIDE-EFFECT : the entry SuccDelay is set up, if one layer
493 follows immediatly another. (needed by TDNN-networks)
494
495
496 UPDATE :
497 ******************************************************************************/
checkOrder(pLayer globalLayers,int x,int y)498 signed char checkOrder(pLayer globalLayers, int x, int y)
499 {
500 /* preference of the unit type : low value means early update */
501 static char pref[12] = {0, 0, 2, 0, 1, 3, 3, 3, 3, 3, 3, 3};
502
503 signed char order = 0;
504
505 if (pref[globalLayers[x].type] < pref[globalLayers[y].type]) {
506 order = (signed char)-1; /* e.g. layer x before layer y */
507 }
508 else if (pref[globalLayers[x].type] > pref[globalLayers[y].type]) {
509 order = 1; /* e.g. layer x after layer y */
510 }
511
512 /* BPTT-Networks may contain any cycles so they must not be checked */
513 if (is_BPTT_net() ) {
514 return(order);
515 }
516
517 if (haveIntersection(globalLayers[x].sources, globalLayers[y].members) ) {
518 if (order == -1) {
519 if (SPECIAL_H != globalLayers[y].type) return (ILLEGAL_CYCLES);
520 }
521 else {
522 order = 1;
523 }
524 }
525 if (haveIntersection(globalLayers[x].members, globalLayers[y].sources) ) {
526 if (order == 1) {
527 if (SPECIAL_H != globalLayers[x].type) return (ILLEGAL_CYCLES);
528 }
529 else {
530 order = (signed char)-1;
531 }
532 }
533
534 return(order);
535 }
536
537
538 /*****************************************************************************
539 FUNCTION : sortNet
540
541 PURPOSE : calculates the order between the global layers an returns it in
542 the array order. So the first number in the array is the first
543 layer to be updated and so on.
544 RETURNS : MEM_ERR : not enough Memory / OK: no problems
545 NOTES :
546
547 UPDATE :
548 ******************************************************************************/
sortNet(pLayer globalLayers,int NoOfLayers,int * order)549 int sortNet(pLayer globalLayers, int NoOfLayers, int *order)
550 {
551 char **matrix; /* precedence matrix */
552 char *mask; /* already chosen layers */
553 int i, j, x, y, ord, isSource = TRUE;
554 char precedence;
555
556 /* reserve memory for all the arrays and matrices */
557 matrix = (char **)malloc(NoOfLayers * sizeof(char *) );
558 if (!matrix) return (MEM_ERR);
559
560 for (i = 0; i < NoOfLayers; i++) {
561 matrix[i] = (char *)calloc(NoOfLayers, sizeof(char) );
562 if (!matrix[i]) return (MEM_ERR);
563 }
564
565 mask = (char *)calloc(NoOfLayers, sizeof(char) );
566 if (!mask) {
567 free(matrix);
568 return (MEM_ERR);
569 }
570
571 /* build the precedence matrix of the Layer-Graph */
572 for (y = 0; y < NoOfLayers; y++) {
573 for (x = y + 1; x < NoOfLayers; x++) {
574 precedence = checkOrder(globalLayers, x, y);
575 if (precedence == ILLEGAL_CYCLES) return(ILLEGAL_CYCLES);
576
577 matrix[x][y] = precedence;
578 matrix[y][x] = -precedence;
579
580 } /* for x */
581
582 } /* for y */
583
584 #ifdef debug
585 printf("\nPrecedence Matrix is:\n");
586 for (y = 0; y < NoOfLayers; y++) {
587 for (x = 0; x < NoOfLayers; x++) {
588 printf("%3d ", matrix[y][x]);
589 }
590 printf("\n");
591 }
592 #endif
593
594 /* put the Layers in the right order **/
595 for (ord = 0; ord < NoOfLayers; ord++) {
596
597 for (i = 0; i < NoOfLayers; i++) {
598 if (mask[i]) continue; /* Layer already chosen */
599
600 isSource = TRUE;
601 for (j = 0; j < NoOfLayers; j++) {
602 /* exists a layer wich must be updated before ? */
603 if (matrix[i][j] == 1) {
604 isSource = FALSE;
605 break;
606 }
607 }
608
609 if (isSource) {
610 order[ord] = i; /* the number of the Layer becomes ord */
611 mask[i] = 1; /* must not test this Layer again */
612
613 for (j = 0; j < NoOfLayers; j++) {
614 matrix[j][i] = 0; /* clear depencies for other Layers */
615 }
616
617 break; /* find next Layer */
618 }
619
620 } /* for i */
621
622 if (!isSource) {
623 return(ILLEGAL_CYCLES);
624 }
625
626 } /* for ord */
627
628 for (i = 0; i < NoOfLayers; i++) {
629 free(matrix[i]);
630 }
631 free(matrix);
632 free(mask);
633
634 #ifdef debug
635 printf("\nLayers sorted in following order :\n");
636 for (i = 0; i < NoOfLayers; i++) {
637 printf(" %d", order[i]);
638 }
639 printf("\n");
640 #endif
641
642 return(OK);
643 }
644
645
646 /*****************************************************************************
647 FUNCTION : add_input_sources
648
649 PURPOSE :
650 RETURNS :
651 NOTES :
652
653 UPDATE :
654 ******************************************************************************/
add_input_sources(pUnit Units,int NoOfUnits,int sources)655 void add_input_sources(pUnit Units, int NoOfUnits, int sources)
656 {
657 int i;
658
659 for (i=0; i<NoOfUnits; i++)
660 {
661 if (IsInputUnit(Units[i]))
662 {
663 Units[i].sources = newList();
664 Units[i].weights = (float *) malloc(sources * sizeof(float));
665 }
666 }
667 }
668
669
670 /*****************************************************************************
671 FUNCTION : adjust_unit_numbers
672
673 PURPOSE :
674 RETURNS :
675 NOTES :
676
677 UPDATE :
678 ******************************************************************************/
adjust_unit_numbers(pUnit Units,int NoOfUnits,int offset)679 int adjust_unit_numbers(pUnit Units, int NoOfUnits, int offset)
680 {
681 int new_offset = offset;
682 int i, j;
683
684 for (i=0; i<NoOfUnits; i++)
685 {
686 Units[i].number += offset;
687 new_offset = MAX(new_offset, Units[i].number);
688 if (Units[i].sources)
689 {
690 for (j=0; j<Units[i].sources->no; j++)
691 {
692 Units[i].sources->values[j] += offset;
693 }
694 }
695 }
696
697 return new_offset;
698 }
699
700
701 /*****************************************************************************
702 FUNCTION : move_networks_down
703
704 PURPOSE :
705 RETURNS :
706 NOTES :
707
708 UPDATE :
709 ******************************************************************************/
move_networks_down(pUnit * UnitsP,int * NoOfUnitsP,int n,int offset)710 void move_networks_down(pUnit *UnitsP, int *NoOfUnitsP, int n, int offset)
711 {
712 int i, j;
713
714 for (i=0; i<n; i++)
715 {
716 for (j=0; j<NoOfUnitsP[i]; j++)
717 UnitsP[i][j].ypos += offset;
718 }
719 }
720
721
722 /*****************************************************************************
723 FUNCTION : adjust_network_positions
724
725 PURPOSE :
726 RETURNS :
727 NOTES :
728
729 UPDATE :
730 ******************************************************************************/
adjust_network_positions(pUnit * UnitsP,int * NoOfUnitsP,pNet NetinfoP,int n,int offset,int * height)731 int adjust_network_positions(pUnit *UnitsP, int *NoOfUnitsP, pNet NetinfoP,
732 int n, int offset, int *height)
733 {
734 int maxwidth = 0;
735 int i;
736 int j;
737 int yoffset=0;
738
739 for (i=0; i<n; i++)
740 {
741 for (j=0; j<NoOfUnitsP[i]; j++)
742 {
743 UnitsP[i][j].xpos += offset - NetinfoP[i].minx;
744 UnitsP[i][j].ypos += yoffset - NetinfoP[i].miny;
745 }
746 yoffset += 2 + NetinfoP[i].maxy - NetinfoP[i].miny;
747 }
748
749 for (i=0; i<n; i++)
750 maxwidth = MAX(maxwidth, 1 + NetinfoP[i].maxx - NetinfoP[i].minx);
751
752 *height = yoffset-1;
753 return maxwidth + offset;
754 }
755
756
757 /*****************************************************************************
758 FUNCTION : make_new_link
759
760 PURPOSE :
761 RETURNS :
762 NOTES :
763
764 UPDATE :
765 ******************************************************************************/
make_new_link(tUnit from,tUnit to,float weight)766 void make_new_link(tUnit from, tUnit to, float weight)
767 {
768 addList(to.sources, from.number);
769 to.weights[searchList(to.sources, from.number)] = weight;
770 }
771
772
773 /*****************************************************************************
774 FUNCTION : connect_input_units
775
776 PURPOSE :
777 RETURNS :
778 NOTES :
779
780 UPDATE :
781 ******************************************************************************/
connect_input_units(pUnit NewUnits,int nnew,pUnit OldUnits,int nold,int full)782 void connect_input_units(pUnit NewUnits, int nnew,
783 pUnit OldUnits, int nold, int full)
784 {
785 int opos;
786 int npos=0;
787
788 for (opos=0; opos<nold; opos++)
789 if (IsInputUnit(OldUnits[opos]))
790 {
791 if (full)
792 {
793 for (npos=0; npos<nnew; npos++)
794 make_new_link(NewUnits[npos], OldUnits[opos], 0.0);
795 OldUnits[opos].type = HIDDEN;
796 }
797 else
798 {
799 if (npos >= nnew)
800 {
801 fprintf(stderr, "%s: internal error\n",
802 "connect_input_units");
803 exit(2);
804 }
805 make_new_link(NewUnits[npos], OldUnits[opos], 1.0);
806 OldUnits[opos].type = SPECIAL_H;
807 OldUnits[opos].Bias = 0.0;
808 OldUnits[opos].ActFuncName = Act_Identity_String;
809 npos++;
810 }
811 }
812 }
813
814
815 /*****************************************************************************
816 FUNCTION : connect_output_units
817
818 PURPOSE :
819 RETURNS :
820 NOTES :
821
822 UPDATE :
823 ******************************************************************************/
connect_output_units(pUnit NewUnits,int nnew,pUnit OldUnits,int nold)824 void connect_output_units(pUnit NewUnits, int nnew, pUnit OldUnits, int nold)
825 {
826 int opos;
827 int npos;
828
829 for (opos=0; opos<nold; opos++)
830 if (IsOutputUnit(OldUnits[opos]))
831 {
832 for (npos=0; npos<nnew; npos++)
833 make_new_link(OldUnits[opos], NewUnits[npos], 0.0);
834 if (IsSpecialIHOUnit(OldUnits[opos]))
835 OldUnits[opos].type = SPECIAL_H;
836 else
837 OldUnits[opos].type = HIDDEN;
838 }
839 }
840
841
842 /*****************************************************************************
843 FUNCTION : connect_inter_units
844
845 PURPOSE :
846 RETURNS :
847 NOTES :
848
849 UPDATE :
850 ******************************************************************************/
connect_inter_units(pUnit OldOutputUnits,int nout,pUnit OldInputUnits,int nin)851 void connect_inter_units(pUnit OldOutputUnits, int nout,
852 pUnit OldInputUnits, int nin)
853 {
854 int opos;
855 int npos;
856
857 for (opos=0; opos<nout; opos++)
858 if (IsOutputUnit(OldOutputUnits[opos]))
859 for (npos=0; npos<nin; npos++)
860 if (IsInputUnit(OldInputUnits[npos]))
861 make_new_link(OldOutputUnits[opos],
862 OldInputUnits[npos], 0.0);
863 }
864
865
866 /*****************************************************************************
867 FUNCTION : multi_connect_inter_units
868
869 PURPOSE :
870 RETURNS :
871 NOTES :
872
873 UPDATE :
874 ******************************************************************************/
multi_connect_inter_units(pUnit * InputUnits,int * InputNoOfUnits,int ninputs,pUnit * OutputUnits,int * OutputNoOfUnits,int noutputs,int nconnects)875 void multi_connect_inter_units(pUnit *InputUnits, int *InputNoOfUnits,
876 int ninputs,
877 pUnit *OutputUnits, int *OutputNoOfUnits,
878 int noutputs, int nconnects)
879 {
880 int inet=0;
881 int ipos=0;
882 int onet=0;
883 int opos=0;
884
885 while (nconnects>0)
886 {
887 while (!IsOutputUnit(InputUnits[inet][ipos]))
888 {
889 ipos++;
890 if (ipos >= InputNoOfUnits[inet])
891 {
892 ipos = 0;
893 inet++;
894 if (inet >= ninputs)
895 {
896 fprintf(stderr, "%s: internal error\n",
897 "multi_connect_inter_unit");
898 exit(2);
899 }
900 }
901 }
902 while (!IsInputUnit(OutputUnits[onet][opos]))
903 {
904 opos++;
905 if (opos >= OutputNoOfUnits[onet])
906 {
907 opos = 0;
908 onet++;
909 if (onet >= noutputs)
910 {
911 fprintf(stderr, "%s: internal error\n",
912 "multi_connect_inter_units");
913 exit(2);
914 }
915 }
916 }
917 make_new_link(InputUnits[inet][ipos],
918 OutputUnits[onet][opos],
919 1.0);
920
921 if (IsSpecialIHOUnit(InputUnits[inet][ipos]))
922 InputUnits[inet][ipos].type = SPECIAL_H;
923 else
924 InputUnits[inet][ipos].type = HIDDEN;
925
926 OutputUnits[onet][opos].type = SPECIAL_H;
927 OutputUnits[onet][opos].Bias = 0.0;
928 OutputUnits[onet][opos].ActFuncName = Act_Identity_String;
929 nconnects--;
930 }
931 }
932
933
934 /*****************************************************************************
935 FUNCTION : substitute_output_units
936
937 PURPOSE :
938 RETURNS :
939 NOTES :
940
941 UPDATE :
942 ******************************************************************************/
substitute_output_units(pUnit Units,int n,int newtype)943 void substitute_output_units(pUnit Units, int n, int newtype)
944 {
945 int newspecialtype;
946
947 switch (newtype)
948 {
949 case INPUT:
950 newspecialtype = SPECIAL_I;
951 break;
952 case HIDDEN:
953 newspecialtype = SPECIAL_H;
954 break;
955 case OUTPUT:
956 newspecialtype = SPECIAL_O;
957 break;
958 default:
959 newspecialtype = newtype;
960 break;
961 }
962
963 while (--n>=0)
964 {
965 if (IsOutputUnit(Units[n]))
966 {
967 if (IsSpecialIHOUnit(Units[n]))
968 Units[n].type = newspecialtype;
969 else
970 Units[n].type = newtype;
971 }
972 }
973 }
974
975
976 /*****************************************************************************
977 FUNCTION : substitute_input_units
978
979 PURPOSE :
980 RETURNS :
981 NOTES :
982
983 UPDATE :
984 ******************************************************************************/
substitute_input_units(pUnit Units,int n,int newtype)985 void substitute_input_units(pUnit Units, int n, int newtype)
986 {
987 int newspecialtype;
988
989 switch (newtype)
990 {
991 case INPUT:
992 newspecialtype = SPECIAL_I;
993 break;
994 case HIDDEN:
995 newspecialtype = SPECIAL_H;
996 break;
997 case OUTPUT:
998 newspecialtype = SPECIAL_O;
999 break;
1000 default:
1001 newspecialtype = newtype;
1002 break;
1003 }
1004
1005 while (--n>=0)
1006 {
1007 if (IsInputUnit(Units[n]))
1008 {
1009 if (IsSpecialIHOUnit(Units[n]))
1010 Units[n].type = newspecialtype;
1011 else
1012 Units[n].type = newtype;
1013 }
1014 }
1015 }
1016
1017
1018 /*****************************************************************************
1019 FUNCTION : usage
1020
1021 PURPOSE :
1022 RETURNS :
1023 NOTES :
1024
1025 UPDATE :
1026 ******************************************************************************/
usage(char * name)1027 void usage(char *name)
1028 {
1029 fprintf(stderr, "usage : %s -innets <netfile> ... [ -outnets <netfile> ... ] -o <output network file> [ options ]\n",
1030 name);
1031 fprintf(stderr, "options: -inunits use copies of input units\n");
1032 fprintf(stderr, " -inconnect <n> fully connect with <n> input units\n");
1033 fprintf(stderr, " -direct connect input with output one-to-one\n");
1034 fprintf(stderr, " -outconnect <n> fully connect to <n> output units\n");
1035 fprintf(stderr, "\n -inunits and -inconnect may not be used together\n");
1036 fprintf(stderr, "\n!!!! PLEASE REFER TO THE MANUAL FOR DETAILED DESCRIPTION!!!!\n");
1037 exit(1);
1038 }
1039
1040
1041 /*****************************************************************************
1042 FUNCTION : create_and_save_network
1043
1044 PURPOSE :
1045 RETURNS :
1046 NOTES :
1047
1048 UPDATE :
1049 ******************************************************************************/
create_and_save_network(char * NetFileName,pUnit Units,int NoOfUnits)1050 int create_and_save_network(char *NetFileName, pUnit Units, int NoOfUnits)
1051 {
1052 int i, j;
1053 krui_err krerr;
1054 pUnit suP;
1055
1056 struct PosType unitpos;
1057
1058 krui_deleteNet();
1059 for (i=0; i<NoOfUnits; i++)
1060 {
1061 Units[i].kernel_nr = krui_createUnit(Units[i].name,
1062 Units[i].OutFuncName,
1063 Units[i].ActFuncName,
1064 Units[i].act,
1065 Units[i].Bias);
1066 if (Units[i].kernel_nr <= 0)
1067 KR_ERROR_RETURN(Units[i].kernel_nr);
1068 if ((krerr=krui_setUnitTType(Units[i].kernel_nr, Units[i].type)) != KRERR_NO_ERROR)
1069 KR_ERROR_RETURN(krerr);
1070 unitpos.x = Units[i].xpos;
1071 unitpos.y = Units[i].ypos;
1072 unitpos.z = Units[i].zpos;
1073 krui_setUnitPosition(Units[i].kernel_nr, &unitpos);
1074 }
1075
1076 for (i=0; i<NoOfUnits; i++)
1077 {
1078 if (Units[i].sources)
1079 {
1080 if ((krerr=krui_setCurrentUnit(Units[i].kernel_nr)) != KRERR_NO_ERROR)
1081 KR_ERROR_RETURN(krerr);
1082 for (j=0; j<Units[i].sources->no; j++)
1083 {
1084 suP = getpUnit(Units, NoOfUnits, Units[i].sources->values[j]);
1085 if (!suP)
1086 return ERR;
1087 if ((krerr=krui_createLink(suP->kernel_nr,
1088 Units[i].weights[j])) != KRERR_NO_ERROR)
1089 KR_ERROR_RETURN(krerr);
1090 }
1091 }
1092 }
1093
1094 if ((krerr=krui_saveNet(NetFileName, "snnslinknet")) != KRERR_NO_ERROR)
1095 KR_ERROR_RETURN(krerr);
1096
1097 return OK;
1098 }
1099
1100
1101 /*****************************************************************************
1102 FUNCTION : load_and_analyze_network
1103
1104 PURPOSE :
1105 RETURNS :
1106 NOTES :
1107
1108 UPDATE :
1109 ******************************************************************************/
load_and_analyze_network(int netnumber,char * NetFileName,pUnit * UnitsP,pLayer * LayersP,int * NoOfUnitsP,int * NoOfLayersP,int ** orderP,pNet NetinfoP)1110 int load_and_analyze_network(int netnumber, char *NetFileName, pUnit *UnitsP,
1111 pLayer *LayersP, int *NoOfUnitsP, int *NoOfLayersP,
1112 int **orderP, pNet NetinfoP)
1113 {
1114 krui_err err; /* error code of SNNS - krui */
1115
1116 char *netname;
1117 int error;
1118 int nr;
1119
1120 #ifdef debug
1121 printf("loading net %s \n", NetFileName);
1122 #endif
1123
1124 /* load Net */
1125 err = krui_loadNet(NetFileName, &netname);
1126 if (err) {
1127 fprintf(stderr, "%s\n", krui_error(err) );
1128 return(CANT_LOAD);
1129 }
1130
1131 error = checkLearnFunc();
1132 if (error) {
1133 checkErr(error);
1134 return(error);
1135 }
1136
1137 *NoOfUnitsP = krui_getNoOfUnits();
1138
1139 *UnitsP = (pUnit)calloc((*NoOfUnitsP + 1), sizeof(tUnit) ); /* because of sentinels */
1140 if (! *UnitsP) {
1141 checkErr(MEM_ERR);
1142 return(MEM_ERR);
1143 }
1144
1145 *LayersP = (pLayer)calloc((*NoOfUnitsP + 1), sizeof(tLayer) ); /* because of sentinels */
1146 if (! *LayersP) {
1147 free(*UnitsP);
1148 checkErr(MEM_ERR);
1149 return(MEM_ERR);
1150 }
1151
1152 for (nr = 0; nr <= *NoOfUnitsP; nr++) {
1153 (*LayersP)[nr].number = nr;
1154 }
1155
1156 #ifdef debug
1157 printf("dividing net into layers ...\n");
1158 #endif
1159
1160 /* part Net into groups */
1161 error = divideNet(*UnitsP, *LayersP, netnumber);
1162 if (error) {
1163 checkErr(error);
1164 return(error);
1165 }
1166
1167 /* count the Non-empty Layers */
1168 for (nr = 0; (*LayersP)[nr].members != NULL; nr++);
1169 *NoOfLayersP = nr;
1170 *orderP = (int *)malloc(*NoOfLayersP * sizeof(int) );
1171
1172
1173 /* count the real number of units */
1174 /* unused units have the number 0 the total Number can't exeed the */
1175 /* Number of Units given by the SNNS-Interface-Function */
1176 for(nr = 0; ((*UnitsP)[nr].number != 0) && (nr < *NoOfUnitsP); nr++) {
1177 }
1178 *NoOfUnitsP = nr;
1179
1180 #ifdef debug
1181 for(nr = 0; nr < *NoOfLayersP; printLayer(*LayersP + nr++) );
1182 #endif
1183
1184 /* topological sort of the layers */
1185 #ifdef debug
1186 printf("sorting layers ...\n");
1187 #endif
1188
1189 error = sortNet(*LayersP, *NoOfLayersP, *orderP);
1190 if (error) {
1191 checkErr(error);
1192 return(error);
1193 }
1194
1195 /* determine overall network info */
1196 NetinfoP->maxx = (*UnitsP)[0].xpos;
1197 NetinfoP->maxy = (*UnitsP)[0].ypos;
1198 NetinfoP->minx = NetinfoP->maxx;
1199 NetinfoP->miny = NetinfoP->maxy;
1200 NetinfoP->no_of_inputs = 0;
1201 NetinfoP->no_of_outputs = 0;
1202 for (nr=0; nr< *NoOfUnitsP; nr++)
1203 {
1204 NetinfoP->maxx = MAX((*UnitsP)[nr].xpos, NetinfoP->maxx);
1205 NetinfoP->maxy = MAX((*UnitsP)[nr].ypos, NetinfoP->maxy);
1206 NetinfoP->minx = MIN((*UnitsP)[nr].xpos, NetinfoP->minx);
1207 NetinfoP->miny = MIN((*UnitsP)[nr].ypos, NetinfoP->miny);
1208 if (IsInputUnit((*UnitsP)[nr]))
1209 NetinfoP->no_of_inputs++;
1210 if (IsOutputUnit((*UnitsP)[nr]))
1211 NetinfoP->no_of_outputs++;
1212 }
1213 return OK;
1214 }
1215
1216
1217 /*****************************************************************************
1218 FUNCTION : main
1219
1220 PURPOSE :
1221 RETURNS :
1222 NOTES :
1223
1224 UPDATE :
1225 ******************************************************************************/
main(int argc,char ** argv)1226 int main(int argc, char **argv)
1227 {
1228 int ninputs = 0;
1229 char *InputNetFileNames[MAX_NO_OF_NETWORKS]; /* input files */
1230 pUnit InputUnits[MAX_NO_OF_NETWORKS]; /* all input unit variables */
1231 pLayer InputLayers[MAX_NO_OF_NETWORKS]; /* all input layer variables */
1232 tNet InputNetinfo[MAX_NO_OF_NETWORKS];
1233
1234 pUnit NewInputUnits;
1235
1236 int noutputs = 0;
1237 char *OutputNetFileNames[MAX_NO_OF_NETWORKS]; /* output files */
1238 pUnit OutputUnits[MAX_NO_OF_NETWORKS]; /* all output unit variables */
1239 pLayer OutputLayers[MAX_NO_OF_NETWORKS];/* all output layer variables */
1240 tNet OutputNetinfo[MAX_NO_OF_NETWORKS];
1241
1242 pUnit NewOutputUnits;
1243
1244 pUnit FinalUnits;
1245 int FinalNoOfUnits;
1246
1247 int InputNoOfUnits[MAX_NO_OF_NETWORKS],
1248 InputNoOfLayers[MAX_NO_OF_NETWORKS];
1249 int *Inputorder[MAX_NO_OF_NETWORKS]; /* array with the order of
1250 the sorted layers */
1251
1252 int OutputNoOfUnits[MAX_NO_OF_NETWORKS],
1253 OutputNoOfLayers[MAX_NO_OF_NETWORKS];
1254 int *Outputorder[MAX_NO_OF_NETWORKS]; /* array with the order of
1255 the sorted layers */
1256
1257 char *outputnetworkfile;
1258 int inunits = 0;
1259 int inconnect = 0;
1260 int interconnect = 1;
1261 int outconnect = 0;
1262
1263 int total_no_of_in_inputs = 0;
1264 int total_no_of_in_outputs = 0;
1265 int total_no_of_out_inputs = 0;
1266 int total_no_of_out_outputs = 0;
1267
1268 int equal_in_input_sizes = 1;
1269 int equal_in_output_sizes = 1;
1270 int equal_out_input_sizes = 1;
1271 int equal_out_output_sizes = 1;
1272
1273 int total_no_of_units = 0;
1274 int no_of_new_input_units = 0;
1275 int no_of_new_output_units = 0;
1276
1277 int i, j;
1278 int offset;
1279 int posoffset;
1280 int yoffseti = 0;
1281 int yoffseto = 0;
1282 int height = 0;
1283
1284 static tUnit default_input_unit = DEFAULT_INPUT_UNIT_INITIALIZER;
1285 static tUnit default_output_unit = DEFAULT_OUTPUT_UNIT_INITIALIZER;
1286
1287 char unitname[20];
1288
1289 /* process options */
1290
1291 i = 0;
1292 if (++i>=argc) usage(argv[0]);
1293
1294 if (strcmp(argv[i], "-innets"))
1295 usage(argv[0]);
1296
1297 if (++i>=argc) usage(argv[0]);
1298 while (i<argc && argv[i][0] != '-')
1299 {
1300 InputNetFileNames[ninputs] = strdup(argv[i]);
1301 ninputs++;
1302 if (ninputs >= MAX_NO_OF_NETWORKS)
1303 {
1304 fprintf(stderr, "to many input networks\n");
1305 exit(1);
1306 }
1307 i++;
1308 }
1309 if (ninputs <= 0)
1310 usage(argv[0]);
1311
1312 if (i>=argc)usage(argv[0]);
1313
1314 if (strcmp(argv[i], "-outnets") == 0)
1315 {
1316 if (++i>=argc) usage(argv[0]);
1317 while (i<argc && argv[i][0] != '-')
1318 {
1319 OutputNetFileNames[noutputs] = strdup(argv[i]);
1320 noutputs++;
1321 if (noutputs >= MAX_NO_OF_NETWORKS)
1322 {
1323 fprintf(stderr, "to many output networks\n");
1324 exit(1);
1325 }
1326 i++;
1327 }
1328 }
1329
1330 if (strcmp(argv[i], "-o"))
1331 usage(argv[0]);
1332
1333 if (++i>=argc) usage(argv[0]);
1334
1335
1336 outputnetworkfile = strdup(argv[i]);
1337 i++;
1338
1339
1340 while (i<argc)
1341 {
1342 if (strcmp(argv[i], "-inunits") == 0)
1343 inunits = 1;
1344 else if (strcmp(argv[i], "-inconnect") == 0)
1345 {
1346 if (++i>=argc) usage(argv[0]);
1347 inconnect = atoi(argv[i]);
1348 }
1349 else if (strcmp(argv[i], "-direct") == 0)
1350 interconnect = 0;
1351 else if (strcmp(argv[i], "-outconnect") == 0)
1352 {
1353 if (++i>=argc) usage(argv[0]);
1354 outconnect = atoi(argv[i]);
1355 }
1356 else
1357 usage(argv[0]);
1358 i++;
1359 }
1360 if (inunits && inconnect)
1361 usage(argv[0]);
1362
1363 if (!interconnect && noutputs==0)
1364 {
1365 fprintf(stderr, "no output networks defined, option -direct ignored\n");
1366 interconnect = 1;
1367 }
1368
1369 for (i=0; i<ninputs; i++)
1370 {
1371 if (load_and_analyze_network(i+1, InputNetFileNames[i],
1372 &InputUnits[i], &InputLayers[i],
1373 &InputNoOfUnits[i], &InputNoOfLayers[i],
1374 &Inputorder[i], &InputNetinfo[i]) != OK)
1375 exit(1);
1376
1377 total_no_of_in_inputs += InputNetinfo[i].no_of_inputs;
1378 total_no_of_in_outputs += InputNetinfo[i].no_of_outputs;
1379 total_no_of_units += InputNoOfUnits[i];
1380
1381 if (i>0)
1382 {
1383 if (InputNetinfo[i].no_of_inputs !=
1384 InputNetinfo[i-1].no_of_inputs)
1385 equal_in_input_sizes = 0;
1386 if (InputNetinfo[i].no_of_outputs !=
1387 InputNetinfo[i-1].no_of_outputs)
1388 equal_in_output_sizes = 0;
1389 }
1390 }
1391
1392 for (i=0; i<noutputs; i++)
1393 {
1394 if (load_and_analyze_network(i+1+ninputs, OutputNetFileNames[i],
1395 &OutputUnits[i], &OutputLayers[i],
1396 &OutputNoOfUnits[i], &OutputNoOfLayers[i],
1397 &Outputorder[i], &OutputNetinfo[i]) != OK)
1398 exit(1);
1399
1400 total_no_of_out_inputs += OutputNetinfo[i].no_of_inputs;
1401 total_no_of_out_outputs += OutputNetinfo[i].no_of_outputs;
1402 total_no_of_units += OutputNoOfUnits[i];
1403
1404 if (i>0)
1405 {
1406 if (OutputNetinfo[i].no_of_inputs !=
1407 OutputNetinfo[i-1].no_of_inputs)
1408 equal_out_input_sizes = 0;
1409 if (OutputNetinfo[i].no_of_outputs !=
1410 OutputNetinfo[i-1].no_of_outputs)
1411 equal_out_output_sizes = 0;
1412 }
1413
1414 }
1415
1416 /* consitency check */
1417 if (inunits && !equal_in_input_sizes)
1418 {
1419 fprintf(stderr, "illegal use of option -inunits\n"
1420 "input networks are of different input sizes\n");
1421 usage(argv[0]);
1422 }
1423 if (noutputs>0 && !interconnect &&
1424 total_no_of_in_outputs != total_no_of_out_inputs)
1425 {
1426 fprintf(stderr, "illegal use of option -direct\n"
1427 "overall sum of input network output sizes differs from overall sum of output network input sizes\n");
1428 usage(argv[0]);
1429 }
1430
1431 /* determine numbers of additional units */
1432 if (inunits)
1433 no_of_new_input_units = InputNetinfo[0].no_of_inputs;
1434 else if (inconnect)
1435 no_of_new_input_units = inconnect;
1436
1437 if (outconnect)
1438 no_of_new_output_units = outconnect;
1439
1440 /* reassign unit numbers */
1441 offset = no_of_new_input_units + 1;
1442 for (i=0; i<ninputs; i++)
1443 offset = adjust_unit_numbers(InputUnits[i],InputNoOfUnits[i],offset)+1;
1444 for (i=0; i<noutputs; i++)
1445 offset = adjust_unit_numbers(OutputUnits[i],OutputNoOfUnits[i],offset)+1;
1446
1447 /* create new units */
1448 NewInputUnits = (pUnit) calloc(no_of_new_input_units + 1, sizeof(tUnit) );
1449 NewOutputUnits = (pUnit) calloc(no_of_new_output_units + 1, sizeof(tUnit));
1450 FinalUnits = (pUnit) calloc(offset + no_of_new_output_units + 1,
1451 sizeof(tUnit) );
1452
1453 if (! NewOutputUnits || ! NewInputUnits || ! FinalUnits) {
1454 checkErr(MEM_ERR);
1455 exit(1);
1456 }
1457
1458 /* move unit positions for graphical output */
1459 posoffset = 1 + adjust_network_positions(InputUnits, InputNoOfUnits,
1460 InputNetinfo, ninputs,
1461 no_of_new_input_units > 0 ?
1462 2 : 0, &yoffseti);
1463 if (noutputs > 0)
1464 posoffset = 1 + adjust_network_positions(OutputUnits, OutputNoOfUnits,
1465 OutputNetinfo, noutputs,
1466 posoffset, &yoffseto);
1467
1468 height = MAX(yoffseti, yoffseto);
1469 if (noutputs > 0)
1470 {
1471 if (yoffseti < yoffseto)
1472 move_networks_down(InputUnits, InputNoOfUnits, ninputs,
1473 (yoffseto - yoffseti)/2);
1474 else
1475 move_networks_down(OutputUnits, OutputNoOfUnits, noutputs,
1476 (yoffseti - yoffseto)/2);
1477 }
1478
1479 /* create new input and output units */
1480 for (i=0; i<no_of_new_input_units; i++)
1481 {
1482 NewInputUnits[i] = default_input_unit;
1483 NewInputUnits[i].sources = newList();
1484 NewInputUnits[i].number = i;
1485 NewInputUnits[i].xpos = 0;
1486 NewInputUnits[i].ypos = i + (no_of_new_input_units < height ?
1487 (height-no_of_new_input_units)/2 : 0);
1488 sprintf(unitname, "in%d", i+1);
1489 NewInputUnits[i].name = strdup(unitname);
1490 }
1491 for (i=0; i<no_of_new_output_units; i++)
1492 {
1493 NewOutputUnits[i] = default_output_unit;
1494 NewOutputUnits[i].sources = newList();
1495 NewOutputUnits[i].weights =
1496 (float *) malloc(MAX(total_no_of_out_outputs,
1497 total_no_of_in_outputs) * sizeof(float));
1498 NewOutputUnits[i].number = i+offset;
1499 NewOutputUnits[i].xpos = posoffset;
1500 NewOutputUnits[i].ypos = i + (no_of_new_output_units < height ?
1501 (height-no_of_new_output_units)/2 : 0);
1502 sprintf(unitname, "out%d", i+1);
1503 NewOutputUnits[i].name = strdup(unitname);
1504 }
1505
1506 /* modify former input units to receive input from other source units */
1507 for (i=0; i<ninputs; i++)
1508 add_input_sources(InputUnits[i], InputNoOfUnits[i],
1509 no_of_new_input_units);
1510 for (i=0; i<noutputs; i++)
1511 add_input_sources(OutputUnits[i], OutputNoOfUnits[i],
1512 total_no_of_in_outputs);
1513
1514 /* connect new input unit structure if necessary */
1515 for (i=0; i<ninputs; i++)
1516 {
1517 if (inunits)
1518 {
1519 connect_input_units(NewInputUnits, no_of_new_input_units,
1520 InputUnits[i], InputNoOfUnits[i], 0);
1521 }
1522 else if (inconnect)
1523 {
1524 connect_input_units(NewInputUnits, no_of_new_input_units,
1525 InputUnits[i], InputNoOfUnits[i], 1);
1526 }
1527 }
1528
1529 /* connect new output unit structure if necessay */
1530 if (outconnect)
1531 {
1532 if (noutputs > 0)
1533 for (i=0; i<noutputs; i++)
1534 {
1535 connect_output_units(NewOutputUnits, no_of_new_output_units,
1536 OutputUnits[i], OutputNoOfUnits[i]);
1537 }
1538 else
1539 for (i=0; i<ninputs; i++)
1540 {
1541 connect_output_units(NewOutputUnits, no_of_new_output_units,
1542 InputUnits[i], InputNoOfUnits[i]);
1543 }
1544 }
1545
1546 /* interconnect networks */
1547 if (interconnect && noutputs>0)
1548 {
1549 for (i=0; i<ninputs; i++)
1550 for (j=0; j<noutputs; j++)
1551 connect_inter_units(InputUnits[i], InputNoOfUnits[i],
1552 OutputUnits[j], OutputNoOfUnits[j]);
1553 for (i=0; i<ninputs; i++)
1554 substitute_output_units(InputUnits[i], InputNoOfUnits[i],
1555 HIDDEN);
1556 for (i=0; i<noutputs; i++)
1557 substitute_input_units(OutputUnits[i], OutputNoOfUnits[i],
1558 HIDDEN);
1559 }
1560 else if (noutputs>0)
1561 multi_connect_inter_units(InputUnits, InputNoOfUnits, ninputs,
1562 OutputUnits, OutputNoOfUnits, noutputs,
1563 total_no_of_in_outputs);
1564
1565 /* combine all networks to one single unit array */
1566 FinalNoOfUnits = 0;
1567 for (i=0; i<no_of_new_input_units; i++)
1568 FinalUnits[FinalNoOfUnits++] = NewInputUnits[i];
1569 for (i=0; i<ninputs; i++)
1570 for (j=0; j<InputNoOfUnits[i]; j++)
1571 FinalUnits[FinalNoOfUnits++] = InputUnits[i][j];
1572 for (i=0; i<noutputs; i++)
1573 for (j=0; j<OutputNoOfUnits[i]; j++)
1574 FinalUnits[FinalNoOfUnits++] = OutputUnits[i][j];
1575 for (i=0; i<no_of_new_output_units; i++)
1576 FinalUnits[FinalNoOfUnits++] = NewOutputUnits[i];
1577
1578 #ifdef debug
1579 for (i=0; i<FinalNoOfUnits; i++)
1580 printUnit(&FinalUnits[i]);
1581 #endif
1582
1583 /* save created network */
1584 if(create_and_save_network(outputnetworkfile, FinalUnits,
1585 FinalNoOfUnits) != OK)
1586 exit(1);
1587
1588 exit(0);
1589 }
1590
1591