/*                  Zadanie z predmetu: NEURONOVE SIETE
                    Projekt c. 2: Kohonenova siet, Euklid. vzdialenost
                    Riesitel: Tomas Smajda, 4. roc., 2001/2002
                                                                             */
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <curses.h>
#include <time.h>
#include <X11/Xlib.h>                     // kazdy Xlib program musi toto obsahovat
#include <assert.h>                       
#include <unistd.h>

#define NIL          (0)                  // meno pre void smernik
#define	N1            2	                  // pocet neuronov vo vstupnej vrstve
#define	N2            5                   // pocet riadkov vo vystupnej vrstve
#define N3            5                   // pocet stlpcov vo vystupnej vrstve
#define POCET_EPOCH  200                  

double x_j[N1];                           // hodnoty neuronov vo vstupnej vrstve
double ou[N2][N3];                        // hodnoty vystupnych neuronov
double sv[N1][N2][N3];                    // vahy w(ij)
double dsv[N1][N2][N3];                   // zmena vah dw(ij)
int x1, x2;                               // suradnice vitazneho neuronu
double vstup[N1];                         // pole na nacitanie vstupu, ktory sa klasifikuje            

double Gama, r;
FILE *pattern_file, *error_file, *vahy;
double x[52], y[52];                      // polia na ulozenie vstupov

int main(int argc, char *argv[])
{
   double min, d;
   int i, j, k, l, epocha=0;
   Gama=1;
   r=(N2+N3)/2;
   
   if ((error_file = fopen("error_file.txt", "w+")) == NULL){
       fprintf(stderr, "Vystupny - chybovy subor sa neda otvorit.\n");
       printf("Stlacte ENTER a aplikacia sa skonci...");
       getchar();
       exit(1);
   }
   if ((pattern_file = fopen("kohonen.pat", "r")) == NULL){
       fprintf(stderr, "Testovaci subor sa neda otvorit.\n");
       printf("Stlacte ENTER a aplikacia sa skonci...");
       getchar();
       exit(1);
   }
   if ((vahy = fopen("vahy.txt", "w+")) == NULL){
       fprintf(stderr, "Nedaju sa zapisat vahy do vystupneho suboru.\n");
       printf("Stlacte ENTER a aplikacia sa skonci...");
       getchar();
       exit(1);
   }

   // naplni sa uciace pole
   for(i=0;i<52;i++)
      fscanf(pattern_file,"%lf %lf\n", &x[i], &y[i]);

   // prvotna inicializacia vah
   printf("Boli inicializovane nasledovne vahy...\n");
   for(i=0;i<N1;i++){
       for(j=0;j<N2;j++){
          for(k=0;k<N3;k++){
             sv[i][j][k]=0.1*rand()/RAND_MAX;
             printf("sv[%d][%d][%d]=%lf\n ", i+1 , j+1, k+1, sv[i][j][k]);
          }
       }
   }
   getchar();

   //------------------------init X11--------------------------------
        // Open the display
        Display *dpy  = XOpenDisplay(NIL);
        assert(dpy);
	       
	// Get some colors
	int blackColor = BlackPixel(dpy, DefaultScreen(dpy));
	int whiteColor = WhitePixel(dpy, DefaultScreen(dpy));
				 
	// Create the window       
	Window w = XCreateSimpleWindow(dpy, DefaultRootWindow(dpy), 0, 0,
				       400, 400, 0, blackColor, blackColor);
										  
        // We want to get MapNotify events								
	XSelectInput(dpy, w, StructureNotifyMask);
											      
	// "Map" the window (that is, make it appear on the screen)							    
	XMapWindow(dpy, w);
													  
	// Create a "Graphics Context"						
	GC gc = XCreateGC(dpy, w, 0, NIL);
														      
	// Tell the GC we draw using the white color											    
	XSetForeground(dpy, gc, whiteColor);
																  
	// Wait for the MapNotify event											
	for(;;) {
	      XEvent e;
	      XNextEvent(dpy, &e);
	      if (e.type == MapNotify)
	            break;
	}																							  																								  
   //-------------------------------------------------------------
   
   do{
      for(l=0;l<52;l++){         
         x_j[0]=x[l];
         x_j[1]=y[l];

         for(i=0;i<N2;i++){         // vypocet hodnoty neuronov na vystupe
            for(j=0;j<N3;j++){
               ou[i][j]=0;
               for(k=0;k<N1;k++){
                  ou[i][j]+=(sv[k][i][j]-x_j[k]) * (sv[k][i][j]-x_j[k]);
               }
            }
         }

         min=ou[0][0];              // najdenie minima
         x1=0;
         x2=0;
         for(i=0;i<N2;i++){
            for(j=0;j<N3;j++){
               if(min>ou[i][j]){
                 min=ou[i][j];
                 x1=i;
                 x2=j;
               }
            }
         }

         for(i=0;i<N1;i++){         // zmena vah
            for(j=0;j<N2;j++){
               for(k=0;k<N3;k++){
                  d=((j-x1)*(j-x1))+((k-x2)*(k-x2));
                  d=sqrtl(d);
                  dsv[i][j][k]=-Gama*(sv[i][j][k]-x_j[i])*exp(-d*d/r);
                  sv[i][j][k]+=dsv[i][j][k];
               }
            }
         }
	 	 
	 // tu zacina vizualizacia 
      
         XSetForeground(dpy, gc, whiteColor);
         for(j=0;j<N3;j++){	      
            for(i=0;i<N2;i++){
	       if(i<N2-1)
	         XDrawLine(dpy, w,gc,((int)(sv[0][i][j]*300)),((int)(sv[1][i][j]*300)),((int)(sv[0][i+1][j]*300)),((int)(sv[1][i+1][j]*300)));
	       if(j<N3-1)
	         XDrawLine(dpy, w,gc,((int)(sv[0][i][j]*300)),((int)(sv[1][i][j]*300)),((int)(sv[0][i][j+1]*300)),((int)(sv[1][i][j+1]*300)));
	    }
         }	 
         XFlush(dpy);
         //sleep(1);
         if (epocha==(POCET_EPOCH-1) && l==51 ){
            sleep(15);
         }	    
         XSetForeground(dpy, gc, blackColor);
         for(j=0;j<N3;j++){
            for(i=0;i<N2;i++){
	       if(i<N2-1)
	         XDrawLine(dpy, w,gc,((int)(sv[0][i][j]*300)),((int)(sv[1][i][j]*300)),((int)(sv[0][i+1][j]*300)),((int)(sv[1][i+1][j]*300)));
	       if(j<N3-1)
	         XDrawLine(dpy, w,gc,((int)(sv[0][i][j]*300)),((int)(sv[1][i][j]*300)),((int)(sv[0][i][j+1]*300)),((int)(sv[1][i][j+1]*300)));
	    }
         }	 
         XFlush(dpy);
         
         // tu konci vizualizacia	
      }
																					           
      epocha++;
      if(!(epocha%1)){
         r=r/1.05;
	 Gama=Gama/1.05;
         //r=exp(-0.01*epocha)+0.01;
         //Gama=exp(-0.01*epocha)+0.01;
      }
      printf("Epocha=%d\t r=%lf\t Gama=%lf\n", epocha, r, Gama);
      fprintf(error_file,"Epocha=%d\t r=%lf\t Gama=%lf\n", epocha, r, Gama);
   }while(epocha<POCET_EPOCH);
   
   // klasifikacia na zaklade zadaneho vstupu    
   printf("\nZadaj vstup x=");
   scanf("%lf",&vstup[0]);
   printf("Zadaj vstup y=");
   scanf("%lf",&vstup[1]);
   
   min=sqrtl( ( (sv[0][0][0]-vstup[0]) * (sv[0][0][0]-vstup[0]) ) + ((sv[1][0][0]-vstup[1]) * (sv[1][0][0]-vstup[1]) ) );
   x1=0;
   x2=0;        
   for(j=0;j<N2;j++){
      for(k=0;k<N3;k++){
            d=sqrtl(((sv[0][j][k]-vstup[0])*(sv[0][j][k]-vstup[0]))+((sv[1][j][k]-vstup[1])*(sv[1][j][k]-vstup[1])));
	    if(min>d){
	      min=d;
	      x1=j;
	      x2=k;
	    }  
      }
   }
   printf("Bol aktivovany neuron[%d][%d].", x1+1, x2+1);
   
   // ulozenie konecnych vah do suboru "vahy.txt"
   for(j=0;j<N2;j++){
       for(k=0;k<N3;k++){
          for(i=0;i<N1;i++){
             fprintf(vahy,"%lf\t", sv[i][j][k]);
          }
          fprintf(vahy,"\n");
       }
   }

   fclose(error_file);
   fclose(vahy);
   fclose(pattern_file);

   //system("gnuplot g.plot");
   printf("\n\nStlacte ENTER a aplikacia sa skonci...");
   getchar();
   getchar();
}

