All Downloads are FREE. Search and download functionalities are using the official Maven repository.

de.invation.code.toval.misc.valuegeneration.StochasticValueGenerator Maven / Gradle / Ivy

package de.invation.code.toval.misc.valuegeneration;

import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Set;

import de.invation.code.toval.validate.InconsistencyException;
import de.invation.code.toval.validate.ParameterException;
import de.invation.code.toval.validate.Validate;


/**
 * This class allows to choose elements according to given occurrence probabilities.
 * It maintains a number of elements and stochastically chooses an element
 * on demand based on the given probability.
 * 
 * Occurrence probabilities for maintained elements must sum up to 1,
 * otherwise the state of this chooser is invalid and no choices are made.
* To handle rounding errors, a tolerance t is defined.
* The difference between the sum of all probabilities and 1 must not exceed t. *

* @author Thomas Stocker * @param element Type */ public class StochasticValueGenerator implements ValueGenerator{ private static final String probFormat = "%s: %s%%\n"; private List keys = new ArrayList(); private List limits = new ArrayList(); private Map probabilities = new HashMap(); private boolean isValid = false; private Random rand = new Random(); private double tolerance; /** * Creates a new StochasticChooser.
* The tolerance is defined as 1/toleranceDenominator. * @param toleranceDenominator * @throws ParameterException */ public StochasticValueGenerator(int toleranceDenominator) throws ParameterException{ Validate.biggerEqual(toleranceDenominator, 1, "Denominator must be >= 1"); tolerance = 1.0/toleranceDenominator; } public StochasticValueGenerator() throws ParameterException{ this(1000); } public void removeElement(Object key){ if(!keys.contains(key)) return; int index = keys.indexOf(key); keys.remove(index); limits.remove(index); probabilities.remove(index); isValid = (1.0-getSum()) <= tolerance; } /** * Adds a new element together with its occurrence probability.
* The method checks and sets the validity state of the chooser. * Once valid, no more probabilities are accepted. * @param o Element to add. * @param p Occurrence probability of the given element. * @throws InconsistencyException Thrown if the sum of all maintained probabilities is greater than 1. */ public boolean addProbability(E o, Double p) throws InconsistencyException, ParameterException { if(isValid()) return false; Validate.probability(p); if(keys.isEmpty()){ keys.add(o); limits.add(p); } else { if((getSum() + p) > 1.0+tolerance){ throw new InconsistencyException("Probabilities must sum up to 1 ("+(getSum() + p)+" instead)."); } keys.add(o); limits.add(getSum() + p); } isValid = (1.0-getSum()) <= tolerance; probabilities.put(o, p); return true; } public Double getProbability(Object o){ try{ return probabilities.get(o); } catch (Exception e){ return null; } } public Set getElements(){ return new HashSet(keys); } /** * Returns the sum of the given probabilities so far. * @return The sum of all maintained probabilities. */ private Double getSum(){ if(limits.isEmpty()) return 0.0; return limits.get(limits.size()-1); } /** * Returns the state of this element chooser. * If all maintained probabilities sum up to 1, the state of this chooser is called valid. * Otherwise it is incomplete (invalid) and refuses to conduct element choices. * @return true if this chooser is valid,
* false otherwise. */ @Override public boolean isValid(){ return isValid; } /** * Conducts a stochastic element choice based on the maintained occurrence probabilities. * @return A randomly chosen element based on occurrence probabilities. * @throws ValueGenerationException Thrown, if the chooser is in an invalid state. */ public E getNextValue() throws ValueGenerationException{ if(!isValid()) throw new ValueGenerationException("Cannot provide elements in invalid state."); Double random = rand.nextDouble(); for(int i=0; i clone(){ StochasticValueGenerator result; try { result = new StochasticValueGenerator(); for(E element: getElements()){ result.addProbability(element, getProbability(element)); } } catch (ParameterException e) { return null; } return result; } @Override public boolean isEmpty() { return keys.isEmpty(); } @Override public String toString(){ NumberFormat nf = new DecimalFormat("#0.##"); StringBuilder builder = new StringBuilder(); for(E e: keys){ builder.append(String.format(probFormat, e, nf.format(getProbability(e)*100.0))); } return builder.toString(); } public static void main(String[] args) throws ParameterException { StochasticValueGenerator vg = new StochasticValueGenerator(1000); vg.addProbability("a", 0.3); vg.addProbability("b", 0.7); System.out.println(vg); System.out.println(vg.isValid()); vg.removeElement("b"); System.out.println(vg); System.out.println(vg.isValid()); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy