/*
 * @(#)ProbStatTools.java    2.3.4   6 February 2005
 *
 * Copyright 2005
 * College of Computer and Information Science
 * Northeastern University
 * Boston, MA  02115
 *
 * The Java Power Tools software may be used for educational
 * purposes as long as this copyright notice is retained intact
 * at the top of all source files.
 *
 * To discuss possible commercial use of this software, 
 * contact Richard Rasala at Northeastern University, 
 * College of Computer and Information Science,
 * 617-373-2462 or rasala@ccs.neu.edu.
 *
 * The Java Power Tools software has been designed and built
 * in collaboration with Viera Proulx and Jeff Raab.
 *
 * Should this software be modified, the words "Modified from 
 * Original" must be included as a comment below this notice.
 *
 * All publication rights are retained.  This software or its 
 * documentation may not be published in any media either
 * in whole or in part without explicit permission.
 *
 * This software was created with support from Northeastern 
 * University and from NSF grant DUE-9950829.
 */

package edu.neu.ccs.util;


/**
 * <p>Class <code>ProbStatTools</code> collects static methods that
 * are useful for randomization, probability, and statistics.</p>
 *
 * @author  Richard Rasala
 * @version 2.3.4
 * @since   2.3.3
 */
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 permutation
     * of the integers from 0 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[] randomPermutation(int n) {
        if (n <= 0)
            return new int[0];
        
        return randomPermutation(integerSequence(n));
    }
    
    
    /**
     * <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;
    }

}