home *** CD-ROM | disk | FTP | other *** search
- /*
-
- This file is part of the PDP software package.
-
- Copyright 1987 by James L. McClelland and David E. Rumelhart.
-
- Please refer to licensing information in the file license.txt,
- which is in the same directory with this source file and is
- included here by reference.
- */
-
-
- /* file: cs.c
-
- Do the actual work for the cs program.
-
- First version implemented by Elliot Jaffe.
-
- Date of last revision: 8-12-87/JLM.
- */
-
- #include "general.h"
- #include "cs.h"
- #include "variable.h"
- #include "command.h"
- #include "patterns.h"
- #include "weights.h"
-
- #define MAXTIMES 20
- #define FMIN (1.0e-37)
- #define fcheck(x) (fabs(x) > FMIN ? (float) x : (float) 0.0)
-
- char *Prompt = "cs: ";
- char *Default_step_string = "cycle";
- boolean System_Defined = FALSE;
-
- boolean clamp = 0;
- boolean boltzmann = 0;
- boolean harmony = 0;
-
- float temperature,coolrate;
- float goodness;
-
- float *activation;
- float *netinput;
- float *intinput;
- float *extinput;
-
- float estr = 1.0;
- float istr = 1.0;
-
- float kappa;
-
- int epochno = 0; /* not used in cs */
- int patno = 0;
- int ncycles = 10;
- int nupdates = 100;
- int cycleno = 0;
- int updateno = 0;
- int unitno = 0;
- char cuname[40];
-
- int ntimes = 0;
-
- struct anneal_schedule {
- int time;
- float temp;
- } *anneal_schedule;
-
- int maxtimes = MAXTIMES;
-
- struct anneal_schedule *last_temp;
- struct anneal_schedule *next_temp;
- struct anneal_schedule *current_temp;
-
- define_system() {
- int i,j;
- float *tmp;
-
- activation = (float *) emalloc((unsigned)(sizeof(float) * nunits));
- (void)install_var("activation",Vfloat,(int *)activation,nunits,0,
- SETSVMENU);
- for (i = 0; i < nunits; i++)
- activation[i] = 0.0;
-
- netinput = (float *) emalloc((unsigned)(sizeof(float) * nunits));
- (void)install_var("netinput",Vfloat,(int *)netinput,nunits,0,SETSVMENU);
- for (i = 0; i < nunits; i++)
- netinput[i] = 0.0;
-
- intinput = (float *) emalloc((unsigned)(sizeof(float) * nunits));
- (void)install_var("intinput",Vfloat,(int *)intinput,nunits,0,SETSVMENU);
- for (i = 0; i < nunits; i++)
- intinput[i] = 0.0;
-
- extinput = (float *) emalloc((unsigned)(sizeof(float) * nunits));
- (void)install_var("extinput",Vfloat,(int *)extinput,nunits,0,SETSVMENU);
- for (i = 0; i < nunits; i++)
- extinput[i] = 0.0;
-
- anneal_schedule = ((struct anneal_schedule *)
- emalloc((unsigned)maxtimes*sizeof(struct anneal_schedule)));
-
- next_temp = anneal_schedule;
- last_temp = anneal_schedule;
- last_temp->time = 0;
- last_temp->temp = 0.0;
-
- constrain_weights();
-
- System_Defined = TRUE;
- reset_system();
- return(TRUE);
- }
-
-
- double logistic (i) float i; {
- double val;
- double ret_val;
- double exp ();
-
- if( temperature <= 0.0)
- return(i > 0);
- else
- val = i / temperature;
-
- if (val > 11.5129)
- return(.99999);
- else
- if (val < -11.5129)
- return(.00001);
- else
- ret_val = 1.0 / (1.0 + exp(-1.0 * val));
- if (ret_val > FMIN) return(ret_val);
- return(0.0);
- }
-
- probability(val) double val; {
- return((rnd() < val) ? 1 : 0);
- }
-
- float
- annealing ( iter) int iter; {
- /* compute the current temperature given the the last landmark, iteration
- number and the current coolrate We use a simple linear function. */
-
- double tmp;
-
- if(iter >= last_temp->time) return(last_temp->temp);
- if(iter >= next_temp->time) {
- tmp = next_temp->temp;
- current_temp = next_temp++;
- coolrate = (current_temp->temp-next_temp->temp)/
- (float)(next_temp->time - current_temp->time);
- }
- else
- tmp = current_temp->temp -
- (coolrate*(float)(iter - current_temp->time));
-
- return((tmp < FMIN ? 0.0 : tmp));
- }
-
- get_schedule() {
- int cnt;
- char *str;
- char string[40];
- struct anneal_schedule *asptr;
-
- if(!System_Defined)
- if(!define_system())
- return(BREAK);
-
- asptr = anneal_schedule;
- next_temp = anneal_schedule;
-
- restart:
- str = get_command("Setting annealing schedule, initial temperature : ");
- if( str == NULL) return(CONTINUE);
- if(sscanf(str,"%f",&(asptr->temp)) == 0) {
- if (put_error("Invalid initial temperature specification.") == BREAK) {
- return(BREAK);
- }
- goto restart;
- }
- if(asptr->temp < 0) {
- if (put_error("Temperatures must be positive.") == BREAK) {
- return(BREAK);
- }
- goto restart;
- }
- cnt = 1;
- last_temp = asptr++;
- sprintf(string,"time for first milestone: ");
- while((str = get_command(string)) != NULL) {
- if(strcmp(str,"end") == 0) return(CONTINUE);
- if (cnt >= maxtimes) {
- maxtimes += 10;
- anneal_schedule = ((struct anneal_schedule *)
- erealloc((char *)anneal_schedule,
- (unsigned)((maxtimes-10)*sizeof(struct anneal_schedule)),
- (unsigned)maxtimes*sizeof(struct anneal_schedule)));
- next_temp = anneal_schedule;
- asptr = anneal_schedule + cnt;
- last_temp = asptr;
- }
- if (sscanf(str,"%d",&asptr->time) == 0) {
- if (put_error("Non_numeric time. ") == BREAK) {
- return(BREAK);
- }
- continue;
- }
- if(asptr->time <= last_temp->time) {
- if (put_error("Times must increase.") == BREAK) {
- return(BREAK);
- }
- continue;
- }
- sprintf(string,"at time %d the temp should be: ",asptr->time);
- if((str = get_command(string)) == NULL) {
- if (put_error("Nothing set at this milestone.") == BREAK) {
- return(BREAK);
- }
- goto retry;
- }
- if(sscanf(str,"%f",&(asptr->temp)) == 0) {
- if(put_error("Non_numberic temperature.") == BREAK) {
- return(BREAK);
- }
- goto retry;
- }
- if(asptr->temp < 0) {
- if(put_error("Temperatures must be positive.") == BREAK) {
- return(BREAK);
- }
- goto retry;
- }
- last_temp = asptr++;
- cnt++;
- retry:
- sprintf(string,"time for milestone %d: ",cnt);
- }
- return(CONTINUE);
- }
-
-
- cycle() {
- int iter;
- char *str;
-
- if (!System_Defined)
- if (!define_system())
- return(BREAK);
-
-
- for (iter = 0; iter < ncycles; iter++) {
- cycleno++;
- if(boltzmann || harmony)
- temperature = annealing(cycleno);
- if (rupdate() == BREAK) return(BREAK);
- if(step_size == CYCLE) {
- get_goodness();
- cs_update_display();
- if(single_flag) {
- if (contin_test() == BREAK) return(BREAK);
- }
- }
- if (Interrupt) {
- get_goodness();
- cs_update_display();
- Interrupt_flag = 0;
- if (contin_test() == BREAK) return(BREAK);
-
- }
- }
- if (step_size == NCYCLES) {
- get_goodness();
- cs_update_display();
- }
- return(CONTINUE);
- }
-
- get_goodness() {
-
- int i,j;
- int num, sender, fs, ls; /* fs is first sender, ls is last */
- double dg;
-
- dg = 0.0;
-
- if(harmony) {
- for(i=ninputs; i < nunits; i++) {
- sender = first_weight_to[i];
- num = num_weights_to[i];
- for(j = 0; j < num && sender < ninputs; j++,sender++) {
- dg +=
- weight[i][j]*activation[i]*activation[sender];
- }
- if (activation[i]) dg -= kappa*sigma[i];
- }
- goto ret_goodness;
- }
- for(i=0; i < nunits; i++) {
- fs = first_weight_to[i];
- ls = num_weights_to[i] + fs -1;
- for(j = i+1; j < nunits; j++) {
- if ( j < fs ) continue;
- if ( j > ls ) break;
- dg += weight[i][j-fs]*activation[i]*activation[j];
- }
- dg += bias[i]*activation[i];
- }
- /* >> dont we want to let goodness be affected by istr whether or not
- clamp is 0? Boltz is always clamped, but not schema */
- if(clamp == 0) {
- dg *= istr;
- for(i=0; i < nunits; i++) {
- dg += activation[i]*extinput[i]*estr;
- }
- }
- ret_goodness:
- goodness = dg;
- return;
- }
-
- constrain_weights() {
- int *nconnections;
- int i,j,num;
- float value;
-
- if(!harmony) return;
-
- nconnections = (int *) emalloc((unsigned)(sizeof(int) * nunits));
- for (i = 0; i < nunits; i++) {
- nconnections[i] = 0;
- }
-
- for (j = ninputs; j < nunits; j++) {
- num = num_weights_to[j];
- for (i = 0; i < num; i++) {
- if (weight[j][i])
- nconnections[j]++;
- }
- }
-
- for (j = ninputs; j < nunits; j++) {
- if (!nconnections[j])
- continue;
- value = sigma[j] / (float) nconnections[j];
- num = num_weights_to[j];
- for (i = 0; i < num; i++) {
- if (weight[j][i]) {
- weight[j][i] *= value;
- }
- }
- }
- free((char *)nconnections);
- }
-
- zarrays() {
- register int i;
-
- if (!System_Defined)
- if (!define_system())
- return(BREAK);
-
- cycleno = 0;
-
- next_temp = anneal_schedule;
- if(last_temp != next_temp) {
- current_temp = next_temp++;
- coolrate =
- (current_temp->temp-next_temp->temp)/(float)next_temp->time;
- }
- temperature = annealing (cycleno);
-
- goodness = 0;
- updateno = 0;
-
- for (i = 0; i < nunits; i++) {
- intinput[i] = netinput[i] = activation[i] = 0;
- }
- if (clamp) {
- init_activations();
- }
- return(CONTINUE);
- }
-
- init_activations() {
- register int i;
- for (i = 0; i < nunits; i++) {
- if (extinput[i] == 1.0) {
- activation[i] = 1.0;
- continue;
- }
- if (extinput[i] == -1.0) {
- activation[i] == 0.0;
- continue;
- }
- }
- }
-
- rupdate() {
- register int j,wi,sender,num,*fwp,*nwp,i,n;
- char *str;
- double dt, inti,neti,acti;
-
- for (updateno = 0,n = 0; n < nupdates; n++) {
- updateno++;
- unitno = i = randint(0, nunits - 1);
- inti = 0.0;
- if (harmony) {
- neti = 0.0;
- if (i < ninputs) {
- if (extinput[i] == 0.0) {
- for (j = ninputs,fwp = &first_weight_to[ninputs],
- nwp = &num_weights_to[ninputs];
- j < nunits; j++) {
- wi = i - *fwp++;
- if ( (wi >= *nwp++) || (wi < 0) ) continue;
- neti += activation[j]*weight[j][wi];
- }
- neti = 2 * neti;
- if (probability(logistic(neti)))
- activation[i] = 1;
- else
- activation[i] = -1;
- }
- else {
- if(extinput[i] < 0.0) activation[i] = -1;
- if(extinput[i] > 0.0) activation[i] = 1;
- }
- }
- else {
- sender = first_weight_to[i];
- num = num_weights_to[i];
- for (j = 0; j < num && sender < ninputs; j++,sender++) {
- neti += activation[sender]*weight[i][j];
- }
- neti -= sigma[i]*kappa;
- activation[i] = probability(logistic(neti));
- netinput[i] = neti;
- }
- }
- else {
- if (clamp) {
- if (extinput[i] > 0.0) {
- activation[i] = 1.0;
- goto end_of_rupdate;
- }
- if (extinput[i] < 0.0) {
- activation[i] = 0.0;
- goto end_of_rupdate;
- }
- }
- sender = first_weight_to[i];
- num = num_weights_to[i];
- for (j = 0; j < num; j++) {
- inti += activation[sender++] * weight[i][j];
- }
- inti += bias[i];
- if (clamp == 0) {
- neti = istr * inti + estr * extinput[i];
- }
- else {
- neti = istr * inti;
- }
- netinput[i] = neti;
- intinput[i] = inti;
- if (boltzmann) {
- if (probability(logistic(neti)))
- activation[i] = 1.0;
- else
- activation[i] = 0.0;
- }
- else {
- if (neti > 0.0) {
- if (activation[i] < 1.0) {
- acti = activation[i];
- dt = acti + neti*(1.0 - acti);
- if (dt > 1.0) {
- activation[i] = (float) 1.0;
- }
- else activation[i] = (float) dt;
- }
- }
- else {
- if (activation[i] > (float) 0.0) {
- acti = activation[i];
- dt = acti + neti * acti;
- if (dt < FMIN) {
- activation[i] = (float) 0.0;
- }
- else activation[i] = (float) dt;
- }
- }
- }
- }
- end_of_rupdate:
- if(step_size == UPDATE) {
- get_goodness();
- cs_update_display();
- if (single_flag) {
- if (contin_test() == BREAK) {
- return(BREAK);
- }
- }
- }
- if(Interrupt) {
- Interrupt_flag = 0;
- get_goodness();
- cs_update_display();
- if (contin_test() == BREAK) {
- return(BREAK);
- }
- }
- }
- return(CONTINUE);
- }
-
- input() {
- int i;
- char *str,tstr[100];
-
- if (!System_Defined)
- if (!define_system())
- return(BREAK);
- if (!nunames) {
- return(put_error("Must provide unit names. "));
- }
- again:
- str = get_command("Do you want to reset all inputs?: (y or n)");
- if (str == NULL) goto again;
- if (str[0] == 'y') {
- for (i = 0; i < nunits; i++)
- extinput[i] = 0;
- }
- else if (str[0] != 'n') {
- put_error ("Must enter y or n!");
- goto again;
- }
-
- gcname:
- str = get_command("give unit name or number: ");
- if (str == NULL || strcmp(str,"end") == 0) {
- if (clamp) init_activations();
- cs_update_display();
- return(CONTINUE);
- }
- if (sscanf(str,"%d",&i) == 0) {
- for (i = 0; i < nunames; i++) {
- if (startsame(str, uname[i])) break;
- }
- }
- if (i >= nunames) {
- if (put_error("invalid name or number -- try again.") == BREAK) {
- return(BREAK);
- }
- goto gcname;
- }
- gcval:
- sprintf(tstr,"enter input strength of %s: ",uname[i]);
- str = get_command(tstr);
- if (str == NULL) {
- sprintf(err_string,"No strength specified for %s",uname[i]);
- if (put_error(err_string) == BREAK) {
- return(BREAK);
- }
- goto gcname;
- }
- if (sscanf(str, "%f", &extinput[i]) != 1) {
- if (put_error("unrecognized value -- try again.") == BREAK) {
- return(BREAK);
- }
- goto gcval;
- }
- goto gcname;
- }
-
- setinput() {
- register int i;
- register float *pp;
-
- for (i = 0, pp = ipattern[patno]; i < nunits; i++, pp++) {
- extinput[i] = *pp;
- }
- strcpy(cpname,pname[patno]);
- }
-
- test_pattern() {
- char *str;
-
- if (!System_Defined)
- if (!define_system())
- return(BREAK);
-
- if(ipattern[0] == NULL) {
- return(put_error("No file of test patterns has been read in."));
- }
- again:
- str = get_command("Test which pattern? (name or number): ");
- if(str == NULL) return(CONTINUE);
- if ((patno = get_pattern_number(str)) < 0) {
- if (put_error("Invalid pattern specification") == BREAK) {
- return(BREAK);
- }
- goto again;
- }
- setinput();
- zarrays();
-
- cycle();
- return(CONTINUE);
- }
-
-
- newstart() {
- random_seed = rand();
- reset_system();
- }
-
- reset_system() {
- srand(random_seed);
- clear_display();
- zarrays();
- cs_update_display();
- return(CONTINUE);
- }
-
- init_system() {
- int get_unames(),test_pattern(),read_weights(),write_weights();
-
- epsilon_menu = NOMENU;
-
- (void) install_command("network", define_network, GETMENU,(int *) NULL);
- (void) install_command("weights", read_weights, GETMENU,(int *) NULL);
- (void) install_command("cycle", cycle, BASEMENU,(int *) NULL);
- (void) install_command("input", input, BASEMENU,(int *) NULL);
- (void) install_command("test", test_pattern, BASEMENU,(int *) NULL);
- (void) install_command("unames", get_unames, GETMENU,(int *) NULL);
- (void) install_command("patterns", get_patterns, GETMENU,(int *) NULL);
- (void) install_command("reset", reset_system, BASEMENU,(int *) NULL);
- (void) install_command("newstart", newstart, BASEMENU,(int *) NULL);
- (void) install_command("weights", write_weights, SAVEMENU,(int *) NULL);
- (void) install_command("annealing", get_schedule, GETMENU,(int *) NULL);
-
- (void) install_var("patno", Int,(int *) & patno, 0, 0, SETSVMENU);
- init_patterns();
- (void) install_var("cycleno", Int,(int *) & cycleno, 0, 0, SETSVMENU);
- (void) install_var("updateno", Int,(int *) & updateno, 0, 0, SETSVMENU);
- (void) install_var("unitno", Int,(int *) & unitno, 0, 0, SETSVMENU);
- (void) install_var("cuname", String,(int *) cuname, 0, 0, SETSVMENU);
- (void) install_var("clamp", Int,(int *) & clamp, 0, 0, SETMODEMENU);
- (void) install_var("nunits", Int,(int *) & nunits, 0, 0, SETCONFMENU);
- (void) install_var("ninputs", Int,(int *) & ninputs, 0, 0, SETCONFMENU);
- (void) install_var("estr", Float,(int *) & estr, 0, 0, SETPARAMMENU);
- (void) install_var("istr", Float,(int *) & istr, 0, 0, SETPARAMMENU);
- (void) install_var("kappa", Float,(int *) & kappa, 0, 0, SETPARAMMENU);
- (void) install_var("boltzmann", Int, (int *) & boltzmann, 0, 0,
- SETMODEMENU);
- (void) install_var("harmony", Int, (int *) & harmony, 0, 0, SETMODEMENU);
- (void) install_var("temperature",Float, (int *) & temperature, 0, 0,
- SETSVMENU);
- (void) install_var("goodness",Float, (int *) & goodness, 0, 0, SETSVMENU);
- (void) install_var("ncycles", Int,(int *) & ncycles, 0, 0, SETPCMENU);
- (void) install_var("nupdates", Int,(int *) & nupdates, 0, 0, SETPCMENU);
- }
-
- cs_update_display() {
- if (unitno < nunames) strcpy(cuname,uname[unitno]);
- update_display();
- }
-