/********************************************** */
/*  The Adaline                                 */
/*                                              */
/*  A simulation of a network to learn using the*/
/*  delta rule (Widrow-Hoff Learning)           */
/*                                              */
/*  Written by  Maureen Caudill in Lightspeed C on a Mac        */
/*                                              */
/********************************************** */

#include <math.h>               /* bring in standard math functions     */
#include <stdio.h>              /* bring in standard I/O functions      */

#define  NUMROWS        5
#define NUMCOLS         5
#define NUMPATTS        2
#define THRESHOLD       0
#define BETA            0.1

/*----------------------------------------------------  */
/*                      Global Storage Variables and Arrays             */
/*                                                                      */
/*----------------------------------------------------  */
/* The ADALINE has NUMROWS*NUMCOLS total weights, kept  */
/* in a matrix                                          */
double  adaline[NUMROWS][NUMCOLS];
double  input1[NUMROWS][NUMCOLS];
double  input2[NUMROWS][NUMCOLS];
double  answers[NUMPATTS];
double  insize1, insize2;     /* magnitude of each input pattern */
FILE            *fopen(), *outfile;
char            *path="widscript";
int             maxrow,maxcol;
/*-----------------------------------------------------*/
/*              printweights()          */
/*      Print the current value of the adaline's weights                */
/*----------------------------------------------------- */
printweights()
{
int     i,j;

for (i=0; i< NUMROWS; i++)
{
        printf("\n");
        for (j=0; j<NUMCOLS; j++)
                printf("    %8.3lf", adaline[i][j]  );
}
printf("\n");
}  /*  end printweights */

/*----------------------------------------------------- */
/*              out_signal(pattnum)             */
/*      Calculate the output signal from the adaline for input          */
/*      pattern "pattnum".  Return value is double floating point       */
/*----------------------------------------------------- */
double  out_signal (pattnum)
int     pattnum;
{
int             row,col;
double  result;

result = 0;
for(row=0; row < NUMROWS; row++)
{
        for (col=0; col < NUMCOLS; col++)
        {
                switch (pattnum)
                {
                        case 0:
                                result += input1[row][col]*adaline[row][col];
                                break;
                        case 1:
                                result += input2[row][col]*adaline[row][col];
                                break;
                }  /* end switch */
        }  /* end for each column */
}  /* end for each row  */
if (result >= (double) THRESHOLD)
        result = 1.0;
else
        result = -1.0;
return (result);
}   /*  end out_signal  */
/*---------------------------------------------------- */
/*              adjust_wts(pattnum,res)         */
/*      Adjust the weights of the adaline according to the      */
/*      Widrow-Hoff learning law (aka the Delta Rule):          */
/* w_new = w_old + (BETA * Error * Input) / [(Input)*(Input)]   */
/*----------------------------------------------------- */
adjust_wts(patt,res)
int             patt;         /* number of the pattern being input   */
double  res;                  /* actual output                       */      
{
double  error, w_old, w_new;
double  in, insize;
int             row, col;
double  beta;

beta = BETA;
error = answers[patt] - res;     /* Error = ideal out - actual out  */
for (row=0; row < NUMROWS; row++)
{
        for (col=0; col < NUMCOLS; col++)
        {
                switch (patt)
                {
                case 0: 
                        in       = input1[row][col];
                        insize = insize1;
                        break;
                case 1:
                        in       = input2[row][col];
                        insize = insize2;
                        break;
                }
                w_old = adaline[row][col];
                w_new = w_old + beta*error*in/insize;
                adaline[row][col] = w_new;
        }  /* end for each column */
}  /*  end for each row */
return;
} /* end adjust_wts  */
/*---------------------------------------------------- */
/*              init_inputs()                   */
/*  Initialize the input patterns with the desired inputs.  Also*/
/*  calculate the magnitudes of the inputs and store in global  */
/*  variables insize1 and insize2 for later use by adjust_wts.  */
/*----------------------------------------------------- */
init_inputs()
{
int             row,col;
int             i,j,k;
double  size;

/*  initialize script output to file       */
outfile = fopen(path,"w");

/*  initialize size of maxrow, maxcol */
maxrow = NUMROWS;
maxcol  = NUMCOLS;

/*  first set all input signals to -1     */
for (row=0; row<NUMROWS; row++)
{
        for (col=0; col<NUMCOLS; col++)
        {
                input1[row][col] = 0;
                input2[row][col] = 0;
        }
}
/*  set the pattern into input1 -- a V pattern */
input1[0][0] = 1.0;             /*  X___X     */
input1[1][1] = 1.0;             /*  _X_X_     */
input1[2][2] = 1.0;             /*  __X__     */
input1[1][3] = 1.0;             /*  _____     */
input1[0][4] = 1.0;             /*  _____     */
/*  set the pattern into input2  -- an inverted V pattern  */
input2[2][0] = 1.0;             /*  __X__     */
input2[1][1] = 1.0;             /*  _X_X_     */
input2[0][2] = 1.0;             /*  X___X     */
input2[1][3] = 1.0;             /*  _____    */
input2[2][4] = 1.0;             /*  _____    */
printf("\n Sample output for ADALINE System: \n");
printf("\n  Input pattern 1:");
for (i=0; i< NUMROWS; i++)
{
        printf("\n");
        for (j=0; j<NUMCOLS; j++)
                printf( "    %8.3lf", input1[i][j]  );
}
printf("\n  Input pattern 2:");
for (i=0; i< NUMROWS; i++)
{
        printf("\n");
        for (j=0; j<NUMCOLS; j++)
                printf( "    %8.3lf", input2[i][j]  );
}
printf("\n  Return to continue...");
scanf("%c",&i);
/*  Since each input has precisely 5 non-zero input signals     */
/*  we cheat and calculate the square of the magnitude as       */
/*  simply as the value 5.      */
insize1 = 5.0;
insize2 = 5.0;
return;
}  /*  end init_inputs  */

/*---------------------------------------------------- */
/*              init_wts()                              */
/* Initialize the weights randomly between -1 and +1 to begin   */
/* Note that the weights are not necessarily normalized.        */
/*----------------------------------------------------  */
init_wts()
{
int             ranvalue;
unsigned int   seed;            /* used to seed the rand() function     */
double  weight;
int             row,col;

printf("Please enter integer random number seed:  ");
scanf ("%d",&seed);
ranvalue = srand(seed);
for (row=0; row<NUMROWS; row++)
{
        for (col=0; col<NUMCOLS; col++)
        {
                ranvalue = rand();    /* pick a random integer  */
                weight = (16384. - (double)ranvalue)/16384.;
                                         /* this will +- weights */
                adaline[row][col] = weight;
        }  /*  end for each column  */
}  /*  end for each row  */
return;
}  /* end init_wts  */

/*----------------------------------------------------  */
/*              init_answers()          */
/* Initialize the answer array to provide the correct outputs.  */
/*----------------------------------------------------  */
init_answers()
{
/*      This is just a primitive method of setting up the answers*/
answers[0] =    -1;
answers[1] =      1;
return;
}  /*  end init_answers  */
/*---------------------------------------------------  */
/*              MAIN Program begins here        */
/*---------------------------------------------------   */
main()
{
int             patt, prev_patt;
int             ok;
double  ans,res;
double  out_signal();
int             in;
int             i,j,k,row,col;

/*      Initialize the system */
init_wts();
init_inputs();
init_answers();
maxrow = NUMROWS;
maxcol  = NUMCOLS;

/*      Do some output of the initial adaline values  */
printf("\n\n Initial weights:");
printweights();
printf("\n");

/*      First get adaline to respond to each pattern correctly  */
for (patt = 0; patt < NUMPATTS; patt++)
{
        printf("\n\n  Beginning adaptation to pattern %d",patt);
        res = out_signal(patt);
        printf("\n  The response is %8.3lf and should be %8.3lf.",
                        res, answers[patt]);
        while (res != answers[patt])
        {
                adjust_wts(patt,res);
                printf("\n  Adjusting weights for pattern %d",patt);
                printf("\n  New weights:  ");
                printweights();
                res = out_signal(patt);
                printf("\n  The response is now %8.3lf and should be %8.3lf.",
                        res, answers[patt]);
                if (res == answers[patt])
                        printf("\n  Pattern correctly identified");
                else
                {
                        printf("\n Adjust again? ('1' to continue)");
                        scanf("%d",&in);
                        if (in != 1)
                                res = answers[patt];
                }  /* end if-else */
        }  /* end while  */
        /*  Now that adaline recognizes this  pattern, double   */
        /*  check to be sure that we can still recognize each of*/
        /*  the previous patterns without changing the weights. */
        /*  If not, we'll have to re-adjust the weights.        */
                for (prev_patt=0; prev_patt<patt; prev_patt++)
                {
                        while (res= out_signal(prev_patt)
                                             != answers[prev_patt])
                        {
                                adjust_wts(prev_patt,res);
                                printf("\n  Re-adjusting weights for pattern %d",
                                        prev_patt);
                                printf("\n  New weights:  ");
                                printweights();
                        }  /* end while */
                }  /*  end for previous patterns */
        printf("\n  Adaline now recognizes pattern %d",patt);
}  /* end for each pattern */
/*      Final check to be sure that all patterns are recognized */
printf("\n \n  Adaline is now adapted to recognize all patterns.");
printf("\n  The final weights are:  ");
printweights();
printf("\n \n  Patt#      Answer      Output");
for (patt = 0; patt < NUMPATTS; patt++)
{
        res = out_signal(patt);
        printf("\n   %d         %3.0lf           %3.0lf",
                        patt, answers[patt], res);
}
printf("\n\n  All patterns have been learned...");
printf( "\n\n  Adaline program complete...");           
}  /* end main program */


Program Listing 1
Copyright Maureen Caudill, 1987
ADALINE Program
