/****************************************************************************** FILE : $Source: /projects/higgs1/SNNS/CVS/SNNS/tools/sources/linknets.c,v $ SHORTNAME : snnslinknets.c SNNS VERSION : 4.2 PURPOSE : Combination of multiple SNNS feedforward networks to one combined net AUTHOR : Michael Vogt DATE : 09.05.97 LAST UPDATE : 09.05.97 CHANGED BY : RCS VERSION : $Revision: 1.11 $ LAST CHANGE : $Date: 1998/05/25 16:01:45 $ Copyright (c) 1990-1995 SNNS Group, IPVR, Univ. Stuttgart, FRG Copyright (c) 1996-1998 SNNS Group, WSI, Univ. Tuebingen, FRG used files : glob_typ.h, kr_ui.h from kernel/sources libkernel.a from kernel/bin/ functions.h, templates.h from actual directory ******************************************************************************/ #include #include #include #include #include #ifdef HAVE_LIMITS_H #include #endif #include #include #include "glob_typ.h" #include "kr_ui.h" #include "functions.h" #include "snns2clib.h" #include "kr_typ.h" #include "kernel.h" #undef debug #define MAX_NO_OF_NETWORKS 20 #define KR_ERROR_RETURN(x) { fprintf(stderr, "%s\n", krui_error(x)); return ERR; } /* Macros for calculating the minimum or maximum of two values */ #define MAX(a, b) ( (a > b) ? (a) : (b) ) #define MIN(a, b) ( (a < b) ? (a) : (b) ) /* Status (Error) Codes : OK = 0 (NO Error), ERR = 1, ... */ typedef enum { OK=0, ERR, CANT_ADD, CANT_LOAD, MEM_ERR, WRONG_PARAM, WRONG_ACT_FUNC, CANT_OPEN, ILLEGAL_CYCLES, NO_CPN, NO_TDNN, NOT_SUPPORTED} Status; /* Recordtype for Layers */ typedef struct { int number; /* of the Layer (not used yet) */ pList members; /* Numbers of all member-units */ pList sources; /* numbers of all sources of the member-units */ int type; /* INPUT , OUTPUT ... */ int ActFunc; /* No in the ActivationFunctionList */ char *name; /* Name of the Layer */ } tLayer, *pLayer; /* Recordtype for Units */ typedef struct { int number; /* of the Unit */ pList sources; /* numbers of the source-Units */ float *weights; /* Link-Weights to the Source-Units */ int ActFunc; /* No in the ActivationFunctionList */ int type; /* INPUT , OUTPUT ... */ char *name; /* Name of the unit, given by the user */ float Bias; /* Bias of the unit */ pLayer layer; /* Pointer to the layer containing the unit */ float act; /* Initial Activation of the Unit */ char *ActFuncName; /* Name of ActivationFunction */ char *OutFuncName; /* Name of OutputFunction */ int xpos; /* unit position */ int ypos; /* unit position */ int zpos; /* unit position */ int kernel_nr; /* kernel internal unit number */ } tUnit, *pUnit; #define DEFAULT_INPUT_UNIT_INITIALIZER \ { 0, NULL, NULL, 0, INPUT, "input", 0.0, NULL, 0.0, "Act_Logistic", "Out_Identity", 0, 0, 0, 0 } #define DEFAULT_OUTPUT_UNIT_INITIALIZER \ { 0, NULL, NULL, 0, OUTPUT, "output", 0.0, NULL, 0.0, "Act_Logistic", "Out_Identity", 0, 0, 0, 0 } #define IsInputUnit(x) ((x).type == INPUT || (x).type == SPECIAL_I) #define IsOutputUnit(x) ((x).type == OUTPUT || (x).type == SPECIAL_O) #define IsSpecialIHOUnit(x) ((x).type == SPECIAL_I || (x).type == SPECIAL_H || (x).type == SPECIAL_O) typedef struct { int maxx; int maxy; int minx; int miny; int no_of_inputs; int no_of_outputs; } tNet, *pNet; static char *Act_Identity_String = "Act_IdentityPlusBias"; /* * Output-Functions for debug-informations */ void printLayer(pLayer layer) { int i; printf("\nLayer %d", layer->number); printf("\nmembers: "); for (i = 0; i < NoOf(layer->members); i++) { printf("%d ", element(layer->members, i) ); } printf("\nsources: "); for (i = 0; i < NoOf(layer->sources); i++) { printf("%d ", element(layer->sources, i) ); } printf("\n"); } void printUnit(pUnit unit) { int i; printf("\nUnit %d", unit->number); printf("\nsources: "); for (i = 0; i < NoOf(unit->sources); i++) { printf("%9d ", element(unit->sources, i) ); } printf("\nweights: "); for (i = 0; i < NoOf(unit->sources); i++) { printf("%9f ", unit->weights[i] ); } printf("\n"); } /***************************************************************************** FUNCTION : getpUnit PURPOSE : Return the array element for the unit with a given number RETURNS : NOTES : UPDATE : ******************************************************************************/ pUnit getpUnit(pUnit Units, int NoOfUnits, int number) { int i; for (i=0; i=NoOfUnits) return NULL; else return &Units[i]; } /***************************************************************************** FUNCTION : checkErr PURPOSE : writes an error message if needed and also stops program if errCode stands for a fatal error RETURNS : NOTES : UPDATE : ******************************************************************************/ void checkErr(int errCode) { switch(errCode) { case OK : ; break; case ERR : printf("unspecified Error\n"); break; case CANT_ADD : case MEM_ERR : printf("not enough memory\n"); break; case CANT_LOAD : printf("can't load file\n"); break; case WRONG_PARAM : printf("wrong parameters\n"); break; case CANT_OPEN : printf("can't open file\n"); break; case NO_CPN : printf("net is not a CounterPropagation network\n"); break; case NO_TDNN : printf("net is not a Time Delay Neural Network\n"); break; case ILLEGAL_CYCLES : printf("net contains illegal cycles\n"); break; case WRONG_ACT_FUNC : ; break; case NOT_SUPPORTED : printf("not supported network type\n"); break; default : printf("unknown error code : %d\n", errCode); } } /***************************************************************************** FUNCTION : is_BPTT_net PURPOSE : checks, if the current Net is a BPTT, BBPTT or QPTT Network by testing the learning functions. RETURNS : TRUE if net is a kind of BPTT network, FALSE otherwise NOTES : UPDATE : ******************************************************************************/ bool is_BPTT_net(void) { return ( (0 == strcmp("BPTT", krui_getLearnFunc() )) || (0 == strcmp("BBPTT", krui_getLearnFunc() )) || (0 == strcmp("QPTT", krui_getLearnFunc() )) ); } /***************************************************************************** FUNCTION : checkLearnFunc PURPOSE : checks, if the Learning Function is supported by linknets RETURNS : Error Code : OK / NOT_SUPPORTED NOTES : UPDATE : ******************************************************************************/ int checkLearnFunc(void) { static char *NotSupportedLearnFuncs[] = { "ART1", "ART2", "ARTMAP", "BackPercolation", "Hebbian", "RM_delta", "Kohonen", NULL }; char *LearnFunc = krui_getLearnFunc(); /* learning function of the network */ char **string = NotSupportedLearnFuncs; /* current function name to test */ while(*string) { if (!strcmp(*string, LearnFunc)) { /* e.g. the same function-name */ return(NOT_SUPPORTED); } string++; } return(OK); } /***************************************************************************** FUNCTION : checkActFunc PURPOSE : checks, if an activation Function with the name actName is present RETURNS : number in the function table or -1 if not present NOTES : UPDATE : ******************************************************************************/ int checkActFunc(char *actName) { int i=0; while (**(ACT_FUNC_NAMES + i) ) { if (!strcmp(ACT_FUNC_NAMES[i], actName) ) return (i); i++; } fprintf(stderr, "Can't find the function <%s>\n", actName); return(-1); } /***************************************************************************** FUNCTION : initLayer PURPOSE : initialize the given layer e.g : - initializes the two lists members and sources - insert the type and the Number of the activation-function of the given Unit in the predefined places. - inserts the sources of the given Unit into the list sources RETURNS : error code NOTES : UPDATE : ******************************************************************************/ int initLayer(pLayer layer, pUnit unit) { layer->members = newList(); /* a list for member unit */ if (!layer->members) return(MEM_ERR); layer->sources = newList(); /* a list for all predecessor */ if (!layer->sources) return(MEM_ERR); /* units of all members */ addList(layer->members, unit->number); /* prototype unit is first member */ if (copyList(layer->sources, unit->sources) ) return(MEM_ERR); layer->ActFunc = unit->ActFunc; layer->type = unit->type; unit->layer = layer; return(OK); } /***************************************************************************** FUNCTION : matchLayer PURPOSE : checks if the unit could be in the same layer as the other units which are in the layer yet RETURNS : TRUE the unit matches with the other units, FALSE otherwise NOTES : UPDATE : ******************************************************************************/ int matchLayer(pLayer layer, pUnit unit) { static int is_BPTT = 0, first_time = 1; /* a special flag is set to avoid unneeded function calls */ if (first_time) { is_BPTT = is_BPTT_net(); first_time = 0; } /* input neurons are all treated the same way */ if ( (unit->type == INPUT) && (layer->type == INPUT) ) return (TRUE); /* unit should match the attributes of the Layer */ if (unit->type != layer->type) return(FALSE); if (unit->ActFunc != layer->ActFunc) return(FALSE); /* BPTT-nets have no topological order */ if (is_BPTT) return (TRUE); /* unit must not be a member of the source units */ if (isMember(layer->sources, unit->number) ) return (FALSE); /* Neue Version von Matthias Oderdorfer */ return ( CompareSources(unit->sources, layer->sources) ); /* alte Version */ /* a member of the layer must not be a source element of the unit */ /* return( !haveIntersection(unit->sources, layer->members) ); */ } /***************************************************************************** FUNCTION : searchLayer PURPOSE : searches a layer with matches the unit (or an empty Layer) and inserts the unit in the layer. RETURNS : MEM_ERR : not enough Memory / OK: no problems NOTES : UPDATE : ******************************************************************************/ int searchLayer(pUnit unit, pLayer globalLayers) { pLayer layer; layer = globalLayers; while(TRUE) { if (layer->members == NULL) { /* empty layer found */ return(initLayer(layer, unit)); /* give possible Errors to caller */ } else if (matchLayer(layer, unit) ) { /* matching layer found */ if (addList(layer->members, unit->number)) { return(MEM_ERR); } unit->layer = layer; return(mergeList(layer->sources, unit->sources)); /* returns Status */ } layer++; } } /***************************************************************************** FUNCTION : divideNet PURPOSE : parts a net into groups and prepares the Net for sorting the layers. RETURNS : MEM_ERR : not enough Memory / OK: no problems NOTES : UPDATE : ******************************************************************************/ int divideNet(pUnit globalUnits, pLayer globalLayers, int netnumber) { int unitNo, sourceNo; /* number of the unit and source unit */ pUnit unit; /* unit and prototype unit */ FlintType dummy, weight; /* link weights */ int error; /* error code */ char *string; /* free variable */ int pos; /* free variable */ struct PosType unitpos; /* loading all Units and group them into Layers */ unitNo = krui_getFirstUnit(); unit = globalUnits; while (unitNo) { unit->number = unitNo; /* copy the entries from SNNS to the own format */ unit->act = krui_getUnitActivation(unitNo); unit->type = krui_getUnitTType(unitNo); unit->Bias = krui_getUnitBias(unitNo); unit->ActFuncName = strdup(krui_getUnitActFuncName(unitNo)); unit->OutFuncName = strdup(krui_getUnitOutFuncName(unitNo)); krui_getUnitPosition(unitNo, &unitpos); unit->xpos = unitpos.x; unit->ypos = unitpos.y; unit->zpos = unitpos.z; /* units always have a name (at least its old number) */ string = krui_getUnitName(unitNo); if (NULL == string) { unit->name = malloc(12 * sizeof(char)); if(! unit->name) { return (MEM_ERR); } sprintf(unit->name, "N%dU%d", netnumber, unit->number); } else { unit->name = malloc(MAX(1,strlen(string)+1)); if(! unit->name) { return (MEM_ERR); } strcpy(unit->name, string); } unit->ActFunc = checkActFunc(krui_getUnitActFuncName(unitNo) ); if (unit->ActFunc < 0) return(WRONG_ACT_FUNC); /* insert all Source units in the list */ unit->sources = newList(); if (!unit->sources) return (MEM_ERR); sourceNo = krui_getFirstPredUnit(&dummy); while (sourceNo) { /* only special-hidden-neurons may have links to itself */ if ( (unit->type != SPECIAL_H) && !is_BPTT_net() ) { if (unit->number == sourceNo) return(ILLEGAL_CYCLES); } if(addList(unit->sources, sourceNo)) return (MEM_ERR); sourceNo = krui_getNextPredUnit(&dummy); } /* now the weights can be written in the right order */ /* One more Element is allocated, because the array might have size 0 */ unit->weights = (float *)malloc(NoOf(unit->sources) * sizeof(float) + sizeof(float)); if (!unit->weights) return(MEM_ERR); sourceNo = krui_getFirstPredUnit(&weight); while (sourceNo) { pos = searchList(unit->sources, sourceNo); unit->weights[pos] = weight; sourceNo = krui_getNextPredUnit(&weight); } #ifdef debug printUnit(unit); #endif error = searchLayer(unit, globalLayers); if (error) return(error); unit++; unitNo = krui_getNextUnit(); } return(OK); } /***************************************************************************** FUNCTION : checkOrder PURPOSE : checks the order between layer x and layer y RETURNS : -1 : layer x before layer y 0 : indifferent 1 : layer x after layer y ILLEGAL_CYCLES : error occured (no order given) NOTES : SIDE-EFFECT : the entry SuccDelay is set up, if one layer follows immediatly another. (needed by TDNN-networks) UPDATE : ******************************************************************************/ signed char checkOrder(pLayer globalLayers, int x, int y) { /* preference of the unit type : low value means early update */ static char pref[12] = {0, 0, 2, 0, 1, 3, 3, 3, 3, 3, 3, 3}; signed char order = 0; if (pref[globalLayers[x].type] < pref[globalLayers[y].type]) { order = (signed char)-1; /* e.g. layer x before layer y */ } else if (pref[globalLayers[x].type] > pref[globalLayers[y].type]) { order = 1; /* e.g. layer x after layer y */ } /* BPTT-Networks may contain any cycles so they must not be checked */ if (is_BPTT_net() ) { return(order); } if (haveIntersection(globalLayers[x].sources, globalLayers[y].members) ) { if (order == -1) { if (SPECIAL_H != globalLayers[y].type) return (ILLEGAL_CYCLES); } else { order = 1; } } if (haveIntersection(globalLayers[x].members, globalLayers[y].sources) ) { if (order == 1) { if (SPECIAL_H != globalLayers[x].type) return (ILLEGAL_CYCLES); } else { order = (signed char)-1; } } return(order); } /***************************************************************************** FUNCTION : sortNet PURPOSE : calculates the order between the global layers an returns it in the array order. So the first number in the array is the first layer to be updated and so on. RETURNS : MEM_ERR : not enough Memory / OK: no problems NOTES : UPDATE : ******************************************************************************/ int sortNet(pLayer globalLayers, int NoOfLayers, int *order) { char **matrix; /* precedence matrix */ char *mask; /* already chosen layers */ int i, j, x, y, ord, isSource = TRUE; char precedence; /* reserve memory for all the arrays and matrices */ matrix = (char **)malloc(NoOfLayers * sizeof(char *) ); if (!matrix) return (MEM_ERR); for (i = 0; i < NoOfLayers; i++) { matrix[i] = (char *)calloc(NoOfLayers, sizeof(char) ); if (!matrix[i]) return (MEM_ERR); } mask = (char *)calloc(NoOfLayers, sizeof(char) ); if (!mask) { free(matrix); return (MEM_ERR); } /* build the precedence matrix of the Layer-Graph */ for (y = 0; y < NoOfLayers; y++) { for (x = y + 1; x < NoOfLayers; x++) { precedence = checkOrder(globalLayers, x, y); if (precedence == ILLEGAL_CYCLES) return(ILLEGAL_CYCLES); matrix[x][y] = precedence; matrix[y][x] = -precedence; } /* for x */ } /* for y */ #ifdef debug printf("\nPrecedence Matrix is:\n"); for (y = 0; y < NoOfLayers; y++) { for (x = 0; x < NoOfLayers; x++) { printf("%3d ", matrix[y][x]); } printf("\n"); } #endif /* put the Layers in the right order **/ for (ord = 0; ord < NoOfLayers; ord++) { for (i = 0; i < NoOfLayers; i++) { if (mask[i]) continue; /* Layer already chosen */ isSource = TRUE; for (j = 0; j < NoOfLayers; j++) { /* exists a layer wich must be updated before ? */ if (matrix[i][j] == 1) { isSource = FALSE; break; } } if (isSource) { order[ord] = i; /* the number of the Layer becomes ord */ mask[i] = 1; /* must not test this Layer again */ for (j = 0; j < NoOfLayers; j++) { matrix[j][i] = 0; /* clear depencies for other Layers */ } break; /* find next Layer */ } } /* for i */ if (!isSource) { return(ILLEGAL_CYCLES); } } /* for ord */ for (i = 0; i < NoOfLayers; i++) { free(matrix[i]); } free(matrix); free(mask); #ifdef debug printf("\nLayers sorted in following order :\n"); for (i = 0; i < NoOfLayers; i++) { printf(" %d", order[i]); } printf("\n"); #endif return(OK); } /***************************************************************************** FUNCTION : add_input_sources PURPOSE : RETURNS : NOTES : UPDATE : ******************************************************************************/ void add_input_sources(pUnit Units, int NoOfUnits, int sources) { int i; for (i=0; ino; j++) { Units[i].sources->values[j] += offset; } } } return new_offset; } /***************************************************************************** FUNCTION : move_networks_down PURPOSE : RETURNS : NOTES : UPDATE : ******************************************************************************/ void move_networks_down(pUnit *UnitsP, int *NoOfUnitsP, int n, int offset) { int i, j; for (i=0; i= nnew) { fprintf(stderr, "%s: internal error\n", "connect_input_units"); exit(2); } make_new_link(NewUnits[npos], OldUnits[opos], 1.0); OldUnits[opos].type = SPECIAL_H; OldUnits[opos].Bias = 0.0; OldUnits[opos].ActFuncName = Act_Identity_String; npos++; } } } /***************************************************************************** FUNCTION : connect_output_units PURPOSE : RETURNS : NOTES : UPDATE : ******************************************************************************/ void connect_output_units(pUnit NewUnits, int nnew, pUnit OldUnits, int nold) { int opos; int npos; for (opos=0; opos0) { while (!IsOutputUnit(InputUnits[inet][ipos])) { ipos++; if (ipos >= InputNoOfUnits[inet]) { ipos = 0; inet++; if (inet >= ninputs) { fprintf(stderr, "%s: internal error\n", "multi_connect_inter_unit"); exit(2); } } } while (!IsInputUnit(OutputUnits[onet][opos])) { opos++; if (opos >= OutputNoOfUnits[onet]) { opos = 0; onet++; if (onet >= noutputs) { fprintf(stderr, "%s: internal error\n", "multi_connect_inter_units"); exit(2); } } } make_new_link(InputUnits[inet][ipos], OutputUnits[onet][opos], 1.0); if (IsSpecialIHOUnit(InputUnits[inet][ipos])) InputUnits[inet][ipos].type = SPECIAL_H; else InputUnits[inet][ipos].type = HIDDEN; OutputUnits[onet][opos].type = SPECIAL_H; OutputUnits[onet][opos].Bias = 0.0; OutputUnits[onet][opos].ActFuncName = Act_Identity_String; nconnects--; } } /***************************************************************************** FUNCTION : substitute_output_units PURPOSE : RETURNS : NOTES : UPDATE : ******************************************************************************/ void substitute_output_units(pUnit Units, int n, int newtype) { int newspecialtype; switch (newtype) { case INPUT: newspecialtype = SPECIAL_I; break; case HIDDEN: newspecialtype = SPECIAL_H; break; case OUTPUT: newspecialtype = SPECIAL_O; break; default: newspecialtype = newtype; break; } while (--n>=0) { if (IsOutputUnit(Units[n])) { if (IsSpecialIHOUnit(Units[n])) Units[n].type = newspecialtype; else Units[n].type = newtype; } } } /***************************************************************************** FUNCTION : substitute_input_units PURPOSE : RETURNS : NOTES : UPDATE : ******************************************************************************/ void substitute_input_units(pUnit Units, int n, int newtype) { int newspecialtype; switch (newtype) { case INPUT: newspecialtype = SPECIAL_I; break; case HIDDEN: newspecialtype = SPECIAL_H; break; case OUTPUT: newspecialtype = SPECIAL_O; break; default: newspecialtype = newtype; break; } while (--n>=0) { if (IsInputUnit(Units[n])) { if (IsSpecialIHOUnit(Units[n])) Units[n].type = newspecialtype; else Units[n].type = newtype; } } } /***************************************************************************** FUNCTION : usage PURPOSE : RETURNS : NOTES : UPDATE : ******************************************************************************/ void usage(char *name) { fprintf(stderr, "usage : %s -innets ... [ -outnets ... ] -o [ options ]\n", name); fprintf(stderr, "options: -inunits use copies of input units\n"); fprintf(stderr, " -inconnect fully connect with input units\n"); fprintf(stderr, " -direct connect input with output one-to-one\n"); fprintf(stderr, " -outconnect fully connect to output units\n"); fprintf(stderr, "\n -inunits and -inconnect may not be used together\n"); fprintf(stderr, "\n!!!! PLEASE REFER TO THE MANUAL FOR DETAILED DESCRIPTION!!!!\n"); exit(1); } /***************************************************************************** FUNCTION : create_and_save_network PURPOSE : RETURNS : NOTES : UPDATE : ******************************************************************************/ int create_and_save_network(char *NetFileName, pUnit Units, int NoOfUnits) { int i, j; krui_err krerr; pUnit suP; struct PosType unitpos; krui_deleteNet(); for (i=0; ino; j++) { suP = getpUnit(Units, NoOfUnits, Units[i].sources->values[j]); if (!suP) return ERR; if ((krerr=krui_createLink(suP->kernel_nr, Units[i].weights[j])) != KRERR_NO_ERROR) KR_ERROR_RETURN(krerr); } } } if ((krerr=krui_saveNet(NetFileName, "snnslinknet")) != KRERR_NO_ERROR) KR_ERROR_RETURN(krerr); return OK; } /***************************************************************************** FUNCTION : load_and_analyze_network PURPOSE : RETURNS : NOTES : UPDATE : ******************************************************************************/ int load_and_analyze_network(int netnumber, char *NetFileName, pUnit *UnitsP, pLayer *LayersP, int *NoOfUnitsP, int *NoOfLayersP, int **orderP, pNet NetinfoP) { krui_err err; /* error code of SNNS - krui */ char *netname; int error; int nr; #ifdef debug printf("loading net %s \n", NetFileName); #endif /* load Net */ err = krui_loadNet(NetFileName, &netname); if (err) { fprintf(stderr, "%s\n", krui_error(err) ); return(CANT_LOAD); } error = checkLearnFunc(); if (error) { checkErr(error); return(error); } *NoOfUnitsP = krui_getNoOfUnits(); *UnitsP = (pUnit)calloc((*NoOfUnitsP + 1), sizeof(tUnit) ); /* because of sentinels */ if (! *UnitsP) { checkErr(MEM_ERR); return(MEM_ERR); } *LayersP = (pLayer)calloc((*NoOfUnitsP + 1), sizeof(tLayer) ); /* because of sentinels */ if (! *LayersP) { free(*UnitsP); checkErr(MEM_ERR); return(MEM_ERR); } for (nr = 0; nr <= *NoOfUnitsP; nr++) { (*LayersP)[nr].number = nr; } #ifdef debug printf("dividing net into layers ...\n"); #endif /* part Net into groups */ error = divideNet(*UnitsP, *LayersP, netnumber); if (error) { checkErr(error); return(error); } /* count the Non-empty Layers */ for (nr = 0; (*LayersP)[nr].members != NULL; nr++); *NoOfLayersP = nr; *orderP = (int *)malloc(*NoOfLayersP * sizeof(int) ); /* count the real number of units */ /* unused units have the number 0 the total Number can't exeed the */ /* Number of Units given by the SNNS-Interface-Function */ for(nr = 0; ((*UnitsP)[nr].number != 0) && (nr < *NoOfUnitsP); nr++) { } *NoOfUnitsP = nr; #ifdef debug for(nr = 0; nr < *NoOfLayersP; printLayer(*LayersP + nr++) ); #endif /* topological sort of the layers */ #ifdef debug printf("sorting layers ...\n"); #endif error = sortNet(*LayersP, *NoOfLayersP, *orderP); if (error) { checkErr(error); return(error); } /* determine overall network info */ NetinfoP->maxx = (*UnitsP)[0].xpos; NetinfoP->maxy = (*UnitsP)[0].ypos; NetinfoP->minx = NetinfoP->maxx; NetinfoP->miny = NetinfoP->maxy; NetinfoP->no_of_inputs = 0; NetinfoP->no_of_outputs = 0; for (nr=0; nr< *NoOfUnitsP; nr++) { NetinfoP->maxx = MAX((*UnitsP)[nr].xpos, NetinfoP->maxx); NetinfoP->maxy = MAX((*UnitsP)[nr].ypos, NetinfoP->maxy); NetinfoP->minx = MIN((*UnitsP)[nr].xpos, NetinfoP->minx); NetinfoP->miny = MIN((*UnitsP)[nr].ypos, NetinfoP->miny); if (IsInputUnit((*UnitsP)[nr])) NetinfoP->no_of_inputs++; if (IsOutputUnit((*UnitsP)[nr])) NetinfoP->no_of_outputs++; } return OK; } /***************************************************************************** FUNCTION : main PURPOSE : RETURNS : NOTES : UPDATE : ******************************************************************************/ int main(int argc, char **argv) { int ninputs = 0; char *InputNetFileNames[MAX_NO_OF_NETWORKS]; /* input files */ pUnit InputUnits[MAX_NO_OF_NETWORKS]; /* all input unit variables */ pLayer InputLayers[MAX_NO_OF_NETWORKS]; /* all input layer variables */ tNet InputNetinfo[MAX_NO_OF_NETWORKS]; pUnit NewInputUnits; int noutputs = 0; char *OutputNetFileNames[MAX_NO_OF_NETWORKS]; /* output files */ pUnit OutputUnits[MAX_NO_OF_NETWORKS]; /* all output unit variables */ pLayer OutputLayers[MAX_NO_OF_NETWORKS];/* all output layer variables */ tNet OutputNetinfo[MAX_NO_OF_NETWORKS]; pUnit NewOutputUnits; pUnit FinalUnits; int FinalNoOfUnits; int InputNoOfUnits[MAX_NO_OF_NETWORKS], InputNoOfLayers[MAX_NO_OF_NETWORKS]; int *Inputorder[MAX_NO_OF_NETWORKS]; /* array with the order of the sorted layers */ int OutputNoOfUnits[MAX_NO_OF_NETWORKS], OutputNoOfLayers[MAX_NO_OF_NETWORKS]; int *Outputorder[MAX_NO_OF_NETWORKS]; /* array with the order of the sorted layers */ char *outputnetworkfile; int inunits = 0; int inconnect = 0; int interconnect = 1; int outconnect = 0; int total_no_of_in_inputs = 0; int total_no_of_in_outputs = 0; int total_no_of_out_inputs = 0; int total_no_of_out_outputs = 0; int equal_in_input_sizes = 1; int equal_in_output_sizes = 1; int equal_out_input_sizes = 1; int equal_out_output_sizes = 1; int total_no_of_units = 0; int no_of_new_input_units = 0; int no_of_new_output_units = 0; int i, j; int offset; int posoffset; int yoffseti = 0; int yoffseto = 0; int height = 0; static tUnit default_input_unit = DEFAULT_INPUT_UNIT_INITIALIZER; static tUnit default_output_unit = DEFAULT_OUTPUT_UNIT_INITIALIZER; char unitname[20]; /* process options */ i = 0; if (++i>=argc) usage(argv[0]); if (strcmp(argv[i], "-innets")) usage(argv[0]); if (++i>=argc) usage(argv[0]); while (i= MAX_NO_OF_NETWORKS) { fprintf(stderr, "to many input networks\n"); exit(1); } i++; } if (ninputs <= 0) usage(argv[0]); if (i>=argc)usage(argv[0]); if (strcmp(argv[i], "-outnets") == 0) { if (++i>=argc) usage(argv[0]); while (i= MAX_NO_OF_NETWORKS) { fprintf(stderr, "to many output networks\n"); exit(1); } i++; } } if (strcmp(argv[i], "-o")) usage(argv[0]); if (++i>=argc) usage(argv[0]); outputnetworkfile = strdup(argv[i]); i++; while (i=argc) usage(argv[0]); inconnect = atoi(argv[i]); } else if (strcmp(argv[i], "-direct") == 0) interconnect = 0; else if (strcmp(argv[i], "-outconnect") == 0) { if (++i>=argc) usage(argv[0]); outconnect = atoi(argv[i]); } else usage(argv[0]); i++; } if (inunits && inconnect) usage(argv[0]); if (!interconnect && noutputs==0) { fprintf(stderr, "no output networks defined, option -direct ignored\n"); interconnect = 1; } for (i=0; i0) { if (InputNetinfo[i].no_of_inputs != InputNetinfo[i-1].no_of_inputs) equal_in_input_sizes = 0; if (InputNetinfo[i].no_of_outputs != InputNetinfo[i-1].no_of_outputs) equal_in_output_sizes = 0; } } for (i=0; i0) { if (OutputNetinfo[i].no_of_inputs != OutputNetinfo[i-1].no_of_inputs) equal_out_input_sizes = 0; if (OutputNetinfo[i].no_of_outputs != OutputNetinfo[i-1].no_of_outputs) equal_out_output_sizes = 0; } } /* consitency check */ if (inunits && !equal_in_input_sizes) { fprintf(stderr, "illegal use of option -inunits\n" "input networks are of different input sizes\n"); usage(argv[0]); } if (noutputs>0 && !interconnect && total_no_of_in_outputs != total_no_of_out_inputs) { fprintf(stderr, "illegal use of option -direct\n" "overall sum of input network output sizes differs from overall sum of output network input sizes\n"); usage(argv[0]); } /* determine numbers of additional units */ if (inunits) no_of_new_input_units = InputNetinfo[0].no_of_inputs; else if (inconnect) no_of_new_input_units = inconnect; if (outconnect) no_of_new_output_units = outconnect; /* reassign unit numbers */ offset = no_of_new_input_units + 1; for (i=0; i 0 ? 2 : 0, &yoffseti); if (noutputs > 0) posoffset = 1 + adjust_network_positions(OutputUnits, OutputNoOfUnits, OutputNetinfo, noutputs, posoffset, &yoffseto); height = MAX(yoffseti, yoffseto); if (noutputs > 0) { if (yoffseti < yoffseto) move_networks_down(InputUnits, InputNoOfUnits, ninputs, (yoffseto - yoffseti)/2); else move_networks_down(OutputUnits, OutputNoOfUnits, noutputs, (yoffseti - yoffseto)/2); } /* create new input and output units */ for (i=0; i 0) for (i=0; i0) { for (i=0; i0) multi_connect_inter_units(InputUnits, InputNoOfUnits, ninputs, OutputUnits, OutputNoOfUnits, noutputs, total_no_of_in_outputs); /* combine all networks to one single unit array */ FinalNoOfUnits = 0; for (i=0; i