// Path: src/com/ibm/exception/DataGenerationException.java
// public class DataGenerationException extends Exception {
// 
// 	private static final long serialVersionUID = 1L;
// 
// }
// 
// Path: src/com/ibm/generation/FitnessProportionateSelection.java
// public class FitnessProportionateSelection <K> implements Serializable{
// 
// 	private static final long serialVersionUID = 1L;
// 
// 	private Map<K, Long> histogram = null;
// 	
// 	private BiMap<K, Tuple<Double, Double>> proportionalityMap;
// 	private List<Tuple<Double, Double>> sortedProbabilityBins;
// 	
// 	private boolean canGenerate;
// 	
// 	public FitnessProportionateSelection(Map<K, Long> histogram) {
// 		this.histogram = histogram;
// 	}
// 	/**
// 	 * This function returns random values whose distribution is based 
// 	 * on the histogram of entropies that characterizes a file. Therefore, 
// 	 * values are generated taking into account the frequency of histogram
// 	 * values of file chunks (Fitness Proportional selection).
// 	 *  
// 	 * @return element selected in a fitness proportional way
// 	 */
// 	public K generateProportionalKeys(Random seed) throws DataGenerationException {
// 		if (!canGenerate){
// 			computeFrequencyBasedProbability();
// 		}
// 		//Generate random trial
// 		double random = seed.nextDouble();
// 		//Binary search for the correct bin
// 		Tuple<Double, Double> proportion = binBinarySearch(sortedProbabilityBins, random);
// 		//Get the key associated to that bin
// 		K key = proportionalityMap.inverse().get(proportion);
// 		if (key != null) return key;
// 		throw new DataGenerationException();
// 	}
// 	public K generateProportionalKeys() throws DataGenerationException {
// 		return generateProportionalKeys(new Random());
// 	}
// 	/**
// 	 * This method builds an internal map that computes each entropy category
// 	 * with ranges between [0,1]. The width of a range represents the probability 
// 	 * of retrieving a chunk of a certain entropy category. Ranges are computed
// 	 * taking into account the frequency of a category compared with the total 
// 	 * frequencies. 
// 	 */
// 	public synchronized void computeFrequencyBasedProbability(Map<K, Long> histogram){
//     	//Calculate the global number of frequencies
// 		proportionalityMap = HashBiMap.create();
// 		sortedProbabilityBins = new ArrayList<Tuple<Double, Double>>();
// 		Long totalFrequencies = 0L;
// 		for (Long frequency: histogram.values()) 
// 			totalFrequencies += frequency;
// 		double proportion, proportionAccum = 0;
// 		Long frequency = 0L;
// 		//Calculate the proportion that represents the frequencies
// 		//of each element compared with the total
// 		for (K category: histogram.keySet()) {
// 			frequency = histogram.get(category); 
// 			if (frequency > 0){
// 				proportion = ((double)frequency)/totalFrequencies;
// 				Tuple<Double, Double> probabilityBin = new Tuple<Double, Double>(
// 						proportionAccum, proportionAccum+proportion);
// 				proportionalityMap.put(category, probabilityBin);
// 				sortedProbabilityBins.add(probabilityBin);
// 				proportionAccum+=proportion;
// 			}
// 		}
// 		//The sum of all probabilities must be 1
// 		if (proportionAccum>1.0001 || proportionAccum<0.999) {
// 			System.err.println("Sum of probabilities not equal to 1: " + proportionAccum);
// 			//System.exit(1);
// 		}
// 		canGenerate = true;
// 	}
// 	
// 	public void computeFrequencyBasedProbability(){
// 		if (histogram!=null){
// 			computeFrequencyBasedProbability(histogram);
// 		}
// 	}
// 
// 	/**
// 	 * Performs a binary search to find the Tuple that the element key
// 	 * belongs to.
// 	 *  
// 	 * @param elements
// 	 * @param key
// 	 * @return
// 	 * @throws DataGenerationException
// 	 */
// 	private Tuple<Double, Double> binBinarySearch(List<Tuple<Double, Double>> elements, double key) 
// 										throws DataGenerationException {
// 		if (elements==null || elements.size()==0) throw new DataGenerationException();
// 		int midPoint = elements.size()/2, minPoint = 0, maxPoint = elements.size();
// 		while (minPoint < maxPoint) {
// 			Tuple<Double, Double> elem = elements.get(midPoint);	
// 			if (key > elem.x && key <= elem.y) return elem;
// 			if (key < elem.x) maxPoint = midPoint;
// 			if (key > elem.y) minPoint = midPoint;
// 			midPoint = minPoint + (maxPoint-minPoint)/2;
// 		}
// 		throw new DataGenerationException();
// 	}
// 	
// 	//	ACCESS METHODS --
// 	
// 	/**
// 	 * @return the histogram
// 	 */
// 	public Map<K, Long> getHistogram() {
// 		return histogram;
// 	}
// 
// 	/**
// 	 * @param histogram the histogram to set
// 	 */
// 	public void setHistogram(Map<K, Long> histogram) {
// 		this.histogram = histogram;
// 	}
// }


import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import com.ibm.exception.DataGenerationException;
import com.ibm.generation.FitnessProportionateSelection;
			currentElement = node;
		}while(currentElement==null);
		return currentElement.element;
	}
	
	public int getNextElementFor(int element) {
		GraphNode node = nodes.get(element);
		return node.getNextChainElement().element;
	}
	
	private class GraphNode {
		
		int element;
		
		Map<GraphNode, Long> links;
		
		FitnessProportionateSelection<GraphNode> selector;

		GraphNode(int element) {
			this.element = element;
			links = new HashMap<GraphNode, Long>();
			selector = new FitnessProportionateSelection<>(links);
		}

		/**
		 * @return
		 */
		public GraphNode getNextChainElement() {
			try {
				return selector.generateProportionalKeys();
// Path: src/com/ibm/exception/DataGenerationException.java
// public class DataGenerationException extends Exception {
// 
// 	private static final long serialVersionUID = 1L;
// 
// }
// 
// Path: src/com/ibm/generation/FitnessProportionateSelection.java
// public class FitnessProportionateSelection <K> implements Serializable{
// 
// 	private static final long serialVersionUID = 1L;
// 
// 	private Map<K, Long> histogram = null;
// 	
// 	private BiMap<K, Tuple<Double, Double>> proportionalityMap;
// 	private List<Tuple<Double, Double>> sortedProbabilityBins;
// 	
// 	private boolean canGenerate;
// 	
// 	public FitnessProportionateSelection(Map<K, Long> histogram) {
// 		this.histogram = histogram;
// 	}
// 	/**
// 	 * This function returns random values whose distribution is based 
// 	 * on the histogram of entropies that characterizes a file. Therefore, 
// 	 * values are generated taking into account the frequency of histogram
// 	 * values of file chunks (Fitness Proportional selection).
// 	 *  
// 	 * @return element selected in a fitness proportional way
// 	 */
// 	public K generateProportionalKeys(Random seed) throws DataGenerationException {
// 		if (!canGenerate){
// 			computeFrequencyBasedProbability();
// 		}
// 		//Generate random trial
// 		double random = seed.nextDouble();
// 		//Binary search for the correct bin
// 		Tuple<Double, Double> proportion = binBinarySearch(sortedProbabilityBins, random);
// 		//Get the key associated to that bin
// 		K key = proportionalityMap.inverse().get(proportion);
// 		if (key != null) return key;
// 		throw new DataGenerationException();
// 	}
// 	public K generateProportionalKeys() throws DataGenerationException {
// 		return generateProportionalKeys(new Random());
// 	}
// 	/**
// 	 * This method builds an internal map that computes each entropy category
// 	 * with ranges between [0,1]. The width of a range represents the probability 
// 	 * of retrieving a chunk of a certain entropy category. Ranges are computed
// 	 * taking into account the frequency of a category compared with the total 
// 	 * frequencies. 
// 	 */
// 	public synchronized void computeFrequencyBasedProbability(Map<K, Long> histogram){
//     	//Calculate the global number of frequencies
// 		proportionalityMap = HashBiMap.create();
// 		sortedProbabilityBins = new ArrayList<Tuple<Double, Double>>();
// 		Long totalFrequencies = 0L;
// 		for (Long frequency: histogram.values()) 
// 			totalFrequencies += frequency;
// 		double proportion, proportionAccum = 0;
// 		Long frequency = 0L;
// 		//Calculate the proportion that represents the frequencies
// 		//of each element compared with the total
// 		for (K category: histogram.keySet()) {
// 			frequency = histogram.get(category); 
// 			if (frequency > 0){
// 				proportion = ((double)frequency)/totalFrequencies;
// 				Tuple<Double, Double> probabilityBin = new Tuple<Double, Double>(
// 						proportionAccum, proportionAccum+proportion);
// 				proportionalityMap.put(category, probabilityBin);
// 				sortedProbabilityBins.add(probabilityBin);
// 				proportionAccum+=proportion;
// 			}
// 		}
// 		//The sum of all probabilities must be 1
// 		if (proportionAccum>1.0001 || proportionAccum<0.999) {
// 			System.err.println("Sum of probabilities not equal to 1: " + proportionAccum);
// 			//System.exit(1);
// 		}
// 		canGenerate = true;
// 	}
// 	
// 	public void computeFrequencyBasedProbability(){
// 		if (histogram!=null){
// 			computeFrequencyBasedProbability(histogram);
// 		}
// 	}
// 
// 	/**
// 	 * Performs a binary search to find the Tuple that the element key
// 	 * belongs to.
// 	 *  
// 	 * @param elements
// 	 * @param key
// 	 * @return
// 	 * @throws DataGenerationException
// 	 */
// 	private Tuple<Double, Double> binBinarySearch(List<Tuple<Double, Double>> elements, double key) 
// 										throws DataGenerationException {
// 		if (elements==null || elements.size()==0) throw new DataGenerationException();
// 		int midPoint = elements.size()/2, minPoint = 0, maxPoint = elements.size();
// 		while (minPoint < maxPoint) {
// 			Tuple<Double, Double> elem = elements.get(midPoint);	
// 			if (key > elem.x && key <= elem.y) return elem;
// 			if (key < elem.x) maxPoint = midPoint;
// 			if (key > elem.y) minPoint = midPoint;
// 			midPoint = minPoint + (maxPoint-minPoint)/2;
// 		}
// 		throw new DataGenerationException();
// 	}
// 	
// 	//	ACCESS METHODS --
// 	
// 	/**
// 	 * @return the histogram
// 	 */
// 	public Map<K, Long> getHistogram() {
// 		return histogram;
// 	}
// 
// 	/**
// 	 * @param histogram the histogram to set
// 	 */
// 	public void setHistogram(Map<K, Long> histogram) {
// 		this.histogram = histogram;
// 	}
// }


// Path: src/com/ibm/scan/MarkovChain.java
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import com.ibm.exception.DataGenerationException;
import com.ibm.generation.FitnessProportionateSelection;

			currentElement = node;
		}while(currentElement==null);
		return currentElement.element;
	}
	
	public int getNextElementFor(int element) {
		GraphNode node = nodes.get(element);
		return node.getNextChainElement().element;
	}
	
	private class GraphNode {
		
		int element;
		
		Map<GraphNode, Long> links;
		
		FitnessProportionateSelection<GraphNode> selector;

		GraphNode(int element) {
			this.element = element;
			links = new HashMap<GraphNode, Long>();
			selector = new FitnessProportionateSelection<>(links);
		}

		/**
		 * @return
		 */
		public GraphNode getNextChainElement() {
			try {
				return selector.generateProportionalKeys();
			} catch (DataGenerationException e) {