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