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 — <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 }
|