001 /*
002 * Java Genetic Algorithm Library (jenetics-1.5.0).
003 * Copyright (c) 2007-2013 Franz Wilhelmstötter
004 *
005 * Licensed under the Apache License, Version 2.0 (the "License");
006 * you may not use this file except in compliance with the License.
007 * You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 *
017 * Author:
018 * Franz Wilhelmstötter (franz.wilhelmstoetter@gmx.at)
019 */
020 package org.jenetics;
021
022 import static java.lang.String.format;
023 import static org.jenetics.util.object.eq;
024 import static org.jenetics.util.object.hashCodeOf;
025
026 import java.util.Objects;
027 import java.util.Random;
028
029 import javolution.context.ObjectFactory;
030
031 import org.jenetics.internal.util.cast;
032
033 import org.jenetics.util.Array;
034 import org.jenetics.util.Factory;
035 import org.jenetics.util.Function;
036 import org.jenetics.util.ISeq;
037 import org.jenetics.util.RandomRegistry;
038
039 /**
040 * <p>
041 * Gene which holds enumerable (countable) genes. Will be used for combinatorial
042 * problems in combination with the {@link PermutationChromosome}.
043 * </p>
044 * The following code shows how to create a combinatorial genotype factory which
045 * can be used when creating an {@link GeneticAlgorithm} instance.
046 * [code]
047 * final ISeq〈Integer〉 alleles = Array.box(1, 2, 3, 4, 5, 6, 7, 8).toISeq();
048 * final Factory〈Genotype〈EnumGene〈Integer〉〉〉 gtf = Genotype.valueOf(
049 * PermutationChromosome.valueOf(alleles)
050 * );
051 * [/code]
052 *
053 * The following code shows the assurances of the {@code EnumGene}.
054 * [code]
055 * final ISeq〈Integer〉 alleles = Array.box(1, 2, 3, 4, 5, 6, 7, 8).toISeq();
056 * final EnumGene〈Integer〉 gene = EnumGene.valueOf(alleles, 5);
057 *
058 * assert(gene.getAlleleIndex() == 5);
059 * assert(gene.getAllele() == gene.getValidAlleles().get(5));
060 * assert(gene.getValidAlleles() == alleles);
061 * [/code]
062 *
063 * @see PermutationChromosome
064 *
065 * @author <a href="mailto:franz.wilhelmstoetter@gmx.at">Franz Wilhelmstötter</a>
066 * @since 1.0
067 * @version 1.5 — <em>$Date: 2013-12-09 $</em>
068 */
069 public final class EnumGene<A>
070 implements
071 Gene<A, EnumGene<A>>,
072 Comparable<EnumGene<A>>
073 {
074
075 private static final long serialVersionUID = 1L;
076
077 private ISeq<A> _validAlleles;
078 private int _alleleIndex = -1;
079
080 EnumGene() {
081 }
082
083 /**
084 * Return sequence of the valid alleles where this gene is a part of.
085 *
086 * @return the sequence of the valid alleles.
087 */
088 public ISeq<A> getValidAlleles() {
089 return _validAlleles;
090 }
091
092 /**
093 * Return the index of the allele this gene is representing.
094 *
095 * @return the index of the allele this gene is representing.
096 */
097 public int getAlleleIndex() {
098 return _alleleIndex;
099 }
100
101 @Override
102 public A getAllele() {
103 return _validAlleles.get(_alleleIndex);
104 }
105
106 @Override
107 public EnumGene<A> copy() {
108 final EnumGene<A> gene = new EnumGene<>();
109 gene._validAlleles = _validAlleles;
110 gene._alleleIndex = _alleleIndex;
111 return gene;
112 }
113
114 @Override
115 public boolean isValid() {
116 return true;
117 }
118
119 @Override
120 public EnumGene<A> newInstance() {
121 @SuppressWarnings("unchecked")
122 final EnumGene<A> gene = FACTORY.object();
123 final Random random = RandomRegistry.getRandom();
124
125 gene._alleleIndex = random.nextInt(_validAlleles.length());
126 gene._validAlleles = _validAlleles;
127 return gene;
128 }
129
130 @Override
131 public int compareTo(final EnumGene<A> gene) {
132 int result = 0;
133 if (_alleleIndex > gene._alleleIndex) {
134 result = 1;
135 } else if (_alleleIndex < gene._alleleIndex) {
136 result = -1;
137 }
138
139 return result;
140 }
141
142 /**
143 * @deprecated No longer needed after adding new factory methods to the
144 * {@link Array} class.
145 */
146 @Deprecated
147 public Factory<EnumGene<A>> asFactory() {
148 return this;
149 }
150
151 @Override
152 public int hashCode() {
153 return hashCodeOf(EnumGene.class)
154 .and(_alleleIndex)
155 .and(_validAlleles).value();
156 }
157
158 @Override
159 public boolean equals(final Object obj) {
160 if (obj == this) {
161 return true;
162 }
163 if (obj == null || getClass() != obj.getClass()) {
164 return false;
165 }
166
167 final EnumGene<?> pg = (EnumGene<?>)obj;
168 return eq(_alleleIndex, pg._alleleIndex) &&
169 eq(_validAlleles, pg._validAlleles);
170 }
171
172 @Override
173 public String toString() {
174 return Objects.toString(getAllele());
175 }
176
177 /* *************************************************************************
178 * Static object creation methods
179 * ************************************************************************/
180
181 static <T> Function<Integer, EnumGene<T>> ToGene(
182 final ISeq<T> validAlleles
183 ) {
184 return new Function<Integer, EnumGene<T>>() {
185 @Override
186 public EnumGene<T> apply(final Integer index) {
187 return valueOf(validAlleles, index);
188 }
189 };
190 }
191
192 static <T> Factory<EnumGene<T>> Gene(final ISeq<? extends T> validAlleles) {
193 return new Factory<EnumGene<T>>() {
194 private int _index = 0;
195 @Override
196 public EnumGene<T> newInstance() {
197 return EnumGene.valueOf(validAlleles, _index++);
198 }
199 };
200 }
201
202
203 @SuppressWarnings("rawtypes")
204 private static final ObjectFactory<EnumGene>
205 FACTORY = new ObjectFactory<EnumGene>() {
206 @Override
207 protected EnumGene create() {
208 return new EnumGene();
209 }
210 };
211
212 public static <G> EnumGene<G> valueOf(
213 final G[] validAlleles,
214 final int alleleIndex
215 ) {
216 return valueOf(Array.valueOf(validAlleles).toISeq(), alleleIndex);
217 }
218
219 public static <G> EnumGene<G> valueOf(
220 final ISeq<? extends G> validAlleles,
221 final int alleleIndex
222 ) {
223 if (validAlleles.length() == 0) {
224 throw new IllegalArgumentException(
225 "Array of valid alleles must be greater than zero."
226 );
227 }
228
229 if (alleleIndex < 0 || alleleIndex >= validAlleles.length()) {
230 throw new IndexOutOfBoundsException(format(
231 "Allele index is not in range [0, %d).", alleleIndex
232 ));
233 }
234
235 @SuppressWarnings("unchecked")
236 final EnumGene<G> gene = FACTORY.object();
237
238 gene._validAlleles = cast.apply(validAlleles);
239 gene._alleleIndex = alleleIndex;
240 return gene;
241 }
242
243 public static <G> EnumGene<G> valueOf(final G[] validAlleles) {
244 return valueOf(Array.valueOf(validAlleles).toISeq());
245 }
246
247 public static <G> EnumGene<G> valueOf(final ISeq<G> validAlleles) {
248 if (validAlleles.length() == 0) {
249 throw new IllegalArgumentException(
250 "Array of valid alleles must be greater than zero."
251 );
252 }
253
254 @SuppressWarnings("unchecked")
255 final EnumGene<G> gene = FACTORY.object();
256 gene._validAlleles = validAlleles;
257 gene._alleleIndex = RandomRegistry.getRandom().nextInt(validAlleles.length());
258 return gene;
259 }
260
261 }
262
263
264
265
|