gdsc.core.utils.PseudoRandomGenerator.java Source code

Java tutorial

Introduction

Here is the source code for gdsc.core.utils.PseudoRandomGenerator.java

Source

package gdsc.core.utils;

/*----------------------------------------------------------------------------- 
 * GDSC Plugins for ImageJ
 * 
 * Copyright (C) 2017 Alex Herbert
 * Genome Damage and Stability Centre
 * University of Sussex, UK
 * 
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *---------------------------------------------------------------------------*/

import org.apache.commons.math3.random.AbstractRandomGenerator;
import org.apache.commons.math3.random.RandomGenerator;

/**
 * Contains a set of random numbers that are reused in sequence
 */
public class PseudoRandomGenerator extends AbstractRandomGenerator implements Cloneable {
    protected final double[] sequence;

    private int position = 0;

    /**
     * Instantiates a new pseudo random generator. The input sequence is cloned.
     *
     * @param sequence
     *            the sequence (must contains numbers in the interval 0 to 1)
     * @throw {@link IllegalArgumentException} if the sequence is not positive in length and contains numbers outside
     *        the interval 0 to 1.
     */
    public PseudoRandomGenerator(double[] sequence) {
        if (sequence == null || sequence.length < 1)
            throw new IllegalArgumentException("Sequence must have a positive length");
        for (int i = sequence.length; i-- > 0;)
            if (sequence[i] < 0 || sequence[i] > 1)
                throw new IllegalArgumentException("Sequence must contain numbers between 0 and 1 inclusive");
        this.sequence = sequence.clone();
    }

    /**
     * Instantiates a new pseudo random generator of the given size.
     *
     * @param size
     *            the size
     * @param source
     *            the random source
     * @throw {@link IllegalArgumentException} if the size is not positive
     * @throw {@link NullPointerException} if the generator is null
     */
    public PseudoRandomGenerator(int size, RandomGenerator source) {
        if (size < 1)
            throw new IllegalArgumentException("Sequence must have a positive length");
        if (source == null)
            throw new NullPointerException("Source generator must not be null");
        sequence = new double[size];
        while (size-- > 0) {
            sequence[size] = source.nextDouble();
        }
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.apache.commons.math3.random.AbstractRandomGenerator#setSeed(long)
     */
    @Override
    public void setSeed(long seed) {
        position = (int) (seed % sequence.length);
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.apache.commons.math3.random.AbstractRandomGenerator#nextDouble()
     */
    @Override
    public double nextDouble() {
        double d = sequence[position++];
        if (position == sequence.length)
            position = 0;
        return d;
    }

    /*
     * (non-Javadoc)
     * 
     * @see java.lang.Object#clone()
     */
    @Override
    public PseudoRandomGenerator clone() {
        try {
            return (PseudoRandomGenerator) super.clone();
        } catch (CloneNotSupportedException e) {
            // This should not happen
            return new PseudoRandomGenerator(sequence);
        }
    }

    /**
     * Returns a pseudorandom, uniformly distributed {@code int} value
     * between 0 (inclusive) and the specified value (exclusive), drawn from
     * this random number generator's sequence.
     * <p>
     * The default implementation returns:
     * 
     * <pre>
     * <code>(int) (nextDouble() * n</code>
     * </pre>
     * <p>
     * Warning: No check is made that n is positive so use with caution.
     *
     * @param n
     *            the bound on the random number to be returned. Must be
     *            positive.
     * @return a pseudorandom, uniformly distributed {@code int}
     *         value between 0 (inclusive) and n (exclusive).
     */
    public int nextIntFast(int n) {
        int result = (int) (nextDouble() * n);
        return result < n ? result : n - 1;
    }

    /**
     * Perform a Fischer-Yates shuffle on the data.
     *
     * @param data
     *            the data
     */
    public void shuffle(int[] data) {
        for (int i = data.length; i-- > 1;) {
            int j = nextIntFast(i + 1);
            int tmp = data[i];
            data[i] = data[j];
            data[j] = tmp;
        }
    }
}