/* @(#)ProbStatTools.java 1.0  10 October 2004 */

/** Code authored by Richard Rasala
 *  Associate Dean
 *  College of Computer and Information Science
 *  Northeastern University
 */

import edu.neu.ccs.util.*;

/**
 * <p>Class <code>ProbStatTools</p> collects static methods that
 * are useful for randomization, probability, and statistics.</p>
 */
public class ProbStatTools {
    
    /** Prevent instantiation. */
    private ProbStatTools() { }
    
    
    /**
     * <p>Returns an array with the integers in sequence:
     * 0, 1, etc, up to (n-1).</p>
     *
     * <p>If n is less than or equal to zero, then returns an
     * empty array of integers.</p>
     */
    public static int[] integerSequence(int n) {
        if (n <= 0)
            return new int[0];
        
        int[] result = new int[n];
        
        for (int i = 0; i < n; i++)
            result[i] = i;
        
        return result;
    }
    
    
    /**
     * <p>Returns an array of length k consisting of integers
     * chosen from 0 to (n-1) with repetition permitted.</p>
     *
     * <p>If n or k is less than or equal to zero, then returns
     * an empty array of integers.</p>
     */
    public static int[] selectWithRepetition(int n, int k) {
        if ((n <= 0) || (k <= 0))
            return new int[0];
        
        return selectWithRepetition(integerSequence(n), k);
    }
    
    
    /**
     * <p>Returns an array of length k consisting of integers
     * chosen from 0 to (n-1) with no repetition permitted.</p>
     *
     * <p>If k is less than or equal to zero or greater than n,
     * then returns an empty array of integers.</p>
     */
    public static int[] selectWithNoRepetition(int n, int k) {
        if ((k <= 0) || (k > n))
            return new int[0];
        
        return selectWithNoRepetition(integerSequence(n), k);
    }
    
    
    /**
     * <p>Returns an array whose contents is a random selection of
     * k elements from the contents of the given data with
     * repetition of a selected index permitted.</p>
     *
     * <p>The data array is unchanged.</p>
     *
     * <p>If the data array is <code>null</code>
     * or if k is less than or equal to zero,
     * then returns an empty array of integers.</p>
     */
    public static int[] selectWithRepetition(int[] data, int k) {
        if ((data == null) || (k <= 0))
            return new int[0];
        
        int size = data.length;
        
        int[] result = new int[k];
        
        for (int i = 0; i < k; i++) {
            int j = MathUtilities.randomInt(0, size - 1);
            result[i] = data[j];
        }
        
        return result;
    }
    
    
    /**
     * <p>Returns an array whose contents is a random selection of
     * k elements from the contents of the given data with
     * no repetition of a selected index.</p>
     *
     * <p>The data array is unchanged.</p>
     *
     * <p>If the data array is <code>null</code>
     * or if k is less than or equal to zero
     * or if k is greater than the data array size,
     * then returns an empty array of integers.</p>
     */
    public static int[] selectWithNoRepetition(int[] data, int k) {
        if (data == null)
            return new int[0];
        
        int size = data.length;
        
        if ((k <= 0) || (k > size))
            return new int[0];
        
        int[] temp = repeatData(data, 1);
        
        int[] result = new int[k];
        
        for (int i = 0; i < k; i++) {
            int j = MathUtilities.randomInt(i, size - 1);
            
            int copy  = temp[i];
            temp[i]   = temp[j];
            temp[j]   = copy;
            
            result[i] = temp[i];
        }
        
        return result;
    }
    
    
    /**
     * <p>Returns an array whose contents is a random permutation
     * of the contents in the data array.</p>
     *
     * <p>The data array is unchanged.</p>
     *
     * <p>If the data array is <code>null</code>,
     * then returns an empty array of integers.</p>
     */
    public static int[] randomPermutation(int[] data) {
        if (data == null)
            return new int[0];
        
        return selectWithNoRepetition(data, data.length);
    }
    
    
    /**
     * <p>Returns an int array that repeats the data in
     * the given array sequentially k times.
     *
     * <p>If the data array is <code>null</code> or
     * if k is less than or equal to zero,
     * then returns an empty array of integers.</p>
     *
     * <p>If k equals one, then copies the given data.</p>
     */
    public static int[] repeatData(int[] data, int k) {
        if ((data == null) || (k <= 0))
            return new int[0];
        
        int size1 = data.length;
        int sizek = k * size1;
        
        int[] result = new int[sizek];
        
        for (int i = 0; i < size1; i++) {
            for (int j = 0; j < k; j++) {
                result[i + j * size1] = data[i];
            }
        }
        
        return result;
    }

}