001 /*
002 * Java Genetic Algorithm Library (jenetics-4.2.0).
003 * Copyright (c) 2007-2018 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@gmail.com)
019 */
020 package io.jenetics;
021
022 import static java.lang.String.format;
023
024 import java.io.Serializable;
025 import java.util.Objects;
026
027 import io.jenetics.util.ISeq;
028 import io.jenetics.util.RandomRegistry;
029
030 /**
031 * <p>
032 * Gene which holds enumerable (countable) genes. Will be used for combinatorial
033 * problems in combination with the {@link PermutationChromosome}.
034 * </p>
035 * The following code shows how to create a combinatorial genotype factory which
036 * can be used when creating an {@link io.jenetics.engine.Engine} instance.
037 * <pre>{@code
038 * final ISeq<Integer> alleles = ISeq.of(1, 2, 3, 4, 5, 6, 7, 8);
039 * final Factory<Genotype<EnumGene<Integer>>> gtf = Genotype.of(
040 * PermutationChromosome.of(alleles)
041 * );
042 * }</pre>
043 *
044 * The following code shows the assurances of the {@code EnumGene}.
045 * <pre>{@code
046 * final ISeq<Integer> alleles = ISeq.of(1, 2, 3, 4, 5, 6, 7, 8);
047 * final EnumGene<Integer> gene = new EnumGene<>(5, alleles);
048 *
049 * assert(gene.getAlleleIndex() == 5);
050 * assert(gene.getAllele() == gene.getValidAlleles().get(5));
051 * assert(gene.getValidAlleles() == alleles);
052 * }</pre>
053 *
054 * @see PermutationChromosome
055 * @see PartiallyMatchedCrossover
056 *
057 * @implNote
058 * This class is immutable and thread-safe.
059 *
060 * @author <a href="mailto:franz.wilhelmstoetter@gmail.com">Franz Wilhelmstötter</a>
061 * @since 1.0
062 * @version 4.0
063 */
064 public final class EnumGene<A>
065 implements
066 Gene<A, EnumGene<A>>,
067 Comparable<EnumGene<A>>,
068 Serializable
069 {
070
071 private static final long serialVersionUID = 2L;
072
073 private final ISeq<A> _validAlleles;
074 private final int _alleleIndex;
075
076 /**
077 * Create a new enum gene from the given valid genes and the chosen allele
078 * index.
079 *
080 * @param alleleIndex the index of the allele for this gene.
081 * @param validAlleles the sequence of valid alleles.
082 * @throws IllegalArgumentException if the give valid alleles sequence is
083 * empty
084 * @throws NullPointerException if the valid alleles seq is {@code null}.
085 */
086 EnumGene(final int alleleIndex, final ISeq<? extends A> validAlleles) {
087 if (validAlleles.isEmpty()) {
088 throw new IllegalArgumentException(
089 "Array of valid alleles must be greater than zero."
090 );
091 }
092
093 if (alleleIndex < 0 || alleleIndex >= validAlleles.length()) {
094 throw new IndexOutOfBoundsException(format(
095 "Allele index is not in range [0, %d).", alleleIndex
096 ));
097 }
098
099 _validAlleles = ISeq.upcast(validAlleles);
100 _alleleIndex = alleleIndex;
101 }
102
103 /**
104 * Return sequence of the valid alleles where this gene is a part of.
105 *
106 * @return the sequence of the valid alleles.
107 */
108 public ISeq<A> getValidAlleles() {
109 return _validAlleles;
110 }
111
112 /**
113 * Return the index of the allele this gene is representing.
114 *
115 * @return the index of the allele this gene is representing.
116 */
117 public int getAlleleIndex() {
118 return _alleleIndex;
119 }
120
121 @Override
122 public A getAllele() {
123 return _validAlleles.get(_alleleIndex);
124 }
125
126 @Override
127 public boolean isValid() {
128 return _alleleIndex >= 0 && _alleleIndex < _validAlleles.length();
129 }
130
131 @Override
132 public EnumGene<A> newInstance() {
133 return new EnumGene<>(
134 RandomRegistry.getRandom().nextInt(_validAlleles.length()),
135 _validAlleles
136 );
137 }
138
139 /**
140 * Create a new gene from the given {@code value} and the gene context.
141 *
142 * @since 1.6
143 *
144 * @param value the value of the new gene.
145 * @return a new gene with the given value.
146 */
147 public EnumGene<A> newInstance(final A value) {
148 return new EnumGene<>(
149 _validAlleles.indexOf(value),
150 _validAlleles
151 );
152 }
153
154 @Override
155 public int compareTo(final EnumGene<A> gene) {
156 int result = 0;
157 if (_alleleIndex > gene._alleleIndex) {
158 result = 1;
159 } else if (_alleleIndex < gene._alleleIndex) {
160 result = -1;
161 }
162
163 return result;
164 }
165
166 @Override
167 public int hashCode() {
168 int hash = 17;
169 hash += 31*_alleleIndex + 37;
170 hash += 31*_validAlleles.hashCode() + 37;
171 return hash;
172 }
173
174 @Override
175 public boolean equals(final Object obj) {
176 return obj instanceof EnumGene &&
177 Objects.equals(((EnumGene)obj)._alleleIndex, _alleleIndex) &&
178 Objects.equals(((EnumGene)obj)._validAlleles, _validAlleles);
179 }
180
181 @Override
182 public String toString() {
183 return Objects.toString(getAllele());
184 }
185
186
187 /* *************************************************************************
188 * Static object creation methods
189 * ************************************************************************/
190
191 /**
192 * Create a new enum gene from the given valid genes and the chosen allele
193 * index.
194 *
195 * @since 3.4
196 *
197 * @param <A> the allele type
198 * @param alleleIndex the index of the allele for this gene.
199 * @param validAlleles the sequence of valid alleles.
200 * @return a new {@code EnumGene} with the given with the allele
201 * {@code validAlleles.get(alleleIndex)}
202 * @throws IllegalArgumentException if the give valid alleles sequence is
203 * empty
204 * @throws NullPointerException if the valid alleles seq is {@code null}.
205 */
206 public static <A> EnumGene<A> of(
207 final int alleleIndex,
208 final ISeq<? extends A> validAlleles
209 ) {
210 return new EnumGene<>(alleleIndex, validAlleles);
211 }
212
213 /**
214 * Return a new enum gene with an allele randomly chosen from the given
215 * valid alleles.
216 *
217 * @param <A> the allele type
218 * @param validAlleles the sequence of valid alleles.
219 * @return a new {@code EnumGene} with an randomly chosen allele from the
220 * sequence of valid alleles
221 * @throws java.lang.IllegalArgumentException if the give valid alleles
222 * sequence is empty
223 * @throws NullPointerException if the valid alleles seq is {@code null}.
224 */
225 public static <A> EnumGene<A> of(final ISeq<? extends A> validAlleles) {
226 return new EnumGene<>(
227 RandomRegistry.getRandom().nextInt(validAlleles.length()),
228 validAlleles
229 );
230 }
231
232 /**
233 * Create a new enum gene from the given valid genes and the chosen allele
234 * index.
235 *
236 * @param <A> the allele type
237 * @param alleleIndex the index of the allele for this gene.
238 * @param validAlleles the array of valid alleles.
239 * @return a new {@code EnumGene} with the given with the allele
240 * {@code validAlleles[alleleIndex]}
241 * @throws java.lang.IllegalArgumentException if the give valid alleles
242 * array is empty of the allele index is out of range.
243 */
244 @SafeVarargs
245 public static <A> EnumGene<A> of(
246 final int alleleIndex,
247 final A... validAlleles
248 ) {
249 return new EnumGene<>(alleleIndex, ISeq.of(validAlleles));
250 }
251
252 /**
253 * Return a new enum gene with an allele randomly chosen from the given
254 * valid alleles.
255 *
256 * @param <A> the allele type
257 * @param validAlleles the array of valid alleles.
258 * @return a new {@code EnumGene} with an randomly chosen allele from the
259 * sequence of valid alleles
260 * @throws IllegalArgumentException if the give valid alleles array is empty
261 */
262 @SafeVarargs
263 public static <A> EnumGene<A> of(final A... validAlleles) {
264 return EnumGene.of(ISeq.of(validAlleles));
265 }
266
267 }
|