[comp.ai.neural-nets] Hopfield Neural Network Simulator

johnsun@hubcap.UUCP (John K Sun) (04/06/88)

/*

   Since many people is interested in my simulation,
   I have posted it right here.

*/

/*
   Neural Network implementation solving optimization problems using
   the  generalized Hopfield model. 

   The shelving problem.  (Exploring the Neural Universe)

   Mix-Mode version.

     shelve -     goes into interactive mode with default values.
     shelve       goes into batch mode with default values.

   By John K. Sun, (C) Feb 25, 1988.

status: This program may be freely used, modified, except for
commercial purposes.

*/

#    include <stdio.h>
#    include <time.h>
#    include <math.h>
#    include <curses.h>
#    include <memory.h>

#    include "local.h"
#    include "neural.h"

     Vector X,				/* Coordinates */
            Y;

     Matrix V,				/* Output  voltage */
            u,				/* Initial voltage */
            Du,				/* Change in U     */
            d,				/* distance matrix */
            I,				/* Backup Current  */
            ExI;			/* Current */

     /* The conductance Multidimensional Array */

     Table  T;

     int 
                Stop_Freq  = 50,
                Iterations = 2000;

     double     
                Threshold = 0.0001,
                C = 1.0,
                R = 300.0;		/* Actually Tau = R * C = 300. */

     int    
            N,				/* N neurons per row or column */
            Gain_rate    = 15,
            SAVE_RATE,
            Times_to_run = 20;
 
     double 
            GAIN         = 0.01,	/* Starting variable gain */
            Scale_factor = 0.28,
            Gain_factor  = 1.05;

     double SAVE_GAIN, 
            SAVE_FACTOR;

     /***************************************************************
      * Fatal error exit routine                                    
      *                                                              
      * syntax: error_exit(function_name, format, arg1, arg2, ...); 
      ***************************************************************/
     void error_exit(name, message)
       char *name, *message;
     {
       /* print out the name of the function causing error */
       fprintf(stderr, "ERROR in %s: ", name);

       /* print out remainder of message */
       fprintf(stderr, message);

       exit(-1);
      } /* error exit */


     /********************************
      * Amplifier function generator 
      ********************************/ 
     double g(u) 
       double u;
     {
       return (0.5 * (1.0 + tanh(u * GAIN)));
     } /* Amplifier output V = g(u) */


     /***********************************************************
      * C * dUi/dt = -Ui / R + sum(TijVj) + Ii    
      ***********************************************************/
     double Delta_u(i, j)          
       int i, j;
     {
       double   sum;
       register int    k, l;

       sum = 0.0;
   
       for (k = 1; k <= N; k++)
       for (l = 1; l <= N; l++)
         sum = sum + T [i] [j] [k] [l] * V[k] [l];

       return( - u[i][j] / (R * C) + (sum + ExI[i][j]) / C );

     } /* Delta_u */

     /*********************************
      * Initialize conductance matrix 
      *********************************/
     void Make_T() 
     {
       register int x, i, y, j;

       for (x = 1; x <= N; x ++)
       for (i = 1; i <= N; i ++)
       for (y = 1; y <= N; y ++)
       for (j = 1; j <= N; j ++) 
           T [x][i][y][j] = 0.0;

       for (x = 1; x <= N; x++)
       for (i = 1; i <= N; i++)
       for (y = 1; y <= N; y++)
       for (j = 1; j <= N; j++) 
         if ((i EQUAL j) AND (x UNEQUAL y) OR 
             (x EQUAL y) AND (i UNEQUAL j))
           T [x][i][y][j] = -2.0;

     } /* Make_T */
       

     /******************************
      * Initialize Output Voltages 
      ******************************/
     void Init_V()
     {
       register int i, j;

       for (i = 1; i <= N; i ++)
       for (j = 1; j <= N; j ++)
         V[i][j] = g(u[i][j]);
     } /* Init_V */


     /*******************************
      * Initialize initial voltages 
      *******************************/
     void Init_u()
     {
       register int i, j;

       for (i = 1; i <= N; i ++)
       for (j = 1; j <= N; j ++)
         u[i][j] = -100.0;
     } /* Init_u */


     /***********************
      * Initialize Currents 
      ***********************/
     void Init_I()
     {
       register int i, j;

       ExI [1][1] = 10.0;
       ExI [1][2] =  5.0;
       ExI [1][3] =  4.0;
       ExI [1][4] =  6.0;
       ExI [1][5] =  5.0;
       ExI [1][6] =  1.0;
       ExI [2][1] =  6.0;
       ExI [2][2] =  4.0;
       ExI [2][3] =  9.0;
       ExI [2][4] =  7.0;
       ExI [2][5] =  3.0;
       ExI [2][6] =  2.0;
       ExI [3][1] =  1.0;
       ExI [3][2] =  8.0;
       ExI [3][3] =  3.0;
       ExI [3][4] =  6.0;
       ExI [3][5] =  4.0;
       ExI [3][6] =  6.0;
       ExI [4][1] =  5.0;
       ExI [4][2] =  3.0;
       ExI [4][3] =  7.0;
       ExI [4][4] =  2.0;
       ExI [4][5] =  1.0;
       ExI [4][6] =  4.0;
       ExI [5][1] =  3.0;
       ExI [5][2] =  2.0;
       ExI [5][3] =  5.0;
       ExI [5][4] =  6.0;
       ExI [5][5] =  8.0;
       ExI [5][6] =  7.0;
       ExI [6][1] =  7.0;
       ExI [6][2] =  6.0;
       ExI [6][3] =  4.0;
       ExI [6][4] =  1.0;
       ExI [6][5] =  3.0;
       ExI [6][6] =  2.0;
       
       for (i = 1; i <= N; i++)
       for (j = 1; j <= N; j++) {
         I   [i][j]  = ExI [i][j];
         ExI [i][j] *= Scale_factor;
         } /* for */
       
     } /* Init_I */

     /****************/
      BOOLEAN Stable()
     /****************/
     {
       register int i, j;

       for (i = 1; i <= N; i++) 
         for (j = 1; j <= N; j++) 
           if (  (u[i][j] * Du[i][j] < 0.0)
             OR ((abs(V[i][j] - 1.0) > Threshold)
             AND (abs(V[i][j]) > Threshold)) ) return(False);

       return(True);

     } /* Stable */

     /*********************/
      double print_answer()
     /*********************/
     {
       double   	Sum;
       register 	int    i, j;

       Sum = 0.0;
       putchar('\n');
       for (j = 1; j <= N; j++)
       for (i = 1; i <= N; i++)
         if (abs(V[i][j] - 1.0) <= Threshold) {
           Sum += I[i][j];
           printf(" %d", i);
           }

       printf(" Total = %7.3f\n", Sum);
       return(Sum);

     } /* Total */

     /*************************************************/
      void change_value(msg_str, row, col, value)
     /*************************************************/
       char   *msg_str;
       int     row, col;
       double *value;
     {
       move(PROMPT_ROW + 1, PROMPT_COL + 25);
       clrtoeol();
       addstr(msg_str);
       refresh();
       scanw("%lf", value);
       mvprintw(row, col + 10, "%7.3f", *value);
       refresh();

     } /* change value */

     /*****************************************/    
      void print_matrix(msg, matrix, row, col)
     /*****************************************/    
       char    *msg;
       Matrix   matrix; 
       int      row, col;
     {
       register int i, j;

       mvaddstr(MAT_ROW, MAT_COL, msg);
       addch('\n');
       for (i = 1; i <= row; i++) {
         for (j = 1; j <= col; j++)    
           printw(" %7.3f ", matrix[i][j]);
         addch('\n');
         } /* for */       
 
       refresh();

     } /* print matrix */
       
     /********************/
      void Restore_Values()
     /********************/
     {
       GAIN        = SAVE_GAIN;
       Gain_factor = SAVE_FACTOR;
       Gain_rate   = SAVE_RATE;

       /* Initialize initial voltage for amplifiers */
       Init_u();

       /* Initialize Output voltage */
       Init_V();

       /* Initialize Currents */
       Init_I();

     } /* restore values */

     /*******************/
      void Save_Values()
     /*******************/
     {
       SAVE_GAIN    = GAIN;
       SAVE_FACTOR  = Gain_factor;
       SAVE_RATE    = Gain_rate;
     } /* Save Values */
       
     /*****************/
      double Energy()
     /*****************/
     {
       register int x, i, y, j;
       double   Sum1, Sum2;

       Sum1 = Sum2 = 0.0;
       for (x = 1; x <= N; x++)
       for (i = 1; i <= N; i++) {
         for (y = 1; y <= N; y++) 
         for (j = 1; j <= N; j++) 
           Sum1 += T [x][i][y][j] * V [x][i] * V [y][j];
         Sum2 += V[x][i] * I[x][i];
       } /* for */

       return( -0.5 * Sum1 - Sum2 );

     } /* System Energy */
 
     /*********************/
      void get_command()
     /*********************/
     {     
       register char c;
       double   temp;
       
       do {
       move(PROMPT_ROW, PROMPT_COL + 1);
       refresh();
       c = getch();
       switch(c) {
         case 'C': case 'c': 
           addstr("\nChange (g, f, r, s, i) :");
           refresh();
           c = getch();
           switch(c) {
             case 'g': case 'G':
             change_value(" Gain = ", GAIN_ROW, GAIN_COL, &SAVE_GAIN);
             break;
        
             case 'f': case 'F':
             change_value(" Factor = ", GAINF_ROW, GAINF_COL, &SAVE_FACTOR);
             break;

             case 'r': case 'R':
             change_value(" Rate = ", GAINR_ROW, GAINR_COL, &temp);
             SAVE_RATE = (int) temp;
             break;

             case 's': case 'S':
             change_value(" Scale = ", SCALEF_ROW, SCALEF_COL, &Scale_factor);
             break;

             case 'i': case 'I':
             change_value(" Stp f = ", FREQ_ROW, FREQ_COL, &temp);
             Stop_Freq = (int) temp;
             break;
	
             default: addstr("Invalid Command!");
             } /* end case */
           refresh();
           break;

         case 'P': case 'p':
           addstr("\nShow (V, U, Du) :");
           clrtoeol();
           refresh();
           c = getch();
           switch(c) {
                 
             case 'u': case 'U':
             print_matrix("+++> Output Us <+++", u, N, N);
             break;

             case 'v': case 'V':
             print_matrix("---> Output Vs <---", V, N, N);
             break;

             case 'd': case 'D':
             print_matrix("---> Output Du <---", Du, N, N);
             break;

             default: addstr("Please try again!");
             } /* end case */
           refresh();
           break;

         case 'g': case 'G': return;

         case 'r': case 'R': Restore_Values(); break;

         case 's': case 'S': Save_Values(); break;
   
         case 'q': case 'Q': endwin(); exit(1);

         default: addstr("Invalid command!");
         } /* end case */
       } while(True);
             
     } /* get command from user */
     /****************/
      main(argc, argv)
     /****************/
       int    argc;
       char **argv;
     {
       long     now;
       double   Answer = 0.0;
       register int    Times, Counter, i, j, rand1, rand2, SqN;
       register int    mode;
   
       N = 6;				 /* Problem dependent */
       Save_Values();

       if (argc UNEQUAL 1) {

         if (argv[1][0] UNEQUAL INTRACT_SW) 
           mode = BATCH;
         else {
           mode = INTERACTIVE;
           stdscr = initscr();
           clear();
           addstr("Turbo NEURAL NETWORK -- OPTIMIZATION PROBLEMS");
           addstr(" (c) 1988 John Sun ");
           if (argc EQUAL 2) 
             goto nocomline;
           } /* else */

         SAVE_GAIN    = GAIN         = (double) atof(argv[1 + mode]);
         SAVE_FACTOR  = Gain_factor  = (double) atof(argv[2 + mode]);
         SAVE_RATE    = Gain_rate    = (int)    atoi(argv[3 + mode]);
         Times_to_run = (int)    atoi(argv[4 + mode]);
         Scale_factor = (double) atof(argv[5 + mode]);
         } /* if */
        
       nocomline:

       if (mode UNEQUAL BATCH) {
         mvprintw(FREQ_ROW,   FREQ_COL,   "Stop F = %7d",   Stop_Freq);
         mvprintw(ENERGY_ROW, ENERGY_COL, "Energy = %7.3f", Energy());
         mvprintw(GAIN_ROW,   GAIN_COL,   "Gain   = %7.3f", GAIN);
         mvprintw(GAINF_ROW,  GAINF_COL,  "Factor = %7.3f", Gain_factor);
         mvprintw(GAINR_ROW,  GAINR_COL,  "Rate   = %7d",   Gain_rate);
         mvprintw(SCALEF_ROW, SCALEF_COL, "Scale  = %7.3f", Scale_factor);
         mvaddch (PROMPT_ROW, PROMPT_COL, '>');
         mvaddstr(HELP_ROW,   HELP_COL,   "(C)hange, (R)estore, (S)ave, (G)o, (P)rint or (Q)uit");
         refresh();
         } /* if */
       else
         printf("\nGain = %6.3f, factor = %6.3f, rate = %7d, scale = %6.3f\n",
              GAIN, Gain_factor, Gain_rate, Scale_factor);

       if (N > Max) 
         error_exit("main", "Subscript Out of range \n");

       SqN = N * N;

       /* Initialize Connectivity Matrix */
       Make_T();

       Restore_Values();

       if (mode UNEQUAL BATCH) get_command();

       for (Times = 1; Times <= Times_to_run; Times ++) {

         /* Start at a random place. 
            Note: srandom() and random() are available in BSD4.2 or higher 
                  and  Ultrix  only.  For  other Unix systems, use srand()
                  and rand() instead. 
         */
         srandom((int) (time(&now) MOD 37) );

         for (Counter = 1; Counter <= Iterations; Counter ++) {
 
           for (i = 1; i <= SqN; i++) {

             rand1 = 1 + (int) (random() % N);

             rand2 = 1 + (int) (random() % N);

             Du [ rand1 ] [ rand2 ] = Delta_u(rand1, rand2);

             u [ rand1 ] [ rand2 ] += Du [ rand1 ] [ rand2 ];

             V  [ rand1 ] [ rand2 ] = g( u[ rand1 ] [ rand2 ]);
             } /* for */

           if (mode UNEQUAL BATCH) {
             mvprintw(ENERGY_ROW, ENERGY_COL, "Energy = %7.3f", Energy());
             mvprintw(GAINC_ROW,  GAINC_COL,  "New Ga = %7.3f", GAIN);
             print_matrix("---> Output Vs <---", V, N, N);
             } /* if */

           if (Stable()) break;

           if ((Counter MOD Gain_rate) EQUAL 0) GAIN *= Gain_factor;

           if (((Counter MOD Stop_Freq) EQUAL 0) AND
               (mode UNEQUAL BATCH) )
             get_command();     

           } /* for */

         Answer += (double) print_answer();
   
         if (mode UNEQUAL BATCH) 
           get_command();
         else 
           Restore_Values();
   
         } /* for */
       
       if (mode UNEQUAL BATCH) {
         move(END_ROW, END_COL);
         printw("\nRuns = %4d, Average = %7.3f\n", Times_to_run,         
                Answer / (double) Times_to_run);
         refresh();
         endwin();
         } /* if */
       else
         printf("\nRuns = %4d, Average = %7.3f\n", Times_to_run,         
                Answer / (double) Times_to_run);

     } /* main */

johnsun@hubcap.UUCP (John K Sun) (04/06/88)

/****************************************
 * Neural Network Include File
 * static char NeuralSid[] = "@(#)neural.h	1.3 4/3/88";
 ****************************************/ 

#ifndef  NEURAL_H

#define  NEURAL_H

#    define  Max              10
#    define  ReservedElements (Max + 1)   /* Reserve 0, use 1..Max */
#    define  GRAPHICS
#    define  MONOGRAPHICS
#    define  INTERACTIVE      1
#    define  BATCH            0
#    define  INTRACT_SW       '-'
#    define  SUN3GRAPH_SW     '+'  

     typedef
         double Vector [ ReservedElements ];
 
     typedef
         Vector Matrix [ ReservedElements ];
 
     typedef
         Matrix Table  [ ReservedElements ] [ ReservedElements ];

#    define  PROMPT_ROW  3 
#    define  PROMPT_COL  0

#    define  HELP_ROW    11
#    define  HELP_COL    0

#    define  MAT_ROW     4
#    define  MAT_COL     20   

#    define  ANS_ROW     4
#    define  ANS_COL     0

#    define  END_ROW     11
#    define  END_COL     0

#    define  FREQ_ROW    1
#    define  FREQ_COL    1

#    define  GAIN_ROW    2
#    define  GAIN_COL    1

#    define  ENERGY_ROW  1
#    define  ENERGY_COL  20

#    define  GAINC_ROW   1
#    define  GAINC_COL   40

#    define  SCALEF_ROW  2
#    define  SCALEF_COL  60

#    define  GAINR_ROW   2
#    define  GAINR_COL   40

#    define  GAINF_ROW   2
#    define  GAINF_COL   20

/* Color definitions */

#define BLACK           0       /* white on b&w */
#define RED             1       /* black on b&w */
#define GREEN           2       /* black on b&w */
#define BLUE            3       /* black on b&w */

/* Position definitions */

#define ORIGIN_X        500
#define ORIGIN_Y        500
#define OFFSET_X        500
#define OFFSET_Y        500
#define MAX_X           2500
#define MAX_Y           2500

#endif 

johnsun@hubcap.UUCP (John K Sun) (04/06/88)

/*
	static char LocalSid[] = "@(#)local.h	1.2 4/1/88";
*/

#        ifndef  LOCAL_H
#        define  LOCAL_H

#        define  Mod         %
#        define  And         &&
#        define  Or          ||
#        define  Not         !
#        define  EQUAL       ==
#        define  UNEQUAL     !=
#        define  NOT_FOUND   (-1)
#        define  ERROR       (-1)
#        define  NULL_CHAR   ('\0')
#        define  PARMS(x)    ()              /* For non ANSI C */
#        define  COL_80      81
#        define  ASCII_TABLE 256
#        define  FOREVER     for(;;)
#        define  End_Of_File 26
#        define  NEW_PAGE    '\014'

         typedef
           enum { True = 1, False = 0 } BOOLEAN;

         typedef
           enum { lt = -1, eq = 0, gt = 1 } RELATION;

#        define SWAP(a, b, t) ((t) = (a), (a) = (b), (b) = (t))

#endif

johnsun@hubcap.UUCP (John K Sun) (04/06/88)

hello folks,

  My recent Hopfield Neural Network should only be used for educational
purposes ONLY.  Please contact me *FIRST*  for  improvements,  changes,
bug reports, comments, etc.

johnsun@hubcap.clemson.edu

bills@hpcllmv.HP.COM (Bill Serra) (04/14/88)

>  My recent Hopfield Neural Network should only be used for educational
>purposes ONLY.  Please contact me *FIRST*  for  improvements,  changes,
>bug reports, comments, etc.
>
>johnsun@hubcap.clemson.edu
>----------

John, thanks++ for submitting this source. I've compiled it without 
problems (except that our C compiler doesn't like AND/OR/MOD)  but 
I'm getting this unsatisfied externals from the loader: 

ld: Unsatisfied symbols:
   $global$ (data)
   initscr (code)
   $$mulI (code)
   srandom (code)
   printf (code)
   endwin (code)
   fprintf (code)
   exit (code)
   atof (code)
   atoi (code)
   printw (code)
   mvprintw (code)
   tanh (code)
   wrefresh (code)
   _iob (data)
   abs (code)
   waddch (code)
   wclear (code)
   time (code)
   wmove (code)
   wgetch (code)
   stdscr (data)
   random (code)
   wclrtoeol (code)
   waddstr (code)
   scanw (code)
   $$remI (code)
   _flsbuf (code)

I know some of them (atof, atoi, exit, fprintf, tanh...) and some other
are completely unknown to me. Is there any special library I should link
it into?  or is there something I'm doing wrong, or missing an include file?


Bill Serra  (e-mail-> bills@hpda | {hpda,hplabs,hpfcla,hpfclp}!hpcllmv!bills)
---

bills@hpcllmv.HP.COM (Bill Serra) (04/15/88)

>John, thanks++ for submitting this source. I've compiled it without 
>problems (except that our C compiler doesn't like AND/OR/MOD)  but 
>I'm getting this unsatisfied externals from the loader: 
>
>ld: Unsatisfied symbols:
>  [..list..]
>
>Bill Serra  (e-mail-> bills@hpda | {hpda,hplabs,hpfcla,hpfclp}!hpcllmv!bills)
>---
Sorry, I didn't realize they were -lcurses... !!

bwk@mitre-bedford.ARPA (Barry W. Kort) (04/16/88)

I, too, had to do a bit of detective work to fix hopfield.c:

First of all, the pre-processor variables "MOD", "AND", "NOT", and "OR"
are defined in "local.h", except that they are spelled "Mod", "And",
"Not", and "Or".  I converted them to ALL UPPER CASE in "local.h"
and that problem disappeared.

Secondly, I guessed at the link libraries needed to resolve the
external function calls.  They turned out to be the math lib (-lm),
the term lib (-ltermlib)  and the curses lib (-lcurses).
I have added the following comment to my copy of hopfield.c so that
future users don't have to go into Sherlock mode to compile it:

/*
        To Compile:

                cc -o hopfield hopfield.c -lm -lcurses -ltermlib

*/

I enjoy playing with interesting software like hopfield.c, but life
would be easier if the creators of such programs would include comments
on compilation, run-time switches, etc.  Now if I could only figure
out the rest of the story behind Hopfield Networks, I would understand
what the program does!  :-)

--Barry Kort 

ying@hubcap.UUCP (Ying Xie) (04/17/88)

In article <10370001@hpcllmv.HP.COM>, bills@hpcllmv.HP.COM (Bill Serra) writes:
> problems (except that our C compiler doesn't like AND/OR/MOD)  but 

for the AND/OR/MOD see local.h

> I'm getting this unsatisfied externals from the loader: 
> 
> ld: Unsatisfied symbols:
>    $global$ (data)
>    initscr (code)
> ....
> etc.

Hello folks,

	please compiled with:

	% cc -o hnn main.c -lcurses -ltermlib -lm &

john.  

Sorry for the inconvienence.