/* * To change this template, choose Tools | Templates * and open the template in the editor. */ package sim.app.socialsystems2; import java.util.Enumeration; import java.util.Hashtable; import java.util.Random; /** * * @author epokh */ public class EntropyString { private static double[] inputDist; //a word made of symbols from an alphabet private String Xword; private String lastMotorWord; private String Yword; private String lastSensorWord; private String XYword; //the word size= how long is the word in terms of symbols private int sensor_wordsize=0; //the word size= how long is the word in terms of symbols private int motor_wordsize=0; //a frequency table to remember symbol occurencies for predictive signal private Hashtable Yf ; //a frequency table to remember symbol occurencies for reflex signal private Hashtable Xf ; //a frequency table for joint occurencies for the X and Y word private Hashtable XYf ; //number of samples for the X variable private int NX=0; //number of samples for the Y variable private int NY=0; //number of samples for the XY variable private int NXY=0; //entropy for X and Y variables private double HX=0; private double HY=0; //joint entropy H(X,Y) private double HXY=0; //binary representation length: default is 8 bits private int BASE=8; private boolean normalize; private double estimate=0; private double sigma=0;; private double nybias; private String approach; private double upperbound=Math.pow(2,BASE); private double lowerbound=0; private double lambda; private double nxbias; private double nxybias; private int X_BASE; private int Y_BASE; private SparseMatrix XYsparse; static double acceptableError = 0.000000000001; static int noOfIterations = 5000; EntropyString(int multiple, boolean flag, String method) { //initialize the hastable for frequency lookup Yf=new Hashtable(); Xf=new Hashtable(); XYf=new Hashtable(); //the X and Y word have the same word size for consistency sensor_wordsize=multiple*BASE; motor_wordsize=multiple*BASE; X_BASE=BASE; Y_BASE=BASE; XYsparse=new SparseMatrix(motor_wordsize, sensor_wordsize); Xword=new String(); Yword=new String(); XYword=new String(); normalize=flag; approach=method.substring(0, 1); approach.toLowerCase(); } public void setBase(int xwordbase,int ywordbase,int motor_wordsize,int sensor_wordsize) { X_BASE=xwordbase; Y_BASE=ywordbase; this.motor_wordsize=X_BASE*motor_wordsize; this.sensor_wordsize=Y_BASE*sensor_wordsize; XYsparse=new SparseMatrix(X_BASE*motor_wordsize, Y_BASE*sensor_wordsize); } //add a symbol in the buffer and when the word size is reached put in the table public boolean lastMotorWord(int value) { String symbol=toLZ(value, X_BASE); //[FIX] the symbol must be enforced: symbol must belong in the alphabet if(Xword.length()==0) { Xword=symbol; } else if(Xword.length()<motor_wordsize) { Xword=Xword+symbol; } if(Xword.length()==motor_wordsize) { //push_X(Xword); lastMotorWord=Xword; Xword=""; return true; }else return false; } //add a symbol in the buffer and when the word size is reached put in the table public boolean addSensorSymbol(int value) { String symbol=toLZ(value, Y_BASE); //[FIX] the symbol must be enforced: symbol must belong in the alphabet if(Yword.length()==0) { Yword=symbol; } else if(Yword.length()<sensor_wordsize) { Yword=Yword+symbol; } if(Yword.length()==sensor_wordsize) { //push_Y(Yword); lastSensorWord=Yword; Yword=""; return true; } else return false; } //add a symbol in the buffer and when the word size is reached put in the table public void addEmpoweredSymbol(int motor, int sensor) { //every n motor words are pushed add the sensor word if (lastMotorWord(motor)) { addSensorSymbol(sensor); String symbol = lastMotorWord + lastSensorWord; //[FIX] the symbol must be enforced: symbol must belong in the alphabet if (XYword.length() == 0) { XYword = symbol; } else if (XYword.length() < (motor_wordsize + sensor_wordsize)) { XYword = XYword + symbol; } if (XYword.length() == (motor_wordsize + sensor_wordsize)) { //push_XY(XYword); XYsparse.add(lastSensorWord, lastMotorWord, 1); XYword = ""; } } } //add a symbol in the buffer and when the word size is reached put in the table public void addXYSymbol(int xvalue,int yvalue) { lastMotorWord(xvalue); addSensorSymbol(yvalue); String symbol_x=toLZ(xvalue, BASE); String symbol_y=toLZ(yvalue, BASE); String symbol=symbol_y+symbol_x; //[FIX] the symbol must be enforced: symbol must belong in the alphabet if(XYword.length()==0) { XYword=symbol; } else if(XYword.length()<(motor_wordsize+sensor_wordsize)) { XYword=XYword+symbol; } if(XYword.length()==(motor_wordsize+sensor_wordsize)) { push_XY(XYword); XYword=""; } } //push the joint variable XY in the frequency table: used for joint distribution private void push_XY(String word) { //if this word has already occurred incremente the frequency if(XYf.containsKey(word)) { //increase the frequency count Integer frequency=(Integer)XYf.get(word); frequency++; XYf.remove(word); XYf.put(word,frequency); }//if it has not yet occurred else { //set to 1 XYf.put(word, new Integer(1)); } //increment the number of total observations NXY++; } private void push_X(String word) { //if this word has already occurred incremente the frequency if(Xf.containsKey(word)) { //increase the frequency count Integer frequency=(Integer)Xf.get(word); frequency++; Xf.remove(word); Xf.put(word,frequency); }//if it has not yet occurred else { //set to 1 Xf.put(word, new Integer(1)); } //increment the number of total observations NX++; } private void push_Y(String word) { //if this word has already occurred incremente the frequency if(Yf.containsKey(word)) { //increase the frequency count Integer frequency=(Integer)Yf.get(word); frequency++; Yf.remove(word); Yf.put(word,frequency); }//if it has not yet occurred else { //set to 1 Yf.put(word, new Integer(1)); } //increment the number of total observations NY++; } public double getYEntropy_old(int base) { //reset the main variables estimate=0; sigma=0; NY=0; upperbound=Math.pow(2, Y_BASE); //get the list of words Enumeration e = Yf.keys(); double nbins=Yf.size(); while (e.hasMoreElements()) { //the number of occurencies for that word Integer hn = (Integer) Yf.get(e.nextElement()); //the histogram count double logf = 0; if (hn != 0) { logf = Math.log(hn); } NY = NY + hn; estimate = estimate - hn * logf; sigma = sigma + hn * logf * logf; } //return the biased estimate of entropy estimate=estimate/(double)NY; sigma =Math.sqrt( (sigma/(double)NY-Math.pow(estimate,2))/((double)NY-1) ); estimate=estimate+Math.log(NY);//+Math.log((upperbound-lowerbound)/nbins); nybias =-(nbins-1)/(2*(double)NY); //conversion to unbiased estimate if (approach.equals("u")) { estimate=estimate-nybias; nybias=0; } //conversion to minimum mse estimate if(approach.equals("m")) {estimate=estimate-nybias; nybias=0; lambda=Math.pow(estimate,2)/(Math.pow(estimate,2)+Math.pow(sigma,2)); nybias =(1-lambda)*estimate; estimate=lambda*estimate; sigma =lambda*sigma; } //base transformation if(base>0) {estimate=estimate/Math.log(base); nybias =nybias /Math.log(base); sigma =sigma /Math.log(base); } HY=estimate; return estimate; } public double getXEntropy(boolean biased, int base) { return XYsparse.getXEntropy(biased, base); } public double getYEntropy(boolean biased,int base) { return XYsparse.getYEntropy(biased, base); } public double getXEntropy_old(int base) { //reset the main variables estimate=0; sigma=0; NX=0; upperbound=Math.pow(2, X_BASE); //get the list of words Enumeration e = Xf.keys(); double nbins=Xf.size(); while (e.hasMoreElements()) { //the number of occurencies for that word Integer hn = (Integer) Xf.get(e.nextElement()); //the histogram count double logf = 0; if (hn != 0) { logf = Math.log(hn); } NX = NX + hn; estimate = estimate - hn * logf; sigma = sigma + hn * logf * logf; } //return the biased estimate of entropy estimate=estimate/(double)NX; sigma =Math.sqrt( (sigma/(double)NX-Math.pow(estimate,2))/((double)NX-1) ); estimate=estimate+Math.log(NX);//Math.log((upperbound-lowerbound)/nbins); nxbias =-(nbins-1)/(2*(double)NX); //conversion to unbiased estimate if (approach.equals("u")) { estimate=estimate-nxbias; nxbias=0; } //conversion to minimum mse estimate if(approach.equals("m")) {estimate=estimate-nybias; nxbias=0; lambda=Math.pow(estimate,2)/(Math.pow(estimate,2)+Math.pow(sigma,2)); nxbias =(1-lambda)*estimate; estimate=lambda*estimate; sigma =lambda*sigma; } //base transformation if(base>0) {estimate=estimate/Math.log(base); nxbias =nxbias /Math.log(base); sigma =sigma /Math.log(base); } HX=estimate; return estimate; } public double getXYEntropy(boolean biased,int base) { return XYsparse.computeJointEntropy(biased, base); } public double getXYEntropy_old(boolean biased,int base) { //reset the main variables estimate=0; sigma=0; NXY=0; //get the list of words Enumeration e = XYf.keys(); double nbins=XYf.size(); while( e. hasMoreElements() ){ //the number of occurencies for that word Integer hn=(Integer) XYf.get(e.nextElement()); //the histogram count double logf=0; if(hn!=0) logf=Math.log(hn); else logf=0; NXY=NXY+hn; estimate=estimate-hn*logf; sigma=sigma+hn*logf*logf; } //return the biased estimate of entropy estimate=estimate/(double)NXY; sigma =Math.sqrt( (sigma/(double)NXY-Math.pow(estimate,2))/((double)NXY-1) ); estimate=estimate+Math.log(NXY);//+Math.log((upperbound-lowerbound)/nbins); nxybias =-(nbins-1)/(2*(double)NXY); //conversion to unbiased estimate if (approach.equals("u")) { estimate=estimate-nxybias; nxybias=0; } //conversion to minimum mse estimate if(approach.equals("m")) {estimate=estimate-nxybias; nxybias=0; lambda=Math.pow(estimate,2)/(Math.pow(estimate,2)+Math.pow(sigma,2)); nxybias =(1-lambda)*estimate; estimate=lambda*estimate; sigma =lambda*sigma; } //base transformation if(base>0) {estimate=estimate/Math.log(base); nxybias =nxybias /Math.log(base); sigma =sigma /Math.log(base); } HXY=estimate; return estimate; } public double getConditionedEntropy(int base) { double hxy=-getXEntropy(false,base)+getXYEntropy(false,base); return hxy; } public double getMutualInformation(boolean biased,int base) { //double hxy=getXEntropy(base)+getYEntropy(base)-getXYEntropy(base); return XYsparse.computeMutualInfo(biased, 2); //return getXEntropy(base)+getYEntropy(base)-getXYEntropy(base); } public static String toLZ( int discretized, int len ) { // converts integer to left-zero padded string, len chars long. String s = Integer.toBinaryString(discretized); if ( s.length() > len ) return s.substring(0,len); else if ( s.length() < len ) // pad on left with zeros return "000000000000000000000000000".substring(0, len - s.length ()) + s; else return s; } // end toLZ public static String toLZ( int[] discretized, int len ) { // converts integer to left-zero padded string, len chars long. String compose=""; for(int k=0;k<discretized.length;k++) {String s=Integer.toBinaryString(discretized[k]); if ( s.length() > len ) compose=compose + s.substring(0,len); else if ( s.length() < len ) // pad on left with zeros compose=compose+("000000000000000000000000000".substring(0, len - s.length ()) + s); else compose=compose+s;} return compose; } // end toLZ public static void generateFrequencies(int p00,int p01,int p10,int p11, EntropyString test) { for (int k = 1; k <= 100; k++) { if (p00 > 0) { test.addXYSymbol(0, 0); p00--; } if (p01 > 0) { test.addXYSymbol(0, 1); p01--; } if (p10 > 0) { test.addXYSymbol(1, 0); p10--; } if (p11 > 0) { test.addXYSymbol(1, 1); p11--; } } } public double getChannelCapacity() { return XYsparse.computeChannelCapacity("p(sensor|action)"); } public static void testChannelCapacity() { // Read the channel matrix using the ReadChannelFile Class boolean readFromChanFile = true; boolean miUniform = false; ReadFile channelFileReader = new ReadFile("/home/epokh/test.csv"); channelFileReader.readChannel(); Channel channel = channelFileReader.getChannel(); // Switch on the kind of channel and calculate capacity accordingly. // Channels can be basic, conditional or multi-user. BlahutArimoto ba = new BlahutArimoto(channel, acceptableError, noOfIterations); double result = 0.0; switch (channel.kind) { case (Channel.BASIC): // Find capacity or mutual information of a basic channel if (miUniform == true) { result = IT.MIuniformInput(channel.getMatrix()); inputDist = IT.unifromDist(channel.noOfInputs()); } else { ba.calculateCapacity(); result = ba.getCapacity(); inputDist = ba.getMaxInputDist(); } break; default: } if (ba.possibleError == 0) { System.out.println(" Complete, after " + ba.iteration + " iterations"); } else if (ba.possibleError <= ba.acceptableError) { System.out.println(" Capacity calculated to within acceptable error, in " + ba.iteration + " iterations"); } else if (ba.possibleError > ba.acceptableError) { System.out.println(" NOT COMPLETE: Performed the maximum number of iterations: " + ba.iteration + "\n" + " and still not with acceptable error rate\n " + " increase the maximum number of iterations (with flag -i <int>)\n" + " or increase the acceptable error (with flag -e <double>"); } System.out.printf(" The Channel Capacity is: %1$6.5g +/- %2$6.5g", (result + (ba.possibleError / 2)), (ba.possibleError / 2)); System.out.printf(" and there are " + channel.noOfInputs() + " possible input events\n"); } public static void testLearningEntropy() { EntropyString test=new EntropyString(1,true,"biased"); //before learning as in paper: 40% and 10% in a total of 100 samples int p00=40; int p01=10; int p10=10; int p11=40; generateFrequencies(p00, p01, p10, p11, test); System.out.println("H(X)="+test.getXEntropy(true,2)); System.out.println("H(Y)="+test.getYEntropy(true,2)); System.out.println("H(X,Y)="+test.getXYEntropy(true,2)); System.out.println("I(X,Y)="+test.getMutualInformation(true,2)); test=new EntropyString(1,true,"biased"); p00=40; p01=40; p10=10; p11=10; generateFrequencies(p00, p01, p10, p11, test); System.out.println("Good learning"); System.out.println("H(X)="+test.getXEntropy(true,2)); System.out.println("H(Y)="+test.getYEntropy(true,2)); System.out.println("H(X,Y)="+test.getXYEntropy(true,2)); System.out.println("I(X,Y)="+test.getMutualInformation(true,2)); test=new EntropyString(1,true,"biased"); p00=50; p01=50; p10=0; p11=0; generateFrequencies(p00, p01, p10, p11, test); System.out.println("Perfect learning"); System.out.println("H(X)="+test.getXEntropy(true,2)); System.out.println("H(Y)="+test.getYEntropy(true,2)); System.out.println("H(X,Y)="+test.getXYEntropy(true,2)); System.out.println("H(X|Y)="+test.getConditionedEntropy(2)); System.out.println("I(X,Y)="+test.getMutualInformation(true,2)); test=new EntropyString(1,true,"biased"); p00=25; p01=25; p10=25; p11=25; generateFrequencies(p00, p01, p10, p11, test); System.out.println("Imperfect learning"); System.out.println("H(X)="+test.getXEntropy(true,2)); System.out.println("H(Y)="+test.getYEntropy(true,2)); System.out.println("H(X,Y)="+test.getXYEntropy(true,2)); System.out.println("H(X|Y)="+test.getConditionedEntropy(2)); System.out.println("I(X,Y)="+test.getMutualInformation(true,2)); } public static void testMutualInfo() { EntropyString test=new EntropyString(0,true,"biased"); test.setBase(3,2,1,1); Random generator = new Random(); for(int k=1;k<=100;k++) { test.addEmpoweredSymbol(generator.nextInt(8), generator.nextInt(4)); } System.out.println("MI: "+test.getMutualInformation(true,2)); System.out.println("H(X,Y): "+test.getXYEntropy(true,2)); System.out.println("H(X): "+test.getXEntropy(true,2)); System.out.println("H(Y): "+test.getYEntropy(true,2)); test=new EntropyString(0,true,"biased"); test.setBase(3,2,1,1); for(int k=1;k<=100;k++) { if(generator.nextBoolean()) test.addEmpoweredSymbol(0, 1); else test.addEmpoweredSymbol(1, 1); } System.out.println("MI: "+test.getMutualInformation(true,2)); System.out.println("H(X,Y): "+test.getXYEntropy(true,2)); System.out.println("H(X): "+test.getXEntropy(true,2)); System.out.println("H(Y): "+test.getYEntropy(true,2)); } public static void main(String[] args){ testMutualInfo(); } }