Wednesday, February 11, 2015

Knight Moves Problem in Java

In this text, i represent a solution for Knight Moves Problem in java. The problem is defined as follows:


Pictured here is a keypad:

We want to find all sequences of length n that can be keyed into the keypad in the following manner:
  • The initial keypress can be any of the keys.
  • Each subsequent keypress must be a knight move from the previous keypress. 
  • There can be at most 2 vowels in the sequence.
  • Run your solution for n = 1 to 32
A knight move is made in one of the following ways:
  • Move two steps horizontally and one step vertically.
  • Move two steps vertically and one step horizontally.
  • There is no wrapping allowed on a knight move.
Here are some examples of knight moves:


Given a value for n, the program should write the number of valid n-key sequences on a single line to standard out.


Knight Moves Solution

package com.denizstij.km;

import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import com.denizstij.km.Keyboard.Key;
/**
 * 
 * @author Deniz Turan, http://denizstij.blogspot.co.uk denizstij AT gmail.com
 * 
 */
public class KnightMoveMain {
 private final int maxVowelCount;
 
 public KnightMoveMain(int maxVowelCount){
  this.maxVowelCount=maxVowelCount;
 }
 
 public long findNumberOfSequence(int lenOfSequence) {
  if (lenOfSequence<=0){   
   return 1;// number of empty set is 1
  }
  Map <PathInfoBean, Long> pathInfoMap= new LinkedHashMap<PathInfoBean, Long>();
  for (Key key : Keyboard.INSTANCE.getKeySet()) {   
   PathInfoBean pathinfo= new PathInfoBean(key, key.isVowel()?1:0);
   pathInfoMap.put(pathinfo, 1L);
  }
  
  long numberOfPaths = findNumberOfSequence1(pathInfoMap,1,lenOfSequence);
  return numberOfPaths;
 }
 
 private long findNumberOfSequence1(Map <PathInfoBean, Long> pathInfoMap ,int sequenceLen, int lenOfSequence) {

  if (sequenceLen>=lenOfSequence){
   long numberOfPaths=0;
   for (Long pathCount : pathInfoMap.values()) {   
    numberOfPaths+=pathCount;
   }      
   return numberOfPaths;
  }   
   
  Map <PathInfoBean, Long> pathInfoMapNew= new LinkedHashMap<PathInfoBean, Long>();
  for (Entry<PathInfoBean, Long> pathInfoBeanEntry : pathInfoMap.entrySet()) {
   PathInfoBean pathInfoBean = pathInfoBeanEntry.getKey();

   Long pathCount = pathInfoBeanEntry.getValue();
   Set<key> possibleMoveSet =pathInfoBeanEntry.getKey().getKey().getKnightMoves();
     
   for (Key key : possibleMoveSet) {
    int vowelCount=pathInfoBean.getVowelCount();
    if (key.isVowel()){
     if (vowelCount>=maxVowelCount){
      continue;
     } 
     vowelCount++;
    }
    PathInfoBean newPathInfoBean = new PathInfoBean(key,vowelCount);  
    Long currentPath = pathInfoMapNew.get(newPathInfoBean);
    if (currentPath==null)  // first time 
     pathInfoMapNew.put(newPathInfoBean,pathCount);
    else {
     // we have already, so just lets aggregate both branch
     pathInfoMapNew.put(newPathInfoBean,currentPath+pathCount);
    }
   }   
  }
  return findNumberOfSequence1(pathInfoMapNew,sequenceLen+1,lenOfSequence);
 }  
 
 public static void main(String[] args) {  
  KnightMoveMain km= new KnightMoveMain(2);
  long now = System.currentTimeMillis();
  for (int n=0;n<=32;n++) {
   long numberOfPaths = km.findNumberOfSequence(n);
   System.out.println(n+"==>"+numberOfPaths);   
  }
  long elapsedTime = System.currentTimeMillis()-now;
  System.out.println("Total Elapsed Time (msec):"+elapsedTime);
 }
}

//###############################################################
//###############################################################
//###############################################################

package com.denizstij.km;

import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.Set;
/**
 * 
 * @author Deniz Turan, http://denizstij.blogspot.co.uk denizstij AT gmail.com
 * 
 */
public class Keyboard{

 final private  Set <key> KEYSET= new LinkedHashSet<key>();    
 final public static Key A= new Key('A', true);
 final public static Key B= new Key('B', false);
 final public static Key C= new Key('C', false);
 final public static Key D= new Key('D', false);
 final public static Key E= new Key('E', true);
 final public static Key F= new Key('F', false);
 final public static Key G= new Key('G', false);
 final public static Key H= new Key('H', false);
 final public static Key I= new Key('I', true);
 final public static Key J= new Key('J', false);
 final public static Key K= new Key('K', false);
 final public static Key L= new Key('L', false);
 final public static Key M= new Key('M', false);
 final public static Key N= new Key('N', false);
 final public static Key O= new Key('O', true);
 final public static Key _1= new Key('1', false);
 final public static Key _2= new Key('2', false);
 final public static Key _3= new Key('3', false);

 final public static Keyboard INSTANCE= new Keyboard();

  private void init(){  
  KEYSET.add(A.setKnightMoves(H,L));
  KEYSET.add(B.setKnightMoves(I,K,M));
  KEYSET.add(C.setKnightMoves(F,J,L,N));
  KEYSET.add(D.setKnightMoves(G,M,O));
  KEYSET.add(E.setKnightMoves(H,N));
  KEYSET.add(F.setKnightMoves(C,M,_1));
  KEYSET.add(G.setKnightMoves(D,N,_2));
  KEYSET.add(H.setKnightMoves(A,E,K,O,_1,_3));
  KEYSET.add(I.setKnightMoves(B,L,_2));
  KEYSET.add(J.setKnightMoves(C,M,_3));
  KEYSET.add(K.setKnightMoves(B,H,_2));
  KEYSET.add(L.setKnightMoves(A,C,I,_3));
  KEYSET.add(M.setKnightMoves(B,D,F,J));
  KEYSET.add(N.setKnightMoves(C,E,G,_1));
  KEYSET.add(O.setKnightMoves(D,H,_2));
  KEYSET.add(_1.setKnightMoves(F,H,N));
  KEYSET.add(_2.setKnightMoves(G,I,K,O));
  KEYSET.add(_3.setKnightMoves(H,J,L));   
 }
 
 // Singleton
 private Keyboard(){
  init();
 }

public Set <key> getKeySet() {
  return KEYSET;
 }

public static class Key{
 final private char key;
 final private boolean isVowel;
 private Set<key> knightMoves;
 
 Key(char key, boolean isVowel){
  this.key=key;
  this.isVowel=isVowel;
 }

 public Key setKnightMoves(Key ...knightMoves) {
  this.knightMoves=Collections.unmodifiableSet(new HashSet<key>(Arrays.asList(knightMoves)));
  return this;
 }

 public Set<key> getKnightMoves() {
  return knightMoves;
 }

 @Override
 public int hashCode() {
  final int prime = 31;
  int result = 1;
  result = prime * result + key;
  return result;
 }

 @Override
 public boolean equals(Object obj) {
  if (this == obj)
   return true;
  if (obj == null)
   return false;
  if (getClass() != obj.getClass())
   return false;
  Key other = (Key) obj;
  if (key != other.key)
   return false;
  return true;
 }
 public char getKey() {
  return key;
 }
 
 public boolean isVowel() {
  return isVowel;
 }
 @Override
 public String toString() {
  return "Key [key=" + key + ", isVowel=" + isVowel +"]";
 }
}
}

//###############################################################
//###############################################################
//###############################################################

package com.denizstij.km;

import com.denizstij.km.Keyboard.Key;

/**
 * 
 * @author Deniz Turan, http://denizstij.blogspot.co.uk denizstij AT gmail.com
 * 
 */
public class PathInfoBean {
 final private Key key; 
 final private int vowelCount;
 
 public PathInfoBean(Key key, int vowelCount) {   
  this.key = key;
  this.vowelCount = vowelCount;
 }
 
 public Key getKey() {
  return key;
 }
 
 public int getVowelCount() {
  return vowelCount;
 }


 @Override
 public int hashCode() {
  final int prime = 31;
  int result = 1;
  result = prime * result + ((key == null) ? 0 : key.hashCode());
  result = prime * result + vowelCount;
  return result;
 }

 @Override
 public boolean equals(Object obj) {
  if (this == obj)
   return true;
  if (obj == null)
   return false;
  if (getClass() != obj.getClass())
   return false;
  PathInfoBean other = (PathInfoBean) obj;
  if (key == null) {
   if (other.key != null)
    return false;
  } else if (!key.equals(other.key))
   return false;
  if (vowelCount != other.vowelCount)
   return false;
  return true;
 }
 
 @Override
 public String toString() {
  return "PathInfoBean [key=" + key + ", vowelCount=" + vowelCount + "]\n";
 }
}

Output
1==>18
2==>60
3==>214
4==>732
5==>2486
6==>8392
7==>27912
8==>93204
9==>306288
10==>1013398
11==>3302640
12==>10842528
13==>35108325
14==>114492546
15==>368772182
16==>1195650888
17==>3833937659
18==>12367469662
19==>39505386940
20==>126863960276
21==>403894417802
22==>1291845025388
23==>4100838894764
24==>13069438426724
25==>41380854190503
26==>131455706155352
27==>415265140628246
28==>1315326269976050
29==>4146551571701468
30==>13098978945964762
31==>41218021719932582
32==>129891093550589788

Total Elapsed Time (msec):450

Tuesday, February 10, 2015

Estimating Pi number with Monte Carlo Simulation in Java and Kdb+ q

package com.denizstij.montecarlo.sim;
 
import java.util.Random;
 
/**
*  This class estimates Pi with monte carlo simulation.
* 
 *  We assume we have a square with dimension 1x1 which contains a disk in middle with radious of 0.5
*  where it touches the square on 4 edges. We generate N number of pairs (x,y) between 0 and 1.
 *  Then we check if each pair is in the circle or not. 4 times ratio of total pairs in circle
*  to total simulation is an estimation of Pi. 
 * 
 *  pi=4*(total pairs in circle)/total pairs
* 
 * @author Deniz Turan, http://denizstij.blogspot.co.uk, denizstij AT gmail.com
*
 */
public class PIEstimationWithMonteCarloSimulation {
       // number of total simulation
       private static final long TOTAL_SIMULATION=10000000L;
      
       private double estimatePI(){            
              double pi=0;
              Random randomGen= new Random();
              long inCircleCounter=0;
              for (int i=0;i<TOTAL_SIMULATION;i++){
                     // generate pairs
                     double x = randomGen.nextDouble();
                     double y = randomGen.nextDouble();
                     // check if the pair  in the circle
                     inCircleCounter+=isInCircle(x,y);
              }
              double ratio=(double)inCircleCounter/TOTAL_SIMULATION;
              pi=ratio*4;
              return pi;
       }
      
       /*
       *  Check given two points in a circle: x^2+y^2<=1
       */
       private int isInCircle(double x, double y) {
              double z=Math.sqrt(x*x+y*y);            
              return z<=1?1:0;
       }
 
       public static void main(String[] args) {
              PIEstimationWithMonteCarloSimulation est= new PIEstimationWithMonteCarloSimulation();
              double estimatedPI = est.estimatePI();
              System.out.println("Estimated PI:"+estimatedPI);
       }
}
And now in Kdb+ q :
piEst:{[N]
        sqrArea:4;                                  / area of square with length 2 and containing a circle with radius 1
        xy:flip {2?1.0} each til N;                 / xy points
        p:sqrt sum xy*xy;                           / sqrt(x^2+y^2) <=1 to be in a circle
        totalIncircle: sum p<=1;
        piEst:sqrArea*totalIncircle%N;                    / that’s the estimation of PI
        :piEst
}
q)piEst[1000000]
3.141476
Above code can be reduced to one line such as:
q)N:10000000
q)(1%N)*4*sum 1>=sqrt sum ({x*x}') each flip {2?1.0} each til N
3.141842

Monday, February 09, 2015

Generating random numbers from a given set of numbers according to a distribution in java

Recently i am asked to implement following in Java based on the below interface:

Implement the method nextNum() and a minimal but effective set of unit tests.  As a quick check, given Random Numbers are [-1, 0, 1, 2, 3] and Probabilities are [0.01, 0.3, 0.58, 0.1, 0.01] if we call nextNum() 100 times we may get the following results. As the results are random, these particular results are unlikely.

-1: 1 times
0: 22 times
1: 57 times
2: 20 times
3: 0 times
public class RandomGen {
 // Values that may be returned by nextNum()
 private int[] randomNums;
 // Probability of the occurence of randomNums
 private float[] probabilities;

 /**
 Returns one of the randomNums. When this method is called
 multiple times over a long period, it should return the
 numbers roughly with the initialized probabilities.
 */
 public int nextNum() {

 }
}
Solution:
package com.denizstij.rand;

import java.util.Arrays;
import java.util.Random;
/**
 * @author Deniz Turan, http://denizstij.blogspot.co.uk denizstij AT gmail.com
 */
public class RandomGen {
	// Values that may be returned by nextNum()
	private int[] randomNums;
	// Probability of the occurence of randomNums
	private float[] probabilities;
	private float[] cumProbabilities;
	private int[] validRandomNums;
	private int totalNonZeroProbElement=0;
	private Random random;
	
	public RandomGen(int[] randomNums,float[] probabilities){
		validateProcessInputs(randomNums,probabilities);
		random= new Random();
	}
	
	public RandomGen(int[] randomNums,float[] probabilities, long seed){
		validateProcessInputs(randomNums,probabilities);
		random= new Random(seed);
	}
		
	private void validateProcessInputs(int[] randomNums,float[] probabilities){			
		if (randomNums==null || probabilities==null || randomNums.length!= probabilities.length || probabilities.length==0){
			throw new IllegalArgumentException("RandomNums and probabilities must be non empty and same size");
		}
		
		int len=probabilities.length;
		cumProbabilities= new float[len];
		validRandomNums= new int[len];
				
		for (int i=0;i < len;i++) {			
			float prob = probabilities[i];
			int randomNum = randomNums[i];
			if (MathUtil.isLess(prob,0.0f)){
				throw new IllegalArgumentException("Probability can not be negative");
			}
			
			if (MathUtil.isGreater(prob,1.0f)){
				throw new IllegalArgumentException("Probability can not be greater than 1");
			}
			
			if (MathUtil.checkAnyIsNanOrInfinite(prob)){
				throw new IllegalArgumentException("Nan or Infite prob is not accepted");
			}

			// not processing elements with zero probabilities as they can not occur
			if (MathUtil.isEqual(prob, 0.0f)){
				continue;
			}
			// store valid random number
			validRandomNums[totalNonZeroProbElement]=randomNum;
			if (totalNonZeroProbElement==0){
				cumProbabilities[totalNonZeroProbElement]=prob;				
			} else {
				cumProbabilities[totalNonZeroProbElement]=prob+cumProbabilities[totalNonZeroProbElement-1];				
			}			
			if (MathUtil.isGreater(cumProbabilities[totalNonZeroProbElement],1.0f)){
				throw new IllegalArgumentException("Cumilative total probability can not be greater than 1");
			}
			totalNonZeroProbElement++;
		}
		
		if (totalNonZeroProbElement==0){
			throw new IllegalArgumentException("All probabilities are zero :(");
		}
		
		if (!MathUtil.isEqual(cumProbabilities[totalNonZeroProbElement-1],1.0f)){
			throw new IllegalArgumentException("Total probability must be 1");
		}

		// let's shrink arrays to save memory
		this.validRandomNums=Arrays.copyOf(validRandomNums, totalNonZeroProbElement);
		this.cumProbabilities=Arrays.copyOf(cumProbabilities, totalNonZeroProbElement); 
		this.randomNums=randomNums;
		this.probabilities=probabilities;
		
		// some logging 
		System.out.println("RandomNums :"+Arrays.toString(this.randomNums));
		System.out.println("probabilities :"+Arrays.toString(this.probabilities));
		System.out.println("totalNonZeroProbElement:"+totalNonZeroProbElement);
		System.out.println("validRandomNums :"+Arrays.toString(validRandomNums));
		System.out.println("cumProbabilities :"+Arrays.toString(cumProbabilities));				
	}
	
	/**
	Returns one of the randomNums. When this method is called
	multiple times over a long period, it should return the
	numbers roughly with the initialized probabilities.
	*/
	public int nextNum() {
		float nextFloat = random.nextFloat();
		return nextNum(nextFloat);
	}
	
	/**
	Returns one of the randomNums. When this method is called
	multiple times over a long period, it should return the
	numbers roughly with the initialized probabilities.
	*/
	// For testing purposes 
	protected int nextNum(float nextFloat) {		
		int index = Arrays.binarySearch(cumProbabilities,nextFloat);
		// if not found in the cum probability array, we need to infer index from insertation index 
		if (index<0 code="" index="-1*index-1;" int="" nextrandomval="" return="">

package com.denizstij.rand;

/**
 * @author Deniz Turan, http://denizstij.blogspot.co.uk denizstij@gmail.com
 */
public class MathUtil {
	public static final float FLOAT_COMPARE_RESOLUTION=0.00001f;	
	
	public static boolean isEqual(float val1, float val2) {		
		if (Math.abs(val1-val2)<FLOAT_COMPARE_RESOLUTION){
			return true;
		}				
		return false;
	}
	
	public static boolean isLess(float val1, float val2) {
		if (isEqual(val1,val2)){
			return false;
		}
		return val1<val2;
	}
	
	public static boolean isLessEqual(float val1, float val2) {
		if (isEqual(val1,val2)){
			return true;
		}
		return val1<val2;
	}
	
	public static boolean isGreater(float val1, float val2) {
		if (isEqual(val1,val2)){
			return false;
		}
		return val1>val2;
	}
	
	public static boolean isGreaterEqual(float val1, float val2) {
		if (isEqual(val1,val2)){
			return true;
		}
		return val1>val2;
	}
	
	public static boolean checkAnyIsNanOrInfinite(float ...values){
		for (float val : values) {
			if (Float.isNaN(val) || Float.isInfinite(val)){
				return true;
			}
		}
		return false;
	}
}
Junit Test:

package com.denizstij.rand.test;

import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Map.Entry;

import org.junit.Assert;
import org.junit.Test;

import com.denizstij.rand.RandomGen;

/**
 * @author Deniz Turan, http://denizstij.blogspot.co.uk denizstij@gmail.com
 */
public class RandomGenTest {
	private static final float SIM_PROB_THRESHOLD = 0.001f;

	@Test(expected=IllegalArgumentException.class)
	public void testNullInputs() {
		int[] randomNums=null;
		float[] probabilities=null;
		new RandomGen(randomNums, probabilities);		
	}

	@Test(expected=IllegalArgumentException.class)
	public void testEmptyArray() {
		int[] randomNums= new int[0];
		float[] probabilities=new float[0];
		new RandomGen(randomNums, probabilities);		
	}

	@Test(expected=IllegalArgumentException.class)
	public void testDifferentSizeNumsAndProbs() {
		int[] randomNums= {1};
		float[] probabilities={0.3f,0.4f};
		new RandomGen(randomNums, probabilities);		
	}
	
	@Test(expected=IllegalArgumentException.class)
	public void testProbsAndNumberArrayDifferentSize() {
		int[] randomNums= {1};
		float[] probabilities={0.3f,0.4f};
		new RandomGen(randomNums, probabilities);		
	}
	
	@Test(expected=IllegalArgumentException.class)
	public void testProbsIsNotNegative() {
		int[] randomNums= {1,2};
		float[] probabilities={0.3f,-0.4f};
		new RandomGen(randomNums, probabilities);		
	}
	
	@Test(expected=IllegalArgumentException.class)
	public void testProbsAllZero() {
		int[] randomNums= {1,2};
		float[] probabilities={0.0f,0.0f};
		new RandomGen(randomNums, probabilities);		
	}
	
	@Test(expected=IllegalArgumentException.class)
	public void testProbArrayHasNaN() {
		int[] randomNums= {1,2};
		float[] probabilities={Float.NaN,0.4f};
		new RandomGen(randomNums, probabilities);		
	}	
	
	@Test(expected=IllegalArgumentException.class)
	public void testProbsIsNotGreaterThanOne() {
		int[] randomNums= {1,2};
		float[] probabilities={0.3f,1.4f};
		new RandomGen(randomNums, probabilities);		
	}
	
	@Test(expected=IllegalArgumentException.class)
	public void testProbsTotalIsNotOne() {
		int[] randomNums= {1,2};
		float[] probabilities={0.3f,0.4f};
		new RandomGen(randomNums, probabilities);		
	}	
	
	@Test
	public void testCumulativeProbLogic() {
		int[] randomNums= {-1,-2,-4,3410,893,9,343,10};
		float[] probabilities={0.0f,0.0f,0.0f,0.3f,0.5f,0.0f,0.2f,0.0f};
		//validRandomNums :[3410, 893, 343]
		//cumProbabilities :[0.3, 0.8, 1.0]
		RandomGenWrapper randomGen = new RandomGenWrapper(randomNums, probabilities);
		// checking random number:3410 which has cum prob of 0<= and <=0.3
		int nextRandomNum = randomGen.nextNum(0.2f);		
		Assert.assertTrue(nextRandomNum==3410);
		nextRandomNum = randomGen.nextNum(0.299f);		
		Assert.assertTrue(nextRandomNum==3410);
		nextRandomNum = randomGen.nextNum(0.3f);		
		Assert.assertTrue(nextRandomNum==3410);

		// checking random number:893 which has cum prob of 0.3< and <=0.8		
		nextRandomNum = randomGen.nextNum(0.30001f);		
		Assert.assertTrue(nextRandomNum==893);
		nextRandomNum = randomGen.nextNum(0.51f);		
		Assert.assertTrue(nextRandomNum==893);
		nextRandomNum = randomGen.nextNum(0.799999f);		
		Assert.assertTrue(nextRandomNum==893);
		nextRandomNum = randomGen.nextNum(0.8f);		
		Assert.assertTrue(nextRandomNum==893);
		
		// checking random number:343 which has cum prob of 0.8< and <=1		
		nextRandomNum = randomGen.nextNum(0.800001f);
		Assert.assertTrue(nextRandomNum==343);
		nextRandomNum = randomGen.nextNum(0.9f);
		Assert.assertTrue(nextRandomNum==343);
		nextRandomNum = randomGen.nextNum(0.9999999f);
		Assert.assertTrue(nextRandomNum==343);
		nextRandomNum = randomGen.nextNum(1);
		Assert.assertTrue(nextRandomNum==343);
	}
	
	@Test
	public void testNonOccuringEventsWithProbZero() {
		// -1 event should never happen here	
		int[] randomNums= {5,-1,2,4};
		float[] probabilities={0.1f,0.0f,0.6f,0.3f};
		RandomGen randomGen = new RandomGen(randomNums, probabilities);
		//lets try several times if this true
		int maxTry=100000;
		for (int i=0;i<maxTry;i++){
			int nextNum = randomGen.nextNum();
			// make sure we never get -1 which has prob 0
			Assert.assertNotEquals(nextNum, -1);
		}		
	}
	
	@Test
	public void testAlwaysOccuringEventsWithProbOne() {
		// -1 event should always happen here	
		int[] randomNums= {5,-1,2,4};
		float[] probabilities={0.0f,1.0f,0.0f,0.0f};
		RandomGen randomGen = new RandomGen(randomNums, probabilities);
		//lets try several times if this true
		int maxTry=100000;
		for (int i=0;i<maxTry;i++){
			int nextNum = randomGen.nextNum();
			// make sure we always get -1 which has prob 1
			Assert.assertEquals(nextNum, -1);
		}		
	}
	
	/*
	 * Generate huge amount of random next number, given probability and random number arrays. 
	 * Then, frequency of each random number is estimated.
	 * Finally it is asserted that frequency is close to the input probability within a threshold (0.001)   
	 */
	@Test
	public void testProvidedQuickCheck() {
		int[] randomNums= {-1,0,1,2,3};
		float[] probabilities={0.01f, 0.3f, 0.58f, 0.1f, 0.01f};
		float[] simFrequency= new float[probabilities.length];
		
		Map <Integer,Long> counterMap= new LinkedHashMap<Integer,Long>();
		// reset counter map
		for (int randomNum : randomNums) {
			counterMap.put(randomNum, 0L);
		}
		
		RandomGen randomGen = new RandomGen(randomNums, probabilities,1234L);
		//lets generate many times random numbers
		int maxTry=10000000;
		for (int i=0;i<maxTry;i++){
			int nextNum = randomGen.nextNum();
			Long counter = counterMap.get(nextNum);			
			counter++;
			counterMap.put(nextNum, counter);			
		}
		
		// estimate frequency 
		int index=0;
		for (Entry<Integer, Long> entry : counterMap.entrySet()) {			
			Long counter = entry.getValue();
			// simulation frequencies
			simFrequency[index]=counter/(float)maxTry;
			float simProbDifference = Math.abs(simFrequency[index]-probabilities[index]);
			// 
			Assert.assertTrue(simProbDifference<SIM_PROB_THRESHOLD);
			index++;
		}

		System.out.println("Counter Map "+counterMap);
		System.out.println("Freq map:"+Arrays.toString(simFrequency));
		
	}
	private class RandomGenWrapper extends RandomGen{

		public RandomGenWrapper(int[] randomNums, float[] probabilities) {
			super(randomNums, probabilities);		
		}
		
		public int nextNum(float nextFloat){
			return super.nextNum(nextFloat);
		}
	}
}