package basics.math;

import basics.testing.Test;
import basics.utl.NumUtl;

//http://de.wikipedia.org/wiki/Entropie_%28Informationstheorie%29
//http://de.wikipedia.org/wiki/Buchstabenh%C3%A4ufigkeit
public class Shannon
{
public static double calcMaxEntropy(long uniqueWords)
{
   double r = NumUtl.log2(uniqueWords);
   return r < 0 ? 0D : r;
}

public static double calcInformationDensity(long tokens, long types)
{
   double r = (1 / (Math.log(tokens) / Math.log(types)));
   return r < 0 ? 0D : r;
}

// main function to try out Logs class
// input: groesse lex, anzahl woerter im text.
public static void main(String [] args)
{
   long tokens = Long.valueOf(args[1]);
   long types = Long.valueOf(args[0]);
   double sh = Shannon.calcMaxEntropy(types);
   double dichte = Shannon.calcInformationDensity(tokens, types);
   if(types > tokens)
   {
      System.out.println("Falsche Eingabe. Lexikon ist groesser als Anzahl Woerter (" + types
         + ", " + tokens + ")");
   }
   System.out.println("Tokens :   " + tokens);
   System.out.println("Types  :    " + types);
   System.out.println("Informationsgehalt: " + sh + " Sh (Shannon pro Wort).");
   System.out.println("Maximale Entropie ~ " + Math.round(sh) + ".");
   System.out.println("Dichte            : " + dichte);
   System.out.println("Artikelwichtung   : " + (dichte * sh));
}

public static void unittest()
{
   int total = 1000;
   Test.assertTrue(Shannon.calcInformationDensity(total, total) == 1D, "density 1 expected");
   Test.assertTrue(Shannon.calcMaxEntropy(total) > 9.9, "max entropy > 9.9 expected, not "
      + Shannon.calcMaxEntropy(total));
   Test.assertTrue(Shannon.calcInformationDensity(total, total / 10) > 0.66,
      "density 0.66 expected");
   Test.assertTrue(Shannon.calcMaxEntropy(total / 10) > 6.6, "max entropy > 6.6 expected, not "
      + Shannon.calcMaxEntropy(total / 10));
   Test.assertTrue(Shannon.calcInformationDensity(total, total / 100) > 0.33,
      "density 0.33 expected");
   Test.assertTrue(Shannon.calcMaxEntropy(total / 100) > 3.3, "max entropy > 3.3 expected, not "
      + Shannon.calcMaxEntropy(total / 100));
   Test.assertTrue(NumUtl.round(Shannon.calcInformationDensity(total, 2), 1) == 0.1,
      "density 0.1 expected, not " + NumUtl.round(Shannon.calcInformationDensity(total, 2), 1));
   Test.assertTrue(Shannon.calcMaxEntropy(2) == 1, "max entropy 1 expected, not "
      + Shannon.calcMaxEntropy(2));
   //   total = 100000;
   //   Test.printout("X1:1 " + Shannon.calcMaxEntropy(total));
   //   Test.printout("X10  " + Shannon.calcMaxEntropy(total / 10));
   //   Test.printout("X100  " + Shannon.calcMaxEntropy(total / 100));
   //   Test.printout("X2    " + Shannon.calcMaxEntropy(2));
   //   Test.printout("X1    " + Shannon.calcMaxEntropy(1));
   //   Test.printout("X0    " + Shannon.calcMaxEntropy(0));
   //   Test.printout("D1:1 " + Shannon.calcInformationDensity(total, total));
   //   Test.printout("D10  " + Shannon.calcInformationDensity(total, total / 10));
   //   Test.printout("D100 " + Shannon.calcInformationDensity(total, total / 100));
   //   Test.printout("D2   " + NumUtl.round(Shannon.calcInformationDensity(total, 2), 2));
   //   Test.printout("D1   " + NumUtl.round(Shannon.calcInformationDensity(total, 1), 2));
   //   Test.printout("D0   " + NumUtl.round(Shannon.calcInformationDensity(total, 0), 2));
}
}
