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

#include <stdio.h>
#include <math.h>
#include <sys/types.h>
#include <sys/file.h>
#include <sys/types.h>
#ifdef X
#include "X/box.h"
#endif
#include "defs.h"

extern float **d_tokenp;
extern long    run;
extern long    sweeps;
extern int     sequential;
extern int     cur_token;
extern int     updatenow;
extern int     ndtokens;
extern int     continuous;
extern float   **layerp;
extern int     context;
extern int     nolearn;
extern int     errsig;
extern int     insize;
extern int     advance;
extern float **t_tokenp;
extern long     check;
extern int     array;
extern char    fileroot[128];
extern int     printout;
extern u_int   cur_type;
extern float **lp;
extern int     pat_err;
extern FILE   *errfp;
extern float   olderr;
extern int     box;
extern float  *type_index;
extern int     disphid;
extern char    **type_list;
extern int     dispout;
extern int     printhid;

/*
 * run slow; noninteractive slow loop
 */
run_slow()
{
	extern int nlayers;
	extern int *layer_descp;
	extern int numout;
	extern float etot;
	extern int numtotal;
	extern float *nodep;
	extern float global_error;
	extern int ecount;
	extern int numin;
	register int i;
	register int j;
	register float *dtp;
	register float *ttp;
	register float *np;
	int     count = 0;
	int    *ldp;
#ifdef X
	u_char  utmp;
	u_char  dot;
#endif

	dtp = *d_tokenp;
	ttp = *t_tokenp;
	for (; run < sweeps; run++) {
		/*
		 * randomly choose a token; activate network;
		 * adjust weights according to error
		 */
		if (sequential == 0) {
			cur_token = ransi();
		} else {
			cur_token++;
			updatenow = 0;
			if (cur_token == ndtokens){
				cur_token = 0;
				updatenow = 1;
			}
		}
		/*
		 * for the 1st layer substitute the data; then
		 * activate all the layers
		 */
		if (continuous == 1) {
			*layerp = dtp;
		} else
			*layerp = *(d_tokenp + cur_token);
		/*
		 * if our hidden units are to be used as
		 * context units, save them and concatenate
		 * with the real input.
		 */
		if (context > 0) {
			buildin(context);
		}
		/*
		 * activate the network
		 */
		activate_net();
		/*
		 * pass along which token so we can do correct
		 * teaching, calculate error and
		 * back-propogate; if checkpointing, save
		 * weights.  If nolearn is set we will skip
		 * the update_net, unless we need to collect
		 * the error signal, in which case we'll pass
		 * nolearn to update_net() and let it
		 * caclulate error & return before changing
		 * anything.  (Note, nolearn==0 means we DO
		 * learning!)
		 */
		if ((nolearn == 0) || (errsig == 1)) {
			if (continuous == 1)
				update_net(ttp, nolearn);
			else
				update_net(*(t_tokenp + cur_token), nolearn);
		}
		/*
		 * if continuous mode, need to advance the
		 * sliding window a little
		 */
		if (continuous == 1) {
			if (dtp < *(d_tokenp) + insize - *layer_descp) {
				ttp += advance;
				dtp += advance;
			} else {
				dtp = *d_tokenp;
				ttp = *t_tokenp;
			}
		}
		/*
		 * if checkpointing, save weights
		 */
		if (check && ((run % check) == 0L))
			if (array == 0)
				saveweights1(fileroot);
			else if (array == 1)
				saveweights2(fileroot);
		/*
		 * if verifying, print token number and output
		 * unit activations
		 */
		if (printout) {
			cur_type = *(type_index + cur_token);
			fprintf(stdout, "%s (%d):\t",
				type_list[cur_type], cur_token);
			if (array == 0) {
				int     lmax;
				float  *l;
				lp = (layerp + nlayers - 1);
				for (i = 0, lmax = *(layer_descp + nlayers - 1),
				l = *lp; i < lmax; i++, l++) {
					fprintf(stdout, "%4.4f ", *l);
				}
			} else if (array == 1) {
				for (i = numtotal - numout, np = nodep + (numtotal - numout); i < numtotal; i++, np++) {
					fprintf(stdout, "%4.4f ", *np);
				}
			}
			fprintf(stdout, "\n");
			fflush(stdout);
		}
		if (pat_err == 1)
			fprintf(errfp, "%f\n", global_error);
		else if ((errsig) && (count > ecount)) {
			count = 0;
			etot /= ecount;
			fprintf(errfp, "%f\n", etot);
			fflush(errfp);
			olderr = etot;
			etot = 0.;
		} else {
			if (errsig) {
				etot += global_error;
				count++;
			}
		}
#ifdef X
		/*
		 * if box display, darken those "types"
		 * for each hidden unit, doing this some
		 * percentange of the time equal to the unit's
		 * activation level.
		 */
		if (box && (array == 0)) {
			u_char  k;
			cur_type = *(type_index + cur_token);
			/*
			 * either display hidden units or
			 * output units
			 */
			if (disphid == 1) {
				for (i = 0, k = 0, ldp = (layer_descp + 1), lp = (layerp + 1); i < (nlayers - 2); i++, ldp++, lp++) {
					float  *l;
					l = *lp;
					for (j = 0; j < *ldp; j++, k++) {
						if (roll(*l))
							dot = 1;
						else
							dot = 0;
						box_dot(BOX_HID, k, cur_type, dot);
						l++;
					}
				}
			} 
			if (dispout == 1) {
				float  *l;
				ldp = (layer_descp + nlayers - 1);
				lp = (layerp + nlayers - 1);
				l = *lp;
				for (j = 0, k = 0; j < *ldp; j++, k++) {
					if (roll(*l))
						dot = 1;
					else
						dot = 0;
					box_dot(BOX_OUT, k,cur_type,dot);
					l++;
				}
			}
		} else if (box && (array == 1)) {
			cur_type = *(type_index + cur_token);
			if (disphid == 1) {
				for (i = numin, np = (nodep + numin); i < (numtotal - numout); i++, np++) {
					dot = roll(*np);
					utmp = (u_char) i - numin;
					box_dot(BOX_HID, utmp, cur_type, dot);
				}
			} 
			if (dispout == 1) {
				for (i = numtotal - numout, np = (nodep + numtotal - numout); i < (numtotal); i++, np++) {
					dot = roll(*np);
					utmp = (u_char) i - (numtotal - numout);
					box_dot(BOX_OUT, utmp, cur_type, dot);
				}
			}
		}
#endif
		if (printhid) {
			int     k;
			cur_type = *(type_index + cur_token);
			fprintf(stdout, "%s (%d):\t", type_list[cur_type], cur_token);
			if (array == 0) {
				for (i = 0, k = 0, ldp = (layer_descp + 1), lp = (layerp + 1); i < (nlayers - 2); i++, ldp++, lp++) {
					float  *l;
					l = *lp;
					for (j = 0; j < *ldp; j++, k++) {
						fprintf(stdout, "\t(%d)%f", k, *l);
						l++;
					}
				}
				fprintf(stdout, "\n");
			} else if (array == 1) {
				float  *np;
				for (i = numin, np = nodep + numin; i < (numtotal - numout); i++, np++) {
					fprintf(stdout, "\t(%d)%f", i - numin, *np);
				}
				fprintf(stdout, "\n");
			}
			fflush(stdout);
		}
		/*
		 * if ((run%FLUSHCNT) == 0) fflush(stdout);
		 */
	}
}
