PermutationChromosome.java
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 &mdash; <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()/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 >= && 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 }