#include<stdio.h>
#include<math.h>
#include<time.h>
#include<stdlib.h>

#define LAYER	3
#define INPUT	2
#define HIDDEN	2
#define OUTPUT	1
#define CTG		4

#define ITERATIONS	30000

#define ETA		1.20
#define EPSILON	1.00
#define WD		4.00
#define MIN_ERR	0.000000001

#define ON		0.9
#define OFF		0.1
#define SMAX	15
#define SMIN	-15
#define MAX		0.99995
#define MIN		0.00005

#ifdef	_Cdecl
#define	drand() ((double)(rand()+1)/RAND_MAX-0.5)
#else
#define	drand() ((double)(rand()+1)/RAND_MAX-0.5)
#endif

#define sq(x) (x)*(x)

double 	i_lay[CTG][INPUT+1],
		h_lay[HIDDEN+1],
		o_lay[OUTPUT],
		teach[CTG][OUTPUT];
		
double	ih_w[INPUT+1][HIDDEN],
		ho_w[HIDDEN+1][OUTPUT];
		
double	h_del[HIDDEN],
		o_del[OUTPUT];

double	ih_lw[INPUT+1][HIDDEN],
		ho_lw[HIDDEN+1][OUTPUT];

//extern double sigmoid();
double sigmoid(double s);

main(argc,argv)
	int	argc;
	char **argv;
{
  int	i,j,ite,ctg;
  double err,sum;
  srand((int)time((long *)0));
  
  /* ExOR Problem */
  i_lay[0][0]=OFF; i_lay[0][1]=OFF; i_lay[0][2]=ON; teach[0][0]=OFF;
  i_lay[1][0]=ON;  i_lay[1][1]=OFF; i_lay[1][2]=ON; teach[1][0]=ON;
  i_lay[2][0]=OFF; i_lay[2][1]=ON;  i_lay[2][2]=ON; teach[2][0]=ON;
  i_lay[3][0]=ON; i_lay[3][1]=ON;  i_lay[3][2]=ON; teach[3][0]=OFF;

  h_lay[HIDDEN]=ON;
	
  for(j=0;j<HIDDEN;j++)
    for(i=0;i<=INPUT;i++)
      ih_w[i][j]=WD*drand();
  for(j=0;j<OUTPUT;j++)
    for(i=0;i<=HIDDEN;i++)
      ho_w[i][j]=WD*drand();

  for(ite=0;ite<=ITERATIONS; ite++){
    for(j=0;j<HIDDEN;j++)
      for(i=0;i<=INPUT;i++)
	ih_lw[i][j]=0.;
    for(j=0;j<OUTPUT;j++)
      for(i=0;i<=HIDDEN;i++)
	ho_lw[i][j]=0.;
    
    for(ctg=0,err=0.;ctg<CTG;ctg++){
      for(j=0;j<HIDDEN;j++){
	for(i=0,sum=0.;i<=INPUT;i++)
	  sum+=i_lay[ctg][i]*ih_w[i][j];
	h_lay[j]=sigmoid(sum);
      }
      for(j=0;j<OUTPUT;j++){
	for(i=0,sum=0.;i<=HIDDEN;i++)
	  sum+=h_lay[i]*ho_w[i][j];
	o_lay[j]=sigmoid(sum);
      }
      for(i=0;i<OUTPUT;i++){
	err+=sq(teach[ctg][i]-o_lay[i])/2./(double)CTG;
	o_del[i]=EPSILON*(teach[ctg][i]-o_lay[i])*o_lay[i]*(1.-o_lay[i]);
      }
      for(j=0;j<=HIDDEN;j++){
	h_del[j]=0.;
	for(i=0;i<OUTPUT;i++)
	  h_del[j]+=o_del[i]*ho_w[j][i];
	h_del[j]*=EPSILON*h_lay[j]*(1.-h_lay[j]);
      }
      
      for(j=0;j<=HIDDEN;j++)
	for(i=0;i<OUTPUT;i++)
	  ho_lw[j][i]+=ETA*o_del[i]*h_lay[j];
      for(j=0;j<=INPUT;j++)
	for(i=0;i<HIDDEN;i++)
	  ih_lw[j][i]+=ETA*h_del[i]*i_lay[ctg][j];
    }
    fprintf(stderr,"iteration = %4d, error = %1.5f\n",ite,err);
    if((err<MIN_ERR)||(ite==ITERATIONS)){
      for(ctg=0;ctg<CTG;ctg++){
	fprintf(stderr,"ctg[%d] : ",ctg);
	for(i=0;i<INPUT;i++)
	  fprintf(stderr,"i[%d] = %1.1f  ",i,i_lay[ctg][i]);
	for(j=0;j<HIDDEN;j++){
	  for(i=0,sum=0.;i<=INPUT;i++)
	    sum+=i_lay[ctg][i]*ih_w[i][j];
	  h_lay[j]=sigmoid(sum);
	}
	for(j=0;j<OUTPUT;j++){
	  for(i=0,sum=0.;i<=HIDDEN;i++)
	    sum+=h_lay[i]*ho_w[i][j];
	  o_lay[j]=sigmoid(sum);
	  fprintf(stderr,"o[%d] = %1.5f, t{%d] = %1.1f\n",j,o_lay[j],j,teach[ctg][j]);
	}
      }
      fprintf(stderr,"iteration = %4d, error = %1.5f\n",ite,err);
      break;
    }
    for(j=0;j<=HIDDEN;j++)
      for(i=0;i<OUTPUT;i++)
	ho_w[j][i]+=ho_lw[j][i];
    for(j=0;j<=INPUT;j++)
      for(i=0;i<HIDDEN;i++)
	ih_w[j][i]+=ih_lw[j][i];
  }
}

double sigmoid(double s)
{
  double sm;
  
  sm=EPSILON*s;
  if(sm>SMAX)			return(MAX);
  else if(sm<SMIN)	return(MIN);
  else				return(1./(1.+exp(-sm)));
}
