001 /*
002 * Java Genetic Algorithm Library (jenetics-1.6.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 org.jenetics.EnumGene.Gene;
023 import static org.jenetics.util.factories.Int;
024 import static org.jenetics.util.functions.StringToInteger;
025
026 import java.io.IOException;
027 import java.io.ObjectInputStream;
028 import java.io.ObjectOutputStream;
029 import java.util.Arrays;
030 import java.util.List;
031
032 import javax.xml.bind.annotation.XmlAccessType;
033 import javax.xml.bind.annotation.XmlAccessorType;
034 import javax.xml.bind.annotation.XmlAnyElement;
035 import javax.xml.bind.annotation.XmlAttribute;
036 import javax.xml.bind.annotation.XmlElement;
037 import javax.xml.bind.annotation.XmlRootElement;
038 import javax.xml.bind.annotation.XmlType;
039 import javax.xml.bind.annotation.adapters.XmlAdapter;
040 import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
041
042 import javolution.xml.XMLFormat;
043 import javolution.xml.XMLSerializable;
044 import javolution.xml.stream.XMLStreamException;
045
046 import org.jenetics.internal.util.HashBuilder;
047 import org.jenetics.internal.util.cast;
048 import org.jenetics.internal.util.jaxb;
049 import org.jenetics.internal.util.model;
050
051 import org.jenetics.util.Array;
052 import org.jenetics.util.Factory;
053 import org.jenetics.util.Function;
054 import org.jenetics.util.ISeq;
055 import org.jenetics.util.bit;
056
057
058 /**
059 * The mutable methods of the {@link AbstractChromosome} has been overridden so
060 * that no invalid permutation will be created.
061 *
062 * @author <a href="mailto:franz.wilhelmstoetter@gmx.at">Franz Wilhelmstötter</a>
063 * @since 1.0
064 * @version 1.6 — <em>$Date: 2014-03-07 $</em>
065 */
066 @XmlJavaTypeAdapter(PermutationChromosome.Model.Adapter.class)
067 public final class PermutationChromosome<T>
068 extends AbstractChromosome<EnumGene<T>>
069 implements XMLSerializable
070 {
071 private static final long serialVersionUID = 1L;
072
073 private ISeq<T> _validAlleles;
074
075 /*
076 * TODO: Refactor this to the default constructor in version 2.0. Currently
077 * not possible, because this would be an incompatible change.
078 */
079 PermutationChromosome(
080 final ISeq<EnumGene<T>> genes,
081 final boolean internal
082 ) {
083 super(genes);
084 _validAlleles = genes.get(0).getValidAlleles();
085 _valid = true;
086 }
087
088 /**
089 * Create a new, random chromosome with the given valid alleles.
090 *
091 * @param validAlleles the valid alleles used for this permutation arrays.
092 */
093 public PermutationChromosome(final ISeq<? extends T> validAlleles) {
094 this(
095 new Array<EnumGene<T>>(
096 validAlleles.length()
097 ).fill(Gene(validAlleles)).shuffle().toISeq(),
098 true
099 );
100 _validAlleles = cast.apply(validAlleles);
101 }
102
103 public ISeq<T> getValidAlleles() {
104 return _validAlleles;
105 }
106
107 /**
108 * Check if this chromosome represents still a valid permutation.
109 */
110 @Override
111 public boolean isValid() {
112 if (_valid == null) {
113 byte[] check = new byte[length()/8 + 1];
114 Arrays.fill(check, (byte)0);
115
116 boolean valid = super.isValid();
117 for (int i = 0; i < length() && valid; ++i) {
118 final int value = _genes.get(i).getAlleleIndex();
119 if (value >= 0 && value < length()) {
120 if (bit.get(check, value)) {
121 valid = false;
122 } else {
123 bit.set(check, value, true);
124 }
125 } else {
126 valid = false;
127 }
128 }
129
130 _valid = valid;
131 }
132
133 return _valid;
134 }
135
136 /**
137 * Return a more specific view of this chromosome factory.
138 *
139 * @return a more specific view of this chromosome factory.
140 *
141 * @deprecated No longer needed after adding new factory methods to the
142 * {@link Array} class.
143 */
144 @Deprecated
145 @SuppressWarnings("unchecked")
146 public Factory<PermutationChromosome<T>> asFactory() {
147 return (Factory<PermutationChromosome<T>>)(Object)this;
148 }
149
150 /**
151 * Create a new, <em>random</em> chromosome.
152 */
153 @Override
154 public PermutationChromosome<T> newInstance() {
155 return new PermutationChromosome<>(_validAlleles);
156 }
157
158 @Override
159 public PermutationChromosome<T> newInstance(final ISeq<EnumGene<T>> genes) {
160 return new PermutationChromosome<>(genes, true);
161 }
162
163 @Override
164 public int hashCode() {
165 return HashBuilder.of(getClass())
166 .and(super.hashCode())
167 .value();
168 }
169
170 @Override
171 public boolean equals(final Object obj) {
172 if (obj == this) {
173 return true;
174 }
175 if (obj == null || getClass() != obj.getClass()) {
176 return false;
177 }
178 return super.equals(obj);
179 }
180
181 @Override
182 public String toString() {
183 final StringBuilder out = new StringBuilder();
184 out.append(_genes.get(0).getAllele());
185 for (int i = 1; i < length(); ++i) {
186 out.append("|").append(_genes.get(i).getAllele());
187 }
188 return out.toString();
189 }
190
191 /**
192 * Create a new PermutationChromosome from the given genes.
193 *
194 * @param genes the genes of this chromosome.
195 * @return a new PermutationChromosome from the given genes.
196 *
197 * @deprecated Use {@link #of(org.jenetics.util.ISeq)} instead.
198 */
199 @Deprecated
200 public static <T> PermutationChromosome<T> valueOf(
201 final ISeq<EnumGene<T>> genes
202 ) {
203 return new PermutationChromosome<>(genes, true);
204 }
205
206 /**
207 * Create a new PermutationChromosome from the given genes.
208 *
209 * @param genes the genes of this chromosome.
210 * @return a new PermutationChromosome from the given genes.
211 */
212 public static <T> PermutationChromosome<T> of(final ISeq<EnumGene<T>> genes) {
213 return new PermutationChromosome<>(genes, true);
214 }
215
216 /**
217 * Create a integer permutation chromosome with the given length.
218 *
219 * @param length the chromosome length.
220 * @return a integer permutation chromosome with the given length.
221 */
222 @SuppressWarnings("deprecation")
223 public static PermutationChromosome<Integer> ofInteger(final int length) {
224 final ISeq<Integer> alleles = new Array<Integer>(length).fill(Int()).toISeq();
225 return new PermutationChromosome<>(alleles);
226 }
227
228 /* *************************************************************************
229 * Java object serialization
230 * ************************************************************************/
231
232 private void writeObject(final ObjectOutputStream out)
233 throws IOException
234 {
235 out.defaultWriteObject();
236
237 out.writeObject(_validAlleles);
238 for (EnumGene<?> gene : _genes) {
239 out.writeInt(gene.getAlleleIndex());
240 }
241 }
242
243 @SuppressWarnings("unchecked")
244 private void readObject(final ObjectInputStream in)
245 throws IOException, ClassNotFoundException
246 {
247 in.defaultReadObject();
248
249 _validAlleles = (ISeq<T>)in.readObject();
250
251 final Array<EnumGene<T>> genes = new Array<>(_validAlleles.length());
252 for (int i = 0; i < _validAlleles.length(); ++i) {
253 genes.set(i, new EnumGene<>(in.readInt(), _validAlleles));
254 }
255
256 _genes = genes.toISeq();
257 }
258
259 /* *************************************************************************
260 * XML object serialization
261 * ************************************************************************/
262
263 @SuppressWarnings("rawtypes")
264 static final XMLFormat<PermutationChromosome>
265 XML = new XMLFormat<PermutationChromosome>(PermutationChromosome.class) {
266
267 private static final String LENGTH = "length";
268 private static final String ALLELE_INDEXES = "allele-indexes";
269
270 @SuppressWarnings("unchecked")
271 @Override
272 public PermutationChromosome newInstance(
273 final Class<PermutationChromosome> cls,
274 final InputElement xml
275 )
276 throws XMLStreamException
277 {
278 final int length = xml.getAttribute(LENGTH, 0);
279 final Array<Object> alleles = new Array<>(length);
280 for (int i = 0; i < length; ++i) {
281 alleles.set(i, xml.getNext());
282 }
283
284 final ISeq<Object> ialleles = alleles.toISeq();
285
286 final Array<Integer> indexes = Array.of(
287 xml.get(ALLELE_INDEXES, String.class
288 ).split(",")).map(StringToInteger);
289
290 final Array<Object> genes = new Array<>(length);
291 for (int i = 0; i < length; ++i) {
292 genes.set(i, new EnumGene<>(indexes.get(i), ialleles));
293 }
294
295 return new PermutationChromosome(genes.toISeq(), true);
296 }
297
298 @Override
299 public void write(
300 final PermutationChromosome chromosome,
301 final OutputElement xml
302 )
303 throws XMLStreamException
304 {
305 xml.setAttribute(LENGTH, chromosome.length());
306 for (Object allele : chromosome.getValidAlleles()) {
307 xml.add(allele);
308 }
309
310 final PermutationChromosome<?> pc = chromosome;
311 final String indexes = pc.toSeq().map(new Function<Object, Integer>() {
312 @Override public Integer apply(final Object value) {
313 return ((EnumGene<?>)value).getAlleleIndex();
314 }
315 }).toString(",");
316 xml.add(indexes, ALLELE_INDEXES);
317 }
318 @Override
319 public void read(
320 final InputElement element,
321 final PermutationChromosome chromosome
322 ) {
323 }
324 };
325
326 /* *************************************************************************
327 * JAXB object serialization
328 * ************************************************************************/
329
330
331 @XmlRootElement(name = "org.jenetics.PermutationChromosome")
332 @XmlType(name = "org.jenetics.PermutationChromosome")
333 @XmlAccessorType(XmlAccessType.FIELD)
334 @SuppressWarnings({"unchecked", "rawtypes"})
335 static final class Model {
336
337 @XmlAttribute
338 public int length;
339
340 @XmlAnyElement
341 public List<Object> genes;
342
343 @XmlJavaTypeAdapter(jaxb.JavolutionElementAdapter.class)
344 @XmlElement(name = "allele-indexes")
345 public Object indexes;
346
347 @model.ValueType(PermutationChromosome.class)
348 @model.ModelType(Model.class)
349 public static final class Adapter
350 extends XmlAdapter<Model, PermutationChromosome>
351 {
352 @Override
353 public Model marshal(final PermutationChromosome pc)
354 throws Exception
355 {
356 final Model model = new Model();
357 model.length = pc.length();
358 model.genes = pc.getValidAlleles()
359 .map(jaxb.Marshaller(pc.getValidAlleles().get(0))).asList();
360 model.indexes = jaxb.marshal(pc.toSeq().map(new Function<Object, Integer>() {
361 @Override public Integer apply(final Object value) {
362 return ((EnumGene<?>)value).getAlleleIndex();
363 }
364 }).toString(","));
365 return model;
366 }
367
368 @Override
369 public PermutationChromosome unmarshal(final Model model)
370 throws Exception
371 {
372 final ISeq seq = Array.of(model.genes)
373 .map(jaxb.Unmarshaller).toISeq();
374 final Array<Integer> indexes = Array
375 .of(model.indexes.toString().split(","))
376 .map(StringToInteger);
377
378 final Array<Object> genes = new Array<>(seq.length());
379 for (int i = 0; i < seq.length(); ++i) {
380 genes.set(i, new EnumGene(indexes.get(i), seq));
381 }
382
383 return new PermutationChromosome(genes.toISeq(), true);
384 }
385 }
386
387 public static final Adapter Adapter = new Adapter();
388 }
389
390 }
|