EnumGene.java
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 &mdash; <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 < || 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