
/**
 * @author Francisco Jose Aguilar Celdran
 *          Sergio Blanco Cuaresma
 *
 * Intel·ligencia Artificial II
 * Exercici de Memoria Associativa
 * Aprenentatge: Classe executa el proces d'establiment de memoria associativa
 *               i calcula els percentatges de recuperacio dels patrons
 *               emmagatzemats.
 */

import java.util.*;
import java.io.*;

public class Aprenentatge {
   private static void impressioResultats(int OK, int KO, int tantxcen, int numero) {
      System.out.println("Resultats de l'aprenentatge de " + Integer.toString(numero)
                         + " patrons sobre memoria associativa:");
      System.out.println("Recuperacions de patrons: " + Integer.toString(OK));
      System.out.println("Fallides de recuperacio de patrons: " + Integer.toString(KO));
      System.out.println("Percentatge de recuperacions: " + tantxcen +"%");
   }

   private static void impressioParametres() {
      System.out.println("Paràmetres del programa:");
      System.out.println("  --generar nom_fitxer -> genera una nova seqüencia aleatoria de N patrons al fitxer <nom_fitxer>");
      System.out.println("  --patrons nom_fitxer -> obté els patrons del fitxer <nom_fitxer> per generar la memòria i testejar-la");
      System.out.println("  --guardarMem nom_fitxer -> guarda la memoria generada");
      System.out.println("  --llegirMem nom_fitxer  -> recupera una memoria ja generada (no la genera de nou)");
      System.out.println("  --numPatrons valor      -> quantitat de patrons a generar / llegir");
      System.out.println("  --tamPatrons valor      -> tamany dels patrons a generar / llegir");
      System.out.println("  --intents valor         -> intents de recuperacio del patro en la memòria");
      System.out.println("  --debug1                -> impressió patrons similars");
      System.out.println("  --debug2                -> impressió de missatges de depuració");
      System.out.println();
      System.out.println("Exemples:");
      System.out.println("  Aprenentatge --generar aleatoris.txt --numPatrons 100 --tamPatrons 1000");
      System.out.println("  Aprenentatge --patrons aleatoris.txt --numPatrons 100 --tamPatrons 1000 --intents 20 --guardarMem memoria.txt");
      System.out.println("  Aprenentatge --patrons aleatoris.txt --llegirMem memoria.txt --numPatrons 100 --tamPatrons 1000");
      System.out.println();
   }

   public static void main(String args[]) throws IOException {
      int numPatrons = 2;
      int tamPatrons = 10;
      boolean debug1 = false;
      boolean debug2 = false;
      int intents = 50;
      int recuperacions = 0;
      int fallides = 0;
      boolean param1 = false, param2 = false, param3 = false;
      int mode = 0;
      String fitxerSortida = "";
      String fitxerEntrada = "";
      String memoriaIn = null;
      String memoriaOut = null;

      // Inicialitzacions i comprovacio dels parametres

      for (int i = 0; i < args.length; i++) {
         if (args[i].equals("--generar")) {
            if (i <= (args.length - 1)) {
               mode = 0;
               param1 = true;
               fitxerSortida = args[i + 1];
            }
         } else if (args[i].equals("--patrons")) {
            if (i < (args.length - 1)) {
               fitxerEntrada = args[i + 1];
               param1 = true;
               mode = 1;
            }
         } else if (args[i].equals("--guardarMem")) {
            if (i < (args.length - 1)) {
               memoriaOut = args[i + 1];
               /*param1 = true;
               mode = 1;*/
            }
         } else if (args[i].equals("--llegirMem")) {
            if (i < (args.length - 1)) {
               memoriaIn = args[i + 1];
               /*param1 = true;
               mode = 1;*/
            }
         }
         else if (args[i].equals("--numPatrons")) {
            if (i < (args.length - 1)) {
               try {
                  numPatrons = Integer.parseInt(args[i + 1]);
                  param2 = true;
                  //mode = 0;
               }
               catch (Exception e) {}
            }
         }
         else if (args[i].equals("--tamPatrons")) {
            if (i < (args.length - 1)) {
               try {
                  tamPatrons = Integer.parseInt(args[i + 1]);
                  param3 = true;
                  //mode = 0;
               }
               catch (Exception e) {}
            }
         }
         else if (args[i].equals("--intents")) {
            if (i < (args.length - 1)) {
               try {
                  intents = Integer.parseInt(args[i + 1]);
               } catch (Exception e) {}
            }
         }
         else if (args[i].equals("--debug1")) {
            debug1 = true;
         }
         else if (args[i].equals("--debug2")) {
            debug2 = true;
         }

      }

      // Si no han sigut especificats tots el paràmetres necessaris, acabar
      if (! (param1 && param2 && param3)) {
         impressioParametres();
         return;
      }

      //////////
      // Inici del programa: S'executarà A o B
      //////////
      GeneradorPatrons patrons = new GeneradorPatrons(numPatrons,tamPatrons);

      Collection coleccioPatrons = null;

      ////////
      // A) Generar nous patrons aleatoris
      ////////
      if (mode == 0) {
         coleccioPatrons = patrons.generarPatrons(fitxerSortida);
         System.out.println("Patrons generats a l'arxiu: "+fitxerSortida);
         // Només genera, no fa cap calcul
         return;
      }
      //////// END

      ////////
      // B) Llegir de fitxer patrons generats previament
      ////////
      try {
         coleccioPatrons = patrons.llegirPatronsFitxer(fitxerEntrada);
         /*patrons.afegirSorollPatrons(fitxerEntrada, "", 32);
         patrons.afegirSorollPatrons(fitxerEntrada, "", 34);
         patrons.afegirSorollPatrons(fitxerEntrada, "", 36);
         patrons.afegirSorollPatrons(fitxerEntrada, "", 38);*/
         /*patrons.afegirSorollPatrons(fitxerEntrada, "", 1);
         patrons.afegirSorollPatrons(fitxerEntrada, "", 5);
         patrons.afegirSorollPatrons(fitxerEntrada, "", 10);
         patrons.afegirSorollPatrons(fitxerEntrada, "", 20);
         patrons.afegirSorollPatrons(fitxerEntrada, "", 30);
         patrons.afegirSorollPatrons(fitxerEntrada, "", 40);
         patrons.afegirSorollPatrons(fitxerEntrada, "", 50);*/
         
         System.out.println("Patrons obtinguts de l'arxiu: "+fitxerEntrada);
      } catch (Exception e) {
         System.out.println("Error en la lectura del fitxer de patrons!");
      }

      // Generem la memoria (matriu)
      Memoria memoria = new Memoria(numPatrons,tamPatrons,intents,debug2);
      
      if (memoriaIn == null) {
         // Generar memoria
         memoria.aprendrePatrons(coleccioPatrons);
      } else {
         // Recuperar una memoria ja generada
         memoria.llegirMemoria(memoriaIn);
      }
      
      if (memoriaOut != null) {
         // Guardar la memoria
         memoria.escriureMemoria(memoriaOut);
      }
      
      ////////
      // Test: intentar recuperar tots els patrons utilitzats
      ////////
      Iterator iterador = coleccioPatrons.iterator();
      int compt = 0; //

      /*while (iterador.hasNext()) {
         Integer valor_patro[] = (Integer[])iterador.next();
         boolean recuperat = memoria.recuperarPatro(valor_patro);//(((Integer[])iterador.next()));
         if (recuperat) {
            recuperacions++;
         } else {
            fallides++;
         }
      }*/
      

      FileWriter arxiuRecuperats = new FileWriter("recuperats.txt");
      BufferedWriter recuperats = new BufferedWriter(arxiuRecuperats);
      while (iterador.hasNext()) {
         Integer valor_patro[] = (Integer[])iterador.next();
         Similar s = memoria.patroSimilar(valor_patro);
         if (s.identic) {
            if (debug1) {
               System.out.print("Patró idèntic trobat: ");
               for (int i=0; i<s.patro.length; i++) {
                  System.out.print(s.patro[i].intValue() + " ");
               }
               System.out.println();
            }
            recuperacions++;
         } else {
            if (debug1) {
               for (int i=0; i<s.patro.length; i++) {
                  System.out.print(s.patro[i].intValue() + " ");
               }
               System.out.print("és el patró més similar a ");
               for (int i=0; i<valor_patro.length; i++) {
                  System.out.print(valor_patro[i].intValue() + " ");
               }
               System.out.print("amb distancia de Hamming "+distanciaHamming(valor_patro, s.patro));
               System.out.println();
            }
            
            fallides++;
         }
         
         // Guardar patro obtingut
         for (int i=0; i<s.patro.length; i++) {
            recuperats.write(s.patro[i].intValue() + " ");
         }
         recuperats.write("\n");
      }
      recuperats.close();
      int percentatge = (recuperacions * 100) / numPatrons;
      impressioResultats(recuperacions,fallides,percentatge,numPatrons);
      //////// END
   }

   public static float distanciaHamming(Integer[] v, Integer[] w) {
      int resultat = 0;
      for (int i=0; i<v.length; i++) {
         resultat += (1 - v[i].intValue()*w[i].intValue());
      }
      return (float)resultat/2;
   }
}

