A random choice maker : Random « Development Class « Java






A random choice maker

  
//package gr.forth.ics.util;

import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Deque;
import java.util.List;
import java.util.Random;

/**
 * A random choice maker, where each choice is associated with a probability. This implementation
 * is based on the fast <em>alias</em> method, where for each random choice two random
 * numbers are generated and only a single table lookup performed.
 *
 * @param <T> the type of the choices to be made
 * @see <a href="http://cg.scs.carleton.ca/~luc/rnbookindex.html">L. Devroye, Non-Uniform Random Variate Generation, 1986, p. 107</a>
 * @author  Andreou Dimitris, email: jim.andreou (at) gmail (dot) com 
 */
public class RandomChooser<T> {
    private final double[] probs;
    private final int[] indexes;
    private final List<T> events;
    
    private final Random random;
    
    private RandomChooser(List<Double> weights, List<T> events, Random random) {
        double sum = 0.0;
        for (double prob : weights) sum += prob;

        this.probs = new double[weights.size()];
        for (int i = 0; i < weights.size(); i++) {
            probs[i] = weights.get(i) * weights.size() / sum; //average = 1.0
        }

        Deque<Integer> smaller = new ArrayDeque<Integer>(weights.size() / 2 + 2);
        Deque<Integer> greater = new ArrayDeque<Integer>(weights.size() / 2 + 2);
        for (int i = 0; i < probs.length; i++) {
            if (probs[i] < 1.0) {
                smaller.push(i);
            } else {
                greater.push(i);
            }
        }
        indexes = new int[weights.size()];
        while (!smaller.isEmpty()) {
            Integer i = smaller.pop();
            Integer k = greater.peek();
            indexes[i] =  k;
            probs[k] -= (1 - probs[i]);
            if (probs[k] < 1.0) {
                greater.pop();
                if (greater.isEmpty()) break;
                smaller.push(k);
            }
        }
        this.events = events;
        this.random = random;
    }

    /**
     * Returns a random choice.
     *
     * @return a random choice
     * @see RandomChooserBuilder about how to configure the available choices
     */
    public T choose() {
        int index = random.nextInt(probs.length);
        double x = random.nextDouble();
        return x < probs[index] ? events.get(index) : events.get(indexes[index]);
    } 

    /**
     * Creates a builder of a {@link RandomChooser} instance. The builder is responsible
     * for configuring the choices and probabilities of the random chooser.
     *
     * @param <T> the type of the choices that will be randomly made
     * @return a builder of a {@code RandomChooser} object
     */
    public static <T> RandomChooserBuilder<T> newInstance() {
        return new RandomChooserBuilder<T>();
    }

    /**
     * A builder of {@link RandomChooser}.
     * 
     * @param <T> the type of the choices that the created {@code RandomChooser} will make
     */
    public static class RandomChooserBuilder<T> {
        private final List<Double> probs = new ArrayList<Double>();
        private final List<T> events = new ArrayList<T>();
        private Random random = new Random(0);

        private RandomChooserBuilder() { }

        /**
         * Adds the possibility of a given choice, weighted by a relative probability.
         * (Relative means that it is not needed that all probabilities have sum {@code 1.0}).
         *
         * @param choice a possible choice
         * @param prob the relative probability of the choice; must be {@code >= 0}
         * @return this
         */
        public RandomChooserBuilder<T> choice(T choice, double prob) {
            Args.gte(prob, 0.0);
            Args.notNull(choice);
            probs.add(prob);
            events.add(choice);
            return this;
        }

        /**
         * Specifies the random number generator to be used by the created {@link RandomChooser}.
         *
         * @param random the random number generator to use
         * @return this
         */
        public RandomChooserBuilder<T> setRandom(Random random) {
            this.random = random;
            return this;
        }

        /**
         * Builds a {@link RandomChooser} instance, ready to make random choices based on the
         * probabilities configured by this builder.
         *
         * @return a {@code RandomChooser}
         */
        public RandomChooser<T> build() {
            if (probs.isEmpty()) {
                throw new IllegalStateException("No choice was defined");
            }
            return new RandomChooser<T>(
                    new ArrayList<Double>(probs),
                    new ArrayList<T>(events),
                    random);
        }
    }
}
class Args {
    private static final String GT = " must be greater than ";
    private static final String GTE = " must be greater or equal to ";
    private static final String LT = " must be less than ";
    private static final String LTE = " must be less or equal to ";

    private static final String EQUALS = " must be equal to ";
    
    public static void doesNotContainNull(Iterable<?> iterable) {
        notNull(iterable);
        for (Object o : iterable) {
            notNull("Iterable contains null", o);
        }
    }
    
    public static void isTrue(boolean condition) {
        isTrue("Condition failed", condition);
    }
    
    public static void isTrue(String msg, boolean condition) {
        if (!condition) {
            throw new RuntimeException(msg);
        }
    }
    
    public static void notNull(Object o) {
        notNull(null, o);
    }
    
    public static void notNull(String arg, Object o) {
        if (arg == null) {
            arg = "Argument";
        }
        if (o == null) {
            throw new IllegalArgumentException(arg + " is null");
        }
    }
    
    public static void notNull(Object... args) {
        notNull(null, args);
    }
    
    public static void notNull(String message, Object... args) {
        if (message == null) {
            message = "Some argument";
        }
        for (Object o : args) {
            notNull(message, o);
        }
    }
    
    public static void notEmpty(Iterable<?> iter) {
        notEmpty(null, iter);
    }
    
    public static void notEmpty(String arg, Iterable<?> iter) {
        if (arg == null) {
            arg = "Iterable";
        }
        notNull(iter);
        if (iter.iterator().hasNext()) return;
        throw new IllegalArgumentException(arg + " is empty");
    }
    
    public static void hasNoNull(Iterable<?> iter) {
        hasNoNull(null, iter);
    }
    
    public static void hasNoNull(String arg, Iterable<?> iter) {
        notNull(iter);
        if (arg == null) {
            arg = "Iterable";
        }
        for (Object o : iter) {
            if (o == null) {
                throw new IllegalArgumentException(arg + " contains null");
            }
        }
    }
    
    public static void equals(int value, int expected) {
        if (value == expected) return;
        throw new IllegalArgumentException(value + EQUALS + expected);
    }
    
    public static void equals(long value, long expected) {
        if (value == expected) return;
        throw new IllegalArgumentException(value + EQUALS + expected);
    }
    
    public static void equals(double value, double expected) {
        if (value == expected) return;
        throw new IllegalArgumentException(value + EQUALS + expected);
    }
    
    public static void equals(float value, float expected) {
        if (value == expected) return;
        throw new IllegalArgumentException(value + EQUALS + expected);
    }
    
    public static void equals(char value, char expected) {
        if (value == expected) return;
        throw new IllegalArgumentException(value + EQUALS + expected);
    }
    
    public static void equals(short value, short expected) {
        if (value == expected) return;
        throw new IllegalArgumentException(value + EQUALS + expected);
    }
    
    public static void equals(byte value, byte expected) {
        if (value == expected) return;
        throw new IllegalArgumentException(value + EQUALS + expected);
    }

    public static void equals(Object value, Object expected) {
        if (value == expected || value.equals(expected)) return;
        throw new IllegalArgumentException(value + EQUALS + expected);
    }
    
    public static void gt(int value, int from) {
        if (value > from) return;
        throw new IllegalArgumentException(value + GT + from);
    }
    
    public static void lt(int value, int from) {
        if (value < from) return;
        throw new IllegalArgumentException(value + LT + from);
    }
    
    public static void gte(int value, int from) {
        if (value >= from) return;
        throw new IllegalArgumentException(value + GTE + from);
    }
    
    public static void lte(int value, int from) {
        if (value <= from) return;
        throw new IllegalArgumentException(value + LTE + from);
    }
    
    public static void gt(long value, long from) {
        if (value > from) return;
        throw new IllegalArgumentException(value + GT + from);
    }
    
    public static void lt(long value, long from) {
        if (value < from) return;
        throw new IllegalArgumentException(value + LT + from);
    }
    
    public static void gte(long value, long from) {
        if (value >= from) return;
        throw new IllegalArgumentException(value + GTE + from);
    }
    
    public static void lte(long value, long from) {
        if (value <= from) return;
        throw new IllegalArgumentException(value + LTE + from);
    }
    
    public static void gt(short value, short from) {
        if (value > from) return;
        throw new IllegalArgumentException(value + GT + from);
    }
    
    public static void lt(short value, short from) {
        if (value < from) return;
        throw new IllegalArgumentException(value + LT + from);
    }
    
    public static void gte(short value, short from) {
        if (value >= from) return;
        throw new IllegalArgumentException(value + GTE + from);
    }
    
    public static void lte(short value, short from) {
        if (value <= from) return;
        throw new IllegalArgumentException(value + LTE + from);
    }
    
    public static void gt(byte value, byte from) {
        if (value > from) return;
        throw new IllegalArgumentException(value + GT + from);
    }
    
    public static void lt(byte value, byte from) {
        if (value < from) return;
        throw new IllegalArgumentException(value + LT + from);
    }
    
    public static void gte(byte value, byte from) {
        if (value >= from) return;
        throw new IllegalArgumentException(value + GTE + from);
    }
    
    public static void lte(byte value, byte from) {
        if (value <= from) return;
        throw new IllegalArgumentException(value + LTE + from);
    }
    
    public static void gt(char value, char from) {
        if (value > from) return;
        throw new IllegalArgumentException(value + GT + from);
    }
    
    public static void lt(char value, char from) {
        if (value < from) return;
        throw new IllegalArgumentException(value + LT + from);
    }
    
    public static void gte(char value, char from) {
        if (value >= from) return;
        throw new IllegalArgumentException(value + GTE + from);
    }
    
    public static void lte(char value, char from) {
        if (value <= from) return;
        throw new IllegalArgumentException(value + LTE + from);
    }
    
    public static void gt(double value, double from) {
        if (value > from) return;
        throw new IllegalArgumentException(value + GT + from);
    }
    
    public static void lt(double value, double from) {
        if (value < from) return;
        throw new IllegalArgumentException(value + LT + from);
    }
    
    public static void gte(double value, double from) {
        if (value >= from) return;
        throw new IllegalArgumentException(value + GTE + from);
    }
    
    public static void lte(double value, double from) {
        if (value <= from) return;
        throw new IllegalArgumentException(value + LTE + from);
    }
    
    public static void gt(float value, float from) {
        if (value > from) return;
        throw new IllegalArgumentException(value + GT + from);
    }
    
    public static void lt(float value, float from) {
        if (value < from) return;
        throw new IllegalArgumentException(value + LT + from);
    }
    
    public static void gte(float value, float from) {
        if (value >= from) return;
        throw new IllegalArgumentException(value + GTE + from);
    }
    
    public static void lte(float value, float from) {
        if (value <= from) return;
        throw new IllegalArgumentException(value + LTE + from);
    }
    
    public static <T> void gt(Comparable<T> c1, T c2) {
        if (c1.compareTo(c2) > 0) return;
        throw new IllegalArgumentException(c1 + GT + c2);
    }
    
    public static <T> void lt(Comparable<T> c1, T c2) {
        if (c1.compareTo(c2) < 0) return;
        throw new IllegalArgumentException(c1 + LT + c2);
    }
    
    public static <T> void gte(Comparable<T> c1, T c2) {
        if (c1.compareTo(c2) >= 0) return;
        throw new IllegalArgumentException(c1 + GTE + c2);
    }
    
    public static <T> void lte(Comparable<T> c1, T c2) {
        if (c1.compareTo(c2) <= 0) return;
        throw new IllegalArgumentException(c1 + LTE + c2);
    }
    
    public static <T> void inRangeII(Comparable<T> value, T from, T to) {
        gte(value, from);
        lte(value, to);
    }
    
    public static <T> void inRangeEE(Comparable<T> value, T from, T to) {
        gt(value, from);
        lt(value, to);
    }
    
    public static <T> void inRangeIE(Comparable<T> value, T from, T to) {
        gt(value, from);
        lt(value, to);
    }
    
    public static <T> void inRangeEI(Comparable<T> value, T from, T to) {
        gt(value, from);
        lte(value, to);
    }
    
    public static void inRangeII(int value, int from, int to) {
        gte(value, from);
        lte(value, to);
    }
    
    public static void inRangeEE(int value, int from, int to) {
        gt(value, from);
        lt(value, to);
    }
    
    public static void inRangeIE(int value, int from, int to) {
        gte(value, from);
        lt(value, to);
    }
    
    public static void inRangeEI(int value, int from, int to) {
        gt(value, from);
        lte(value, to);
    }
    
    public static void inRangeII(long value, long from, long to) {
        gte(value, from);
        lte(value, to);
    }
    
    public static void inRangeEE(long value, long from, long to) {
        gt(value, from);
        lt(value, to);
    }
    
    public static void inRangeIE(long value, long from, long to) {
        gte(value, from);
        lt(value, to);
    }
    
    public static void inRangeEI(long value, long from, long to) {
        gt(value, from);
        lte(value, to);
    }
    
    public static void inRangeII(short value, short from, short to) {
        gte(value, from);
        lte(value, to);
    }
    
    public static void inRangeEE(short value, short from, short to) {
        gt(value, from);
        lt(value, to);
    }
    
    public static void inRangeIE(short value, short from, short to) {
        gte(value, from);
        lt(value, to);
    }
    
    public static void inRangeEI(short value, short from, short to) {
        gt(value, from);
        lte(value, to);
    }
    
    public static void inRangeII(byte value, byte from, byte to) {
        gte(value, from);
        lte(value, to);
    }
    
    public static void inRangeEE(byte value, byte from, byte to) {
        gt(value, from);
        lt(value, to);
    }
    
    public static void inRangeIE(byte value, byte from, byte to) {
        gte(value, from);
        lt(value, to);
    }
    
    public static void inRangeEI(byte value, byte from, byte to) {
        gt(value, from);
        lte(value, to);
    }
    
    public static void check(boolean assertion, String messageIfFailed) {
        if (!assertion) {
            throw new RuntimeException(messageIfFailed);
        }
    }
}

   
    
  








Related examples in the same category

1.Create random number
2.Create two random number generators with the same seed
3.Does Math.random() produce 0.0 and 1.0
4.Random numbers between 1 and 100
5.Random number between 0 AND 10
6.Random integers that range from from 0 to n
7.Random.nextInt(n) returns a distributed int value between 0 (inclusive) and n (exclusive).
8.Round Java float and double numbers using Math.round
9.Randomizer
10.nextDouble() and nextGaussian() in java.util.Random
11.Generating random numbers
12.Generate random ints by asking Random() for
13.Getting random numbers: nextGaussian
14.Generate a random array of numbers
15.Next double and next int
16.Random bytes
17.Random boolean
18.Random long type number
19.Random float type number
20.Random double type number
21.Math.random
22.A wrapper that supports all possible Random methods via the java.lang.Math#random() method and its system-wide {@link Random} object.
23.Operations for random Strings
24.Random Util with ReentrantLock
25.A Java implementation of the MT19937 (Mersenne Twister) pseudo random number generator algorithm
26.Randomizer
27.Random: Properly synchronized and can be used in a multithreaded environment
28.A predictable random number generator.
29.Random GUID
30.A random.org seeded random generator.
31.Generates a secure random word with the given length consisting of uppercase and lowercase letters and numbers.
32.Memory-efficient map of keys to values with list-style random-access semantics.
33.Generates a random integer inside the lo and hi interval
34.Randomizer
35.RandomGUID generates truly random GUIDs
36.A random access text file allows a text file to be accessed randomly starting at any position.
37.A garbage-free randomised quicksort
38.A linear random method based on xor shifts
39.Mersenne Twister Random
40.A GaussianHat is a random number generator that will give you numbers based on a population mean and standard deviation.
41.Randomly permutes the elements of the specified array
42.generate string consists of random characters.
43.Atomic Pseudo Random
44.Atomic Simple Random
45.Mersenne
46.Mersenne Twister
47.Mersenne Twister Fast
48.Mersenne Twister algorithm
49.Emulates a dice