package math.info;

import math.utils.MathUtil;

public class InfoUtil{
	/**
	 * H albo hartley określa liczbę bitów na dit i służy do
	 * przeliczania między tymi jednostkami
	 */
	public static final double H = 1.0 / MathUtil.log(2, 10);

	private InfoUtil(){}

	/** 
	 * @param liczbaElementow - liczba elementów układu
	 * @param liczbaStanowElementu - liczba odróżnialnych stanów elementu
	 * @return - liczbę stanów badanego układu
	 */
	public static double liczbaStanowUkladu(double liczbaElementow,
			double liczbaStanowElementu) {
		return Math.pow(liczbaStanowElementu, liczbaElementow);
	}

	/**
	 * Oblicza różnorodność zbioru rozróżnialnych stanów
	 * @param liczbaStanow - liczba możliwych sytanów
	 * @return - zwraca różnorodność zbioru wyrażoną w postaci liczby
	 * bitów
	 */
	public static double roznorodnosc2(double liczbaStanow) {
		return MathUtil.log(liczbaStanow, 2);
	}

	/**
	 * Oblicza różnorodność zbioru rozróżnialnych stanów
	 * @param liczbaStanow - liczba możliwych sytanów
	 * @return - zwraca różnorodność zbioru wyrażoną w postaci liczby
	 * ditów
	 */
	public static double roznorodnosc10(double liczbaStanow) {
		return MathUtil.log(liczbaStanow, 10);
	}

	/**
	 * Entropia w ditach
	 * @param tabl - tablica prawdopodobieństw stanów
	 * @return - entropię w ditach
	 */
	public static double entropiaD(double[] tabl) {
		double sum = 0;
		for (double aTabl : tabl) {
			if (aTabl != 0) {
				sum += aTabl * MathUtil.log(aTabl, 10);
			}
		}
		return (-1.0) * sum;
	}

	/**
	 * Entropia w bitach
	 * @param tabl - tablica prawdopodobieństw stanów
	 * @return - entropię w bitach
	 */
	public static double entropiaB(double[] tabl) {
		double sum = 0;
		for (double aTabl : tabl) {
			if (aTabl != 0) {
				sum += aTabl * MathUtil.log(aTabl, 2);
			}
		}
		return (-1.0) * sum;
	}

	/**
	 * Ilość informacji przekazywanej przez system
	 * @param tabl - tablica prawdopodobieństw
	 * @return - ilość informacji w bitach/stan
	 */
	public static double sredniaInformacja(double[] tabl) {
		double sum = 0;
		for (double aTabl : tabl) {
			if (aTabl != 0) {
				sum += aTabl * MathUtil.log(1.0 / aTabl, 2);
			}
		}
		return sum;
	}

	/**
	 * Ilość informacji przekazywanej przez system
	 * @param tabl - tablica prawdopodobieństw
	 * @param n - liczebnosc populacji
	 * @return - średnia ilość informacji w bitach/stan
	 */
	public static double sredniaInformacja(double[][] tabl, double n) {
		int r = tabl.length;//liczba rzedow
		double[] temp = new double[r];
		double[] entropia = new double[r];
		double[] czestosc = new double[r];
		for(int i = 0; i < r; i++){
			for(int j = 0; j < r; j++){
				czestosc[i] += tabl[i][j];
			}
		}
		for(int k = 0; k < czestosc.length; k++){
			czestosc[k] = czestosc[k] / n;
		}
		for(int l = 0; l < r; l++){
			for(int m = 0; m < r; m++){
				temp[m] = tabl[m][l];
			}
			entropia[l] = InfoUtil.entropiaB(temp);
		}
		double sum = 0;
		double sum2 = 0;
		for(int o = 0; o < entropia.length; o++){
			sum += entropia[o] * czestosc[o];
			sum2 += czestosc[o];
		}
		return sum / sum2;
	}
}
