001 /*
002 * Java Genetic Algorithm Library (jenetics-3.0.0).
003 * Copyright (c) 2007-2014 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.internal.util.Equality.eq;
024
025 import java.util.List;
026 import java.util.Objects;
027 import java.util.function.Function;
028
029 import javax.xml.bind.annotation.XmlAccessType;
030 import javax.xml.bind.annotation.XmlAccessorType;
031 import javax.xml.bind.annotation.XmlAttribute;
032 import javax.xml.bind.annotation.XmlElement;
033 import javax.xml.bind.annotation.XmlElementWrapper;
034 import javax.xml.bind.annotation.XmlRootElement;
035 import javax.xml.bind.annotation.XmlType;
036 import javax.xml.bind.annotation.adapters.XmlAdapter;
037 import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
038
039 import org.jenetics.internal.util.Equality;
040 import org.jenetics.internal.util.Hash;
041 import org.jenetics.internal.util.jaxb;
042 import org.jenetics.internal.util.model.IndexedObject;
043 import org.jenetics.internal.util.reflect;
044
045 import org.jenetics.util.ISeq;
046 import org.jenetics.util.RandomRegistry;
047
048 /**
049 * <p>
050 * Gene which holds enumerable (countable) genes. Will be used for combinatorial
051 * problems in combination with the {@link PermutationChromosome}.
052 * </p>
053 * The following code shows how to create a combinatorial genotype factory which
054 * can be used when creating an {@link org.jenetics.engine.Engine} instance.
055 * [code]
056 * final ISeq<Integer> alleles = ISeq.of(1, 2, 3, 4, 5, 6, 7, 8);
057 * final Factory<Genotype<EnumGene<Integer>>> gtf = Genotype.of(
058 * PermutationChromosome.of(alleles)
059 * );
060 * [/code]
061 *
062 * The following code shows the assurances of the {@code EnumGene}.
063 * [code]
064 * final ISeq<Integer> alleles = ISeq.of(1, 2, 3, 4, 5, 6, 7, 8);
065 * final EnumGene<Integer> gene = new EnumGene<>(5, alleles);
066 *
067 * assert(gene.getAlleleIndex() == 5);
068 * assert(gene.getAllele() == gene.getValidAlleles().get(5));
069 * assert(gene.getValidAlleles() == alleles);
070 * [/code]
071 *
072 * @see PermutationChromosome
073 *
074 * @author <a href="mailto:franz.wilhelmstoetter@gmx.at">Franz Wilhelmstötter</a>
075 * @since 1.0
076 * @version 2.0 — <em>$Date: 2014-12-28 $</em>
077 */
078 @XmlJavaTypeAdapter(EnumGene.Model.Adapter.class)
079 public final class EnumGene<A>
080 implements
081 Gene<A, EnumGene<A>>,
082 Comparable<EnumGene<A>>
083 {
084
085 private static final long serialVersionUID = 2L;
086
087 private final ISeq<A> _validAlleles;
088 private final int _alleleIndex;
089
090 /**
091 * Create a new enum gene from the given valid genes and the chosen allele
092 * index.
093 * @param alleleIndex the index of the allele for this gene.
094 * @param validAlleles the sequence of valid alleles.
095 * @throws IllegalArgumentException if the give valid alleles sequence is
096 * empty
097 * @throws NullPointerException if the valid alleles seq is {@code null}.
098 */
099 EnumGene(final int alleleIndex, final ISeq<? extends A> validAlleles) {
100 if (validAlleles.length() == 0) {
101 throw new IllegalArgumentException(
102 "Array of valid alleles must be greater than zero."
103 );
104 }
105
106 if (alleleIndex < 0 || alleleIndex >= validAlleles.length()) {
107 throw new IndexOutOfBoundsException(format(
108 "Allele index is not in range [0, %d).", alleleIndex
109 ));
110 }
111
112 _validAlleles = reflect.cast(validAlleles);
113 _alleleIndex = alleleIndex;
114 }
115
116 /**
117 * Return sequence of the valid alleles where this gene is a part of.
118 *
119 * @return the sequence of the valid alleles.
120 */
121 public ISeq<A> getValidAlleles() {
122 return _validAlleles;
123 }
124
125 /**
126 * Return the index of the allele this gene is representing.
127 *
128 * @return the index of the allele this gene is representing.
129 */
130 public int getAlleleIndex() {
131 return _alleleIndex;
132 }
133
134 @Override
135 public A getAllele() {
136 return _validAlleles.get(_alleleIndex);
137 }
138
139 @Override
140 public boolean isValid() {
141 return _alleleIndex >= 0 && _alleleIndex < _validAlleles.length();
142 }
143
144 @Override
145 public EnumGene<A> newInstance() {
146 return new EnumGene<>(
147 RandomRegistry.getRandom().nextInt(_validAlleles.length()),
148 _validAlleles
149 );
150 }
151
152 /**
153 * Create a new gene from the given {@code value} and the gene context.
154 *
155 * @since 1.6
156 * @param value the value of the new gene.
157 * @return a new gene with the given value.
158 */
159 public EnumGene<A> newInstance(final A value) {
160 return new EnumGene<>(
161 _validAlleles.indexOf(value),
162 _validAlleles
163 );
164 }
165
166 @Override
167 public int compareTo(final EnumGene<A> gene) {
168 int result = 0;
169 if (_alleleIndex > gene._alleleIndex) {
170 result = 1;
171 } else if (_alleleIndex < gene._alleleIndex) {
172 result = -1;
173 }
174
175 return result;
176 }
177
178 @Override
179 public int hashCode() {
180 return Hash.of(EnumGene.class)
181 .and(_alleleIndex)
182 .and(_validAlleles).value();
183 }
184
185 @Override
186 public boolean equals(final Object obj) {
187 return Equality.of(this, obj).test(pg ->
188 eq(_alleleIndex, pg._alleleIndex) &&
189 eq(_validAlleles, pg._validAlleles)
190 );
191 }
192
193 @Override
194 public String toString() {
195 return Objects.toString(getAllele());
196 }
197
198 /* *************************************************************************
199 * Static object creation methods
200 * ************************************************************************/
201
202 /**
203 * Return a new enum gene with an allele randomly chosen from the given
204 * valid alleles.
205 *
206 * @param <A> the allele type
207 * @param validAlleles the sequence of valid alleles.
208 * @return a new {@code EnumGene} with the given parameter
209 * @throws java.lang.IllegalArgumentException if the give valid alleles
210 * sequence is empty
211 * @throws NullPointerException if the valid alleles seq is {@code null}.
212 */
213 public static <A> EnumGene<A> of(final ISeq<? extends A> validAlleles) {
214 return new EnumGene<>(
215 RandomRegistry.getRandom().nextInt(validAlleles.length()),
216 validAlleles
217 );
218 }
219
220 /**
221 * Create a new enum gene from the given valid genes and the chosen allele
222 * index.
223 *
224 * @param <A> the allele type
225 * @param alleleIndex the index of the allele for this gene.
226 * @param validAlleles the array of valid alleles.
227 * @return a new {@code EnumGene} with the given parameter
228 * @throws java.lang.IllegalArgumentException if the give valid alleles
229 * array is empty of the allele index is out of range.
230 */
231 @SafeVarargs
232 public static <A> EnumGene<A> of(
233 final int alleleIndex,
234 final A... validAlleles
235 ) {
236 return new EnumGene<>(alleleIndex, ISeq.of(validAlleles));
237 }
238
239 /**
240 * Return a new enum gene with an allele randomly chosen from the given
241 * valid alleles.
242 *
243 * @param <A> the allele type
244 * @param validAlleles the array of valid alleles.
245 * @return a new {@code EnumGene} with the given parameter
246 * @throws java.lang.IllegalArgumentException if the give valid alleles
247 * array is empty
248 */
249 @SafeVarargs
250 public static <A> EnumGene<A> of(final A... validAlleles) {
251 return EnumGene.of(ISeq.of(validAlleles));
252 }
253
254 /* *************************************************************************
255 * JAXB object serialization
256 * ************************************************************************/
257
258 @XmlRootElement(name = "enum-gene")
259 @XmlType(name = "org.jenetics.EnumGene")
260 @XmlAccessorType(XmlAccessType.FIELD)
261 @SuppressWarnings({"unchecked", "rawtypes"})
262 final static class Model {
263
264 @XmlAttribute(name = "length", required = true)
265 public int length;
266
267 @XmlElementWrapper(name = "valid-alleles", required = true, nillable = false)
268 @XmlElement(name = "allele", required = true, nillable = false)
269 public List alleles;
270
271 @XmlElement(name = "allele", required = true, nillable = false)
272 public IndexedObject allele = new IndexedObject();
273
274 public static final class Adapter
275 extends XmlAdapter<Model, EnumGene>
276 {
277 @Override
278 public Model marshal(final EnumGene gene) {
279 final Function marshaller = jaxb.Marshaller(gene.getAllele());
280 final Model m = new Model();
281 m.length = gene.getValidAlleles().length();
282 m.allele.index = gene.getAlleleIndex();
283 m.allele.value = marshaller.apply(gene.getAllele());
284 m.alleles = gene.getValidAlleles()
285 .map(marshaller)
286 .asList();
287
288 return m;
289 }
290
291 @Override
292 public EnumGene unmarshal(final Model m) {
293 return new EnumGene<>(
294 m.allele.index,
295 ISeq.of(m.alleles)
296 .map(jaxb.Unmarshaller(m.allele.value))
297 );
298 }
299
300 }
301 }
302
303 }
|