PermutationChromosome.java
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.bit.getAndSet;
024 import static org.jenetics.util.MSeq.toMSeq;
025 
026 import java.io.IOException;
027 import java.io.ObjectInputStream;
028 import java.io.ObjectOutputStream;
029 import java.io.Serializable;
030 import java.util.List;
031 import java.util.function.Function;
032 import java.util.stream.Collectors;
033 import java.util.stream.IntStream;
034 
035 import javax.xml.bind.annotation.XmlAccessType;
036 import javax.xml.bind.annotation.XmlAccessorType;
037 import javax.xml.bind.annotation.XmlAttribute;
038 import javax.xml.bind.annotation.XmlElement;
039 import javax.xml.bind.annotation.XmlElementWrapper;
040 import javax.xml.bind.annotation.XmlList;
041 import javax.xml.bind.annotation.XmlRootElement;
042 import javax.xml.bind.annotation.XmlType;
043 import javax.xml.bind.annotation.adapters.XmlAdapter;
044 import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
045 
046 import org.jenetics.internal.util.Equality;
047 import org.jenetics.internal.util.Hash;
048 import org.jenetics.internal.util.IntRef;
049 import org.jenetics.internal.util.bit;
050 import org.jenetics.internal.util.jaxb;
051 import org.jenetics.internal.util.reflect;
052 
053 import org.jenetics.util.ISeq;
054 import org.jenetics.util.MSeq;
055 import org.jenetics.util.RandomRegistry;
056 import org.jenetics.util.Seq;
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 2.0 &mdash; <em>$Date: 2014-12-28 $</em>
065  */
066 @XmlJavaTypeAdapter(PermutationChromosome.Model.Adapter.class)
067 public final class PermutationChromosome<T>
068     extends AbstractChromosome<EnumGene<T>>
069     implements Serializable
070 {
071     private static final long serialVersionUID = 2L;
072 
073     private ISeq<T> _validAlleles;
074 
075     public PermutationChromosome(final ISeq<EnumGene<T>> genes) {
076         super(genes);
077         _validAlleles = genes.get(0).getValidAlleles();
078     }
079 
080     public ISeq<T> getValidAlleles() {
081         return _validAlleles;
082     }
083 
084     /**
085      * Check if this chromosome represents still a valid permutation.
086      */
087     @Override
088     public boolean isValid() {
089         if (_valid == null) {
090             final byte[] check = bit.newArray(length());
091             _valid = _genes.forAll(g -> !getAndSet(check, g.getAlleleIndex()));
092         }
093 
094         return _valid;
095     }
096 
097     /**
098      * Create a new, <em>random</em> chromosome.
099      */
100     @Override
101     public PermutationChromosome<T> newInstance() {
102         return of(_validAlleles);
103     }
104 
105     @Override
106     public PermutationChromosome<T> newInstance(final ISeq<EnumGene<T>> genes) {
107         return new PermutationChromosome<>(genes);
108     }
109 
110     @Override
111     public int hashCode() {
112         return Hash.of(getClass())
113                 .and(super.hashCode())
114                 .value();
115     }
116 
117     @Override
118     public boolean equals(final Object obj) {
119         return Equality.of(this, obj).test(super::equals);
120     }
121 
122     @Override
123     public String toString() {
124         return _genes.asList().stream()
125             .map(g -> g.getAllele().toString())
126             .collect(Collectors.joining("|"));
127     }
128 
129     /**
130      * Create a new, random chromosome with the given valid alleles.
131      *
132      @param <T> the gene type of the chromosome
133      @param alleles the valid alleles used for this permutation arrays.
134      @return a new chromosome with the given alleles
135      */
136     public static <T> PermutationChromosome<T> of(final ISeq<? extends T> alleles) {
137         final ISeq<EnumGene<T>> genes = IntStream.range(0, alleles.length())
138             .mapToObj(index -> new EnumGene<>(index, alleles))
139             .collect(toMSeq())
140             .shuffle(RandomRegistry.getRandom())
141             .toISeq();
142 
143         final PermutationChromosome<T> chromosome =
144             new PermutationChromosome<>(genes);
145         chromosome._validAlleles = reflect.cast(alleles);
146         chromosome._valid = true;
147 
148         return chromosome;
149     }
150 
151     /**
152      * Create a new, random chromosome with the given valid alleles.
153      *
154      @since 2.0
155      @param <T> the gene type of the chromosome
156      @param alleles the valid alleles used for this permutation arrays.
157      @return a new chromosome with the given alleles
158      */
159     @SafeVarargs
160     public static <T> PermutationChromosome<T> of(final T... alleles) {
161         return of(ISeq.of(alleles));
162     }
163 
164     /**
165      * Create a integer permutation chromosome with the given length.
166      *
167      @param length the chromosome length.
168      @return a integer permutation chromosome with the given length.
169      */
170     public static PermutationChromosome<Integer> ofInteger(final int length) {
171         return ofInteger(0, length);
172     }
173 
174     /**
175      * Create a integer permutation chromosome with the given length.
176      *
177      @since 2.0
178      @param start the start of the integer range (inclusively) of the returned
179      *        chromosome.
180      @param end the end of the integer range (exclusively) of the returned
181      *        chromosome.
182      @return a integer permutation chromosome with the given integer range
183      *         values.
184      @throws java.lang.IllegalArgumentException if {@code end <= start}
185      */
186     public static PermutationChromosome<Integer>
187     ofInteger(final int start, final int end) {
188         if (end <= start) {
189             throw new IllegalArgumentException(format(
190                 "end <= start: %d <= %d", end, start
191             ));
192         }
193 
194         final IntRef index = new IntRef(start);
195         final ISeq<Integer> alleles = MSeq.<Integer>ofLength(end - start)
196             .fill(() -> index.value++)
197             .toISeq();
198 
199         return of(alleles);
200     }
201 
202     /* *************************************************************************
203      *  Java object serialization
204      * ************************************************************************/
205 
206     private void writeObject(final ObjectOutputStream out)
207         throws IOException
208     {
209         out.defaultWriteObject();
210 
211         out.writeObject(_validAlleles);
212         for (EnumGene<?> gene : _genes) {
213             out.writeInt(gene.getAlleleIndex());
214         }
215     }
216 
217     @SuppressWarnings("unchecked")
218     private void readObject(final ObjectInputStream in)
219         throws IOException, ClassNotFoundException
220     {
221         in.defaultReadObject();
222 
223         _validAlleles = (ISeq<T>)in.readObject();
224 
225         final MSeq<EnumGene<T>> genes = MSeq.ofLength(_validAlleles.length());
226         for (int i = 0; i < _validAlleles.length(); ++i) {
227             genes.set(i, new EnumGene<>(in.readInt(), _validAlleles));
228         }
229 
230         _genes = genes.toISeq();
231     }
232 
233     /* *************************************************************************
234      *  JAXB object serialization
235      * ************************************************************************/
236 
237     @XmlRootElement(name = "permutation-chromosome")
238     @XmlType(name = "org.jenetics.PermutationChromosome")
239     @XmlAccessorType(XmlAccessType.FIELD)
240     @SuppressWarnings({"unchecked""rawtypes"})
241     static final class Model {
242 
243         @XmlAttribute
244         public int length;
245 
246         @XmlElementWrapper(name = "valid-alleles")
247         @XmlElement(name = "allele")
248         public List<Object> alleles;
249 
250         @XmlList
251         @XmlElement(name = "order")
252         public List<Integer> order;
253 
254         public static final class Adapter
255             extends XmlAdapter<Model, PermutationChromosome> {
256             @Override
257             public Model marshal(final PermutationChromosome pc)
258                 throws Exception {
259                 final Model model = new Model();
260                 model.length = pc.length();
261                 model.alleles = pc.getValidAlleles()
262                     .map(jaxb.Marshaller(pc.getValidAlleles().get(0)))
263                     .asList();
264                 model.order = ((Seq<EnumGene<?>>)pc.toSeq())
265                     .map(EnumGene::getAlleleIndex)
266                     .asList();
267 
268                 return model;
269             }
270 
271             @Override
272             public PermutationChromosome unmarshal(final Model model)
273                 throws Exception {
274                 final ISeq alleles = ISeq.of(model.alleles)
275                     .map(jaxb.Unmarshaller(model.alleles.get(0)));
276 
277                 return new PermutationChromosome(
278                     ISeq.of(model.order).map(Gene(alleles))
279                 );
280             }
281         }
282 
283         private static Function<Integer, EnumGene<Object>>
284         Gene(final ISeq<Object> alleles) {
285             return value -> new EnumGene<>(value, alleles);
286         }
287     }
288 }