BitChromosome.java

package net.bmahe.genetics4j.core.chromosomes;

import java.util.BitSet;

import org.apache.commons.lang3.Validate;

/**
 * A chromosome implementation that represents genetic information as a sequence of bits.
 * 
 * <p>BitChromosome is commonly used for binary optimization problems, feature selection,
 * and any application where the solution can be encoded as a bit string. Each bit (allele)
 * can be either 0 or 1, representing boolean choices or binary features.
 * 
 * <p>This implementation is immutable and uses a {@link BitSet} for efficient storage
 * and manipulation of the bit sequence.
 * 
 * <p>Common use cases include:
 * <ul>
 * <li>Binary optimization problems (knapsack, subset selection)</li>
 * <li>Feature selection in machine learning</li>
 * <li>Boolean satisfiability problems</li>
 * <li>Circuit design and logic optimization</li>
 * </ul>
 * 
 * @see Chromosome
 * @see java.util.BitSet
 */
public class BitChromosome implements Chromosome {

	private final int numBits;
	private final BitSet bitSet;

	/**
	 * Creates a new bit chromosome with the specified number of bits and initial values.
	 * 
	 * @param _numBits the number of bits in this chromosome, must be positive
	 * @param _bitSet the initial bit values for this chromosome
	 * @throws IllegalArgumentException if numBits is zero or negative, if bitSet is null,
	 *                                  or if numBits exceeds the bitSet size
	 */
	public BitChromosome(final int _numBits, final BitSet _bitSet) {
		Validate.isTrue(_numBits > 0, "numBits can't be zero or negative");
		Validate.notNull(_bitSet);
		Validate.isTrue(_numBits <= _bitSet.size());

		this.numBits = _numBits;
		this.bitSet = new BitSet(numBits);
		this.bitSet.or(_bitSet);
	}

	@Override
	public int getNumAlleles() {
		return numBits;
	}

	/**
	 * Returns the bit value at the specified index.
	 * 
	 * @param index the index of the bit to retrieve (0-based)
	 * @return {@code true} if the bit is set (1), {@code false} if clear (0)
	 * @throws IllegalArgumentException if index is negative or greater than or equal to numBits
	 */
	public boolean getBit(final int index) {
		Validate.isTrue(index >= 0);
		Validate.isTrue(index < numBits);

		return bitSet.get(index);
	}

	/**
	 * Returns the underlying BitSet containing all bit values.
	 * 
	 * <p>The returned BitSet is a copy and modifications to it will not affect this chromosome.
	 * 
	 * @return a BitSet containing the bit values of this chromosome
	 */
	public BitSet getBitSet() {
		return bitSet;
	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + ((bitSet == null) ? 0 : bitSet.hashCode());
		result = prime * result + numBits;
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		BitChromosome other = (BitChromosome) obj;
		if (bitSet == null) {
			if (other.bitSet != null)
				return false;
		} else if (!bitSet.equals(other.bitSet))
			return false;
		if (numBits != other.numBits)
			return false;
		return true;
	}

	@Override
	public String toString() {
		return "BitChromosome [numBits=" + numBits + ", bitSet=" + bitSet + "]";
	}
}