
/*
 * Copyright (1987) Jeff Elman.  University of California, San Diego
 * This software may be redistributed without charge; this notice
 * should be preserved.
 */

/*
 * build_network.c
 *
 * Build a network to specification. 
 * We are handed:
 *	- the number of layers, 
 *	- the number of elements in each layer, and
 * 	- the bounds for random initialization of weights
 * We do:
 *	- create layer pointers and elements
 *	- initialize elements to 0
 *	- create inter-layer weights
 *	- initialize weights to some random value
 *	- allocate space for element deltas
 */

#include <stdio.h>
#include <sys/types.h>

build_network(weight_limit)
	float	weight_limit;
{
	extern	char *malloc();
	extern	float **layerp;
	extern	float **weightp;
	extern	float **dweightp;
	extern	float **iweightp;
	extern	float **deltap;
	extern	float **biasp;
	extern	float **dbiasp;
	extern	float **ibiasp;
	extern	float *cunits;
	extern	int *layer_descp;
	extern	int nlayers;
	extern	int context;
	extern	float rans();
	extern	int num_hidden;
	extern	int numout;
	register int i;
	register int j;
	float	**wp;
	float	**lp;
	float	**dp;
	float	**bp;
	float	**dbp;
	float	*cup;
	int	*ldp;

	/* 
	 * allocate space for layer pointers
	 */
	layerp = (float **) malloc((u_int)nlayers * sizeof(float **));
	if (layerp == NULL) {
		perror("layerp malloc");
		exit(1);
	}
	/*
	 * allocate space for layers
	 */
	for (i=0, lp=layerp, ldp=layer_descp; i<nlayers; i++, lp++, ldp++) {
		/*
		 * if our input contains a context copied in from hidden
		 * units, we will allocate space for the additional units
		 * (Note that the first layer may not be used; we often
		 * just point the layerp toward where the input token is
		 * stored.). 
		 */
		*lp = (float *)malloc((u_int) *ldp * sizeof(float *));
		if (*lp == NULL) {
			perror("lp malloc");
			exit(1);
		}
	}
	/*
	 * allocate space for delta pointers
	 */
	deltap = (float **) malloc((u_int) nlayers * sizeof(float **));
	if (deltap == NULL) {
		perror("deltap malloc");
		exit(1);
	}
	/*
	 * allocate space for deltas
	 */
	for (i=0, dp=deltap, ldp=layer_descp; i<nlayers; i++, dp++, ldp++) {
		*dp = (float *)malloc((u_int) *ldp * sizeof(float *));
		if (*dp == NULL) {
			perror("dp malloc");
			exit(1);
		}
	}
	/*
	 * initialize deltas 
	 */
	for (i=0, dp=deltap, ldp=layer_descp; i<nlayers; i++, dp++, ldp++) {
		float *d;
		for (j=0, d = *dp; j < *ldp; j++, d++) {
			*d = 0.0;
		}
	}
	/*
	 * allocate space for bias pointers
	 */
	biasp = (float **) malloc((u_int) nlayers * sizeof(float **));
	if (biasp == NULL) {
		perror("biasp malloc");
		exit(1);
	}
	/*
	 * allocate space for biases
	 */
	for (i=0, bp=biasp, ldp=layer_descp; i<nlayers; i++, bp++, ldp++) {
		*bp = (float *)malloc((u_int) *ldp * sizeof(float *));
		if (*bp == NULL) {
			perror("bp malloc");
			exit(1);
		}
	}
	/*
	 * initialize biases
	 */
	for (i=0, bp=biasp, ldp=layer_descp; i<nlayers; i++, bp++, ldp++) {
		float *b;
		for (j=0, b= *bp; j < *ldp; j++, b++) {
			*b = 0.0;
		}
	}
	/*
	 * allocate space for delta bias pointers
	 */
	dbiasp = (float **) malloc((u_int) nlayers * sizeof(float **));
	if (dbiasp == NULL) {
		perror("dbiasp malloc");
		exit(1);
	}
	/*
	 * allocate space for incremental bias pointers
	 */
	ibiasp = (float **) malloc((u_int) nlayers * sizeof(float **));
	if (ibiasp == NULL) {
		perror("ibiasp malloc");
		exit(1);
	}
	/*
	 * allocate space for delta biases
	 */
	for (i=0, dbp=dbiasp, ldp=layer_descp; i<nlayers; i++, dbp++, ldp++) {
		*dbp = (float *)malloc((u_int) *ldp * sizeof(float *));
		if (*dbp == NULL) {
			perror("dbp malloc");
			exit(1);
		}
	}
	/*
	 * allocate space for incremental biases
	 */
	for (i=0, dbp=ibiasp, ldp=layer_descp; i<nlayers; i++, dbp++, ldp++) {
		*dbp = (float *)malloc((u_int) *ldp * sizeof(float *));
		if (*dbp == NULL) {
			perror("dbp malloc");
			exit(1);
		}
	}
	/*
	 * initialize delta biases
	 */
	for (i=0, dbp=dbiasp, ldp=layer_descp; i<nlayers; i++, dbp++, ldp++) {
		float *b;
		for (j=0, b= *dbp; j < *ldp; j++, b++) {
			*b = 0.0;
		}
	}
	/*
	 * initialize incremental biases
	 */
	for (i=0, dbp=ibiasp, ldp=layer_descp; i<nlayers; i++, dbp++, ldp++) {
		float *b;
		for (j=0, b= *dbp; j < *ldp; j++, b++) {
			*b = 0.0;
		}
	}
	/*
	 * allocate space for weight pointers 
	 */
	weightp = (float **) malloc((u_int) (nlayers-1) * sizeof(float **));
	if (weightp == NULL) {
		perror("weightp malloc");
		exit(1);
	}
	/*
	 * allocate space for dweight pointers 
	 */
	dweightp = (float **) malloc((u_int) (nlayers-1) * sizeof(float **));
	if (dweightp == NULL) {
		perror("dweightp malloc");
		exit(1);
	}
	/*
	 * allocate space for iweight pointers 
	 */
	iweightp = (float **) malloc((u_int) (nlayers-1) * sizeof(float **));
	if (iweightp == NULL) {
		perror("iweightp malloc");
		exit(1);
	}
	/*
	 * ...and for actual weights (each unit in a given layer connecting
	 * to each unit in layer below)
	 */
	for (i=0, wp=weightp, ldp=(layer_descp+1); i<(nlayers-1); i++,wp++) {
		int num;
		num = *(ldp + i) * *(ldp + i -1);
		*wp = (float *)malloc((u_int) num * sizeof(float *));
		if (*wp == NULL) {
			perror("wp malloc");
			exit(1);
		}
	}
	/*
	 * ...and for actual dweights (each unit in a given layer connecting
	 * to each unit in layer below)
	 */
	for (i=0, wp=dweightp, ldp=(layer_descp+1); i<(nlayers-1); i++,wp++) {
		int num;
		num = *(ldp + i) * *(ldp + i -1);
		*wp = (float *)malloc((u_int) num * sizeof(float *));
		if (*wp == NULL) {
			perror("wp malloc");
			exit(1);
		}
	}
	/*
	 * ...and for actual iweights (each unit in a given layer connecting
	 * to each unit in layer below)
	 */
	for (i=0, wp=iweightp, ldp=(layer_descp+1); i<(nlayers-1); i++,wp++) {
		int num;
		num = *(ldp + i) * *(ldp + i -1);
		*wp = (float *)malloc((u_int) num * sizeof(float *));
		if (*wp == NULL) {
			perror("wp malloc");
			exit(1);
		}
	}
	/*
	 * initialize weights randomly
	 */
	for (i=0, wp=weightp, ldp=(layer_descp+1); i<(nlayers-1); i++, wp++) {
		float *w;
		int num;
		num = *(ldp + i) * *(ldp + i - 1);
		for (j=0, w = *wp; j < num ; j++, w++) {
			*w = rans(weight_limit);
		}
	}
	/*
	 * initialize dweights to zero
	 */
	for (i=0, wp=dweightp, ldp=(layer_descp+1); i<(nlayers-1); i++, wp++) {
		float *w;
		int num;
		num = *(ldp + i) * *(ldp + i - 1);
		for (j=0, w = *wp; j < num ; j++, w++) {
			*w = 0.;
		}
	}
	/*
	 * initialize iweights to zero
	 */
	for (i=0, wp=iweightp, ldp=(layer_descp+1); i<(nlayers-1); i++, wp++) {
		float *w;
		int num;
		num = *(ldp + i) * *(ldp + i - 1);
		for (j=0, w = *wp; j < num ; j++, w++) {
			*w = 0.;
		}
	}
	/*
	 * build context units
	 */
	if (context == 1) {
		cunits = (float *) malloc((u_int) num_hidden * sizeof(float));
		if (cunits == NULL) {
			perror("cunits malloc");
			exit(1);
		}
		j = num_hidden;
	}
	if (context) {
		for (i=0, cup=cunits; i<j; i++, cup++) {
			*cup = 0.0;
		}
	}
}

destroy_network() {
	extern	float **layerp;
	extern	float **weightp;
	extern	float **dweightp;
	extern	float **iweightp;
	extern	float **deltap;
	extern	float **biasp;
	extern	float **dbiasp;
	extern	float **ibiasp;
	extern	float *nodep;
	extern	float *cunits;
	extern	float *delta_x;
	extern	float *delta_z;
	extern	int *layer_descp;
	extern	int nlayers;
	extern	float rans();
	extern	int num_hidden;
	extern	int numtotal;
	extern	int array;
	register int i;
	float	**wp;
	float	**lp;
	float	**dp;
	float	**bp;
	float	**dbp;

	 
	if (array == 0) {
	    for (i=0, dp=deltap; i<nlayers; i++, dp++) {
		    if (*dp) {
			    free((char *)*dp);
		    }
	    }
	    if (deltap) {
		    free((char *)deltap);
	    }
	    for (i=0, bp=biasp; i<nlayers; i++, bp++) {
		    if (*bp) {
			    free((char *)*bp);
		    }
	    }
	    if (biasp) {
		    free((char *)biasp);
	    }
	    for (i=0, dbp=dbiasp; i<nlayers; i++, dbp++) {
		    if (*dbp) {
			    free((char *)*dbp);
		    }
	    }
	    if (dbiasp) {
		    free((char *)dbiasp);
	    }
	    for (i=0, dbp=ibiasp; i<nlayers; i++, dbp++) {
		    if (*dbp) {
			    free((char *)*dbp);
		    }
	    }
	    if (ibiasp) {
		    free((char *)ibiasp);
	    }
	    for (i=0, wp=weightp; i<(nlayers-1); i++,wp++) {
		    if (*wp) {
			    free((char *)*wp);
		    }
	    }
	    if (weightp) {
		    free((char *)weightp);
	    }
	    for (i=0, wp=dweightp; i<(nlayers-1); i++,wp++) {
		    if (*wp) {
			    free((char *)*wp);
		    }
	    }
	    if (dweightp) {
		    free((char *)dweightp);
	    }
	    for (i=0, wp=iweightp; i<(nlayers-1); i++,wp++) {
		    if (*wp) {
			    free((char *)*wp);
		    }
	    }
	    if (iweightp) {
		    free((char *)iweightp);
	    }
	    for (i=0, lp=layerp; i<nlayers; i++, lp++) {
		    if (*lp) {
			    free((char *)*lp);
		    }
	    }
	    if (layerp)
		    free((char *)layerp);
	    layerp = weightp = dweightp = iweightp = deltap = biasp = dbiasp = ibiasp = 0;
	    if (cunits)
		    free((char *)cunits);
	} else if (array == 1) {
	    if (deltap) {
		    free((char *)deltap);
	    }
	    if (biasp) {
		    free((char *)biasp);
	    }
	    if (dbiasp) {
		    free((char *)dbiasp);
	    }
	    if (ibiasp) {
		    free((char *)ibiasp);
	    }
	    for (i=0, wp=weightp ; i<numtotal; i++,wp++) {
		    if (*wp) {
			    free((char *)*wp);
		    }
	    }
	    if (weightp) {
		    free((char *)weightp);
	    }
	    for (i=0, wp=dweightp; i<numtotal; i++,wp++) {
		    if (*wp) {
			    free((char *)*wp);
		    }
	    }
	    if (dweightp) {
		    free((char *)dweightp);
	    }
	    for (i=0, wp=iweightp; i<numtotal; i++,wp++) {
		    if (*wp) {
			    free((char *)*wp);
		    }
	    }
	    if (iweightp) {
		    free((char *)iweightp);
	    }
	    for (i=0, lp=layerp; i<nlayers; i++, lp++) {
		    if (*lp) {
			    free((char *)*lp);
		    }
	    }
	    if (layerp)
		    free((char *)layerp);
	    if (nodep)
		    free((char *)nodep);
	    if (delta_x)
		    free((char *)delta_x);
	    if (delta_z)
		    free((char *)delta_z);
	    layerp = weightp = dweightp = iweightp = deltap = biasp = dbiasp = ibiasp = 0;
	    if (cunits)
		    free((char *)cunits);

	}
}
