View Javadoc
1   package net.bmahe.genetics4j.core.chromosomes;
2   
3   import java.util.BitSet;
4   import java.util.Objects;
5   
6   import org.apache.commons.lang3.Validate;
7   
8   /**
9    * A chromosome implementation that represents genetic information as a sequence of bits.
10   * 
11   * <p>BitChromosome is commonly used for binary optimization problems, feature selection, and any application where the
12   * solution can be encoded as a bit string. Each bit (allele) can be either 0 or 1, representing boolean choices or
13   * binary features.
14   * 
15   * <p>This implementation is immutable and uses a {@link BitSet} for efficient storage and manipulation of the bit
16   * sequence.
17   * 
18   * <p>Common use cases include:
19   * <ul>
20   * <li>Binary optimization problems (knapsack, subset selection)</li>
21   * <li>Feature selection in machine learning</li>
22   * <li>Boolean satisfiability problems</li>
23   * <li>Circuit design and logic optimization</li>
24   * </ul>
25   * 
26   * @see Chromosome
27   * @see java.util.BitSet
28   */
29  public class BitChromosome implements Chromosome {
30  
31  	private final int numBits;
32  	private final BitSet bitSet;
33  
34  	/**
35  	 * Creates a new bit chromosome with the specified number of bits and initial values.
36  	 * 
37  	 * @param _numBits the number of bits in this chromosome, must be positive
38  	 * @param _bitSet  the initial bit values for this chromosome
39  	 * @throws IllegalArgumentException if numBits is zero or negative, if bitSet is null, or if numBits exceeds the
40  	 *                                  bitSet size
41  	 */
42  	public BitChromosome(final int _numBits, final BitSet _bitSet) {
43  		Validate.isTrue(_numBits > 0, "numBits can't be zero or negative");
44  		Objects.requireNonNull(_bitSet);
45  		Validate.isTrue(_numBits <= _bitSet.size());
46  
47  		this.numBits = _numBits;
48  		this.bitSet = new BitSet(numBits);
49  		this.bitSet.or(_bitSet);
50  	}
51  
52  	@Override
53  	public int getNumAlleles() {
54  		return numBits;
55  	}
56  
57  	/**
58  	 * Returns the bit value at the specified index.
59  	 * 
60  	 * @param index the index of the bit to retrieve (0-based)
61  	 * @return {@code true} if the bit is set (1), {@code false} if clear (0)
62  	 * @throws IllegalArgumentException if index is negative or greater than or equal to numBits
63  	 */
64  	public boolean getBit(final int index) {
65  		Validate.isTrue(index >= 0);
66  		Validate.isTrue(index < numBits);
67  
68  		return bitSet.get(index);
69  	}
70  
71  	/**
72  	 * Returns the underlying BitSet containing all bit values.
73  	 * 
74  	 * <p>The returned BitSet is a copy and modifications to it will not affect this chromosome.
75  	 * 
76  	 * @return a BitSet containing the bit values of this chromosome
77  	 */
78  	public BitSet getBitSet() {
79  		return bitSet;
80  	}
81  
82  	/**
83  	 * Returns the number of bits set to 1 in this chromosome.
84  	 *
85  	 * <p>This method counts all bits that are set to true (1) in the chromosome's bit sequence.
86  	 *
87  	 * @return the count of bits set to 1, ranging from 0 to numBits
88  	 */
89  	public int countOnes() {
90  		return bitSet.cardinality();
91  	}
92  
93  	/**
94  	 * Returns the number of bits set to 0 in this chromosome.
95  	 *
96  	 * <p>This method counts all bits that are set to false (0) in the chromosome's bit sequence. This is the complement
97  	 * of {@link #countOnes()}.
98  	 *
99  	 * @return the count of bits set to 0, ranging from 0 to numBits
100 	 * @see #countOnes()
101 	 */
102 	public int countZeros() {
103 		return numBits - countOnes();
104 	}
105 
106 	@Override
107 	public int hashCode() {
108 		final int prime = 31;
109 		int result = 1;
110 		result = prime * result + (bitSet == null ? 0 : bitSet.hashCode());
111 		return prime * result + numBits;
112 	}
113 
114 	@Override
115 	public boolean equals(Object obj) {
116 		if (this == obj) {
117 			return true;
118 		}
119 		if (obj == null) {
120 			return false;
121 		}
122 		if (getClass() != obj.getClass()) {
123 			return false;
124 		}
125 		BitChromosome other = (BitChromosome) obj;
126 		if (bitSet == null) {
127 			if (other.bitSet != null) {
128 				return false;
129 			}
130 		} else if (!bitSet.equals(other.bitSet)) {
131 			return false;
132 		}
133 		return !(numBits != other.numBits);
134 	}
135 
136 	@Override
137 	public String toString() {
138 		return "BitChromosome [numBits=" + numBits + ", bitSet=" + bitSet + "]";
139 	}
140 }