/*  
 *  Copyright 2007-2008 Lawrence Beadle & Tom Castle
 *  Licensed under GNU General Public License
 * 
 *  This file is part of EpochX: genetic programming for research
 *
 *  EpochX 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 3 of the License, or
 *  (at your option) any later version.
 *
 *  EpochX is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 * 
 *  You should have received a copy of the GNU General Public License
 *  along with EpochX.  If not, see <http://www.gnu.org/licenses/>.
 */
package com.epochx.util;


/**
 * This class provides static utility methods for working with booleans and 
 * boolean arrays.
 */
public class BoolUtils {
    
    /**
     * Translates a String of zeros ('0') and ones ('1') to an array of 
     * booleans. '0' characters are translated to a boolean false, and 
     * '1' characters to boolean true.
     * 
     * @param input An input String made up of 1s and 0s
     * @return An equivalent array of booleans.
     */
    public static boolean[] toArray(String input) {        
        int len = input.length();
        boolean[] bools = new boolean[len];
        
        for(int i = 0; i<len; i++) {
            bools[i] = (input.charAt(i) == '1');
        }
        
        return bools;
    }
    
    /**
     * Generates an array of boolean arrays of all possible combinations of 
     * true/false values for the given number of elements. 
     * 
     * <p>This function will not cope with large values of noBits over about 
     * 30 due to the size limitations of the int datatype, and maximum array 
     * sizes. There are also likely to be issues with heap space. Alternatively 
     * users should use the BoolUtils.generateBoolSequence(int, long) method 
     * which generates the same boolean arrays on an individual basis.
     * 
     * @param noBits The number of boolean values in which different 
     * 				 combinations are made.
     * @return An array of all the possible boolean arrays possible with the 
     * given number of elements. There will be 2^noBits combinations and so 
     * the returned array will have this many elements.
     */
    public static boolean[][] generateBoolSequences(int noBits) {
    	int noInputs = (int) Math.pow(2, noBits);
    	
    	boolean[][] inputs = new boolean[noInputs][noBits];
    	
    	for(int i=0; i<noBits; i++) {
    		int rep = (int) Math.pow(2, i+1);
    		
    		for(int j=0; j<noInputs; j++) {
    			inputs[j][i] = (j % rep) > Math.floor(rep / 2)-1;
    		}
    	}
    	
    	return inputs;
    }
    
    /**
     * Provides an alternative to BoolUtils.generateBoolSequences(int) 
     * particularly for larger numbers of bits greater than 30 which that 
     * method will struggle with. The order of the bools generated by this 
     * method are identical to that method, so that calling it with an index 
     * parameter of n will return a boolean[] identical to the nth element of 
     * the boolean[][] returned by BoolUtils.generateBoolSequences(int).
     * 
     * @param noBits The number of boolean values in which different 
     * 				 combinations are made.
     * @param index An index into the possible combinations to allow iteration 
     * 				through the possibilities. There will be 2^noBits 
     * 				combinations and so indexes up to 2^noBits-1 will be valid.
     * @return An array of booleans. The value of the booleans is identical to 
     * the nth element of the result from BoolUtils.generateBoolSequences, where 
     * n == index. Each valid index value will return a unique combination of 
     * booleans.
     */
    public static boolean[] generateBoolSequence(int noBits, long index) {
    	boolean[] inputs = new boolean[noBits];
    	
    	for(int i=0; i<noBits; i++) {
    		int rep = (int) Math.pow(2, i+1);
    		
    		inputs[i] = (index % rep) > Math.floor(rep / 2)-1;
    	}
    	
    	return inputs;
    }
}
