| 
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 org.jenetics.CharacterGene.DEFAULT_CHARACTERS;
 023 import static org.jenetics.internal.util.Equality.eq;
 024
 025 import java.io.IOException;
 026 import java.io.ObjectInputStream;
 027 import java.io.ObjectOutputStream;
 028 import java.io.Serializable;
 029 import java.util.function.Supplier;
 030 import java.util.stream.Collectors;
 031
 032 import javax.xml.bind.annotation.XmlAccessType;
 033 import javax.xml.bind.annotation.XmlAccessorType;
 034 import javax.xml.bind.annotation.XmlAttribute;
 035 import javax.xml.bind.annotation.XmlElement;
 036 import javax.xml.bind.annotation.XmlRootElement;
 037 import javax.xml.bind.annotation.XmlType;
 038 import javax.xml.bind.annotation.adapters.XmlAdapter;
 039 import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
 040
 041 import org.jenetics.internal.util.Equality;
 042 import org.jenetics.internal.util.Hash;
 043 import org.jenetics.internal.util.IntRef;
 044
 045 import org.jenetics.util.CharSeq;
 046 import org.jenetics.util.ISeq;
 047 import org.jenetics.util.MSeq;
 048
 049 /**
 050  * CharacterChromosome which represents character sequences.
 051  *
 052  * @author <a href="mailto:franz.wilhelmstoetter@gmx.at">Franz Wilhelmstötter</a>
 053  * @since 1.0
 054  * @version 3.0 — <em>$Date: 2014-12-28 $</em>
 055  */
 056 @XmlJavaTypeAdapter(CharacterChromosome.Model.Adapter.class)
 057 public class CharacterChromosome
 058     extends
 059         AbstractChromosome<CharacterGene>
 060     implements
 061         CharSequence,
 062         Serializable
 063 {
 064     private static final long serialVersionUID = 2L;
 065
 066     private transient CharSeq _validCharacters;
 067
 068     /**
 069      * Create a new chromosome from the given {@code genes} array. The genes
 070      * array is copied, so changes to the given genes array doesn't effect the
 071      * genes of this chromosome.
 072      *
 073      * @param genes the genes that form the chromosome.
 074      * @throws NullPointerException if the given gene array is {@code null}.
 075      * @throws IllegalArgumentException if the length of the gene array is
 076      *         smaller than one.
 077      */
 078     protected CharacterChromosome(final ISeq<CharacterGene> genes) {
 079         super(genes);
 080         _validCharacters = genes.get(0).getValidCharacters();
 081     }
 082
 083     /**
 084      * Create a new chromosome with the {@code validCharacters} char set as
 085      * valid characters.
 086      *
 087      * @param validCharacters the valid characters for this chromosome.
 088      * @param length the length of the new chromosome.
 089      * @throws NullPointerException if the {@code validCharacters} is
 090      *         {@code null}.
 091      * @throws IllegalArgumentException if the {@code length} is smaller than
 092      *         one.
 093      */
 094     public CharacterChromosome(final CharSeq validCharacters, final int length) {
 095         this(CharacterGene.seq(validCharacters, length));
 096         _valid = true;
 097     }
 098
 099     @Override
 100     public char charAt(final int index) {
 101         return getGene(index).charValue();
 102     }
 103
 104     @Override
 105     public CharacterChromosome subSequence(final int start, final int end) {
 106         return new CharacterChromosome(_genes.subSeq(start, end));
 107     }
 108
 109     /**
 110      * @throws NullPointerException if the given gene array is {@code null}.
 111      */
 112     @Override
 113     public CharacterChromosome newInstance(final ISeq<CharacterGene> genes) {
 114         return new CharacterChromosome(genes);
 115     }
 116
 117     /**
 118      * Create a new, <em>random</em> chromosome.
 119      */
 120     @Override
 121     public CharacterChromosome newInstance() {
 122         return new CharacterChromosome(_validCharacters, length());
 123     }
 124
 125     @Override
 126     public int hashCode() {
 127         return Hash.of(getClass())
 128                 .and(super.hashCode())
 129                 .and(_validCharacters).value();
 130     }
 131
 132     @Override
 133     public boolean equals(final Object obj) {
 134         return Equality.of(this, obj).test(cc ->
 135             super.equals(obj) &&
 136             eq(_validCharacters, cc._validCharacters)
 137         );
 138     }
 139
 140     @Override
 141     public String toString() {
 142         return toSeq().stream()
 143             .map(Object::toString)
 144             .collect(Collectors.joining());
 145     }
 146
 147     /**
 148      * Returns an char array containing all of the elements in this chromosome
 149      * in proper sequence.  If the chromosome fits in the specified array, it is
 150      * returned therein. Otherwise, a new array is allocated with the length of
 151      * this chromosome.
 152      *
 153      * @since 3.0
 154      *
 155      * @param array the array into which the elements of this chromosomes are to
 156      *        be stored, if it is big enough; otherwise, a new array is
 157      *        allocated for this purpose.
 158      * @return an array containing the elements of this chromosome
 159      * @throws NullPointerException if the given {@code array} is {@code null}
 160      */
 161     public char[] toArray(final char[] array) {
 162         final char[] a = array.length >= length() ?
 163             array : new char[length()];
 164
 165         for (int i = length(); --i >= 0;) {
 166             a[i] = charAt(i);
 167         }
 168
 169         return a;
 170     }
 171
 172     /**
 173      * Returns an char array containing all of the elements in this chromosome
 174      * in proper sequence.
 175      *
 176      * @since 3.0
 177      *
 178      * @return an array containing the elements of this chromosome
 179      */
 180     public char[] toArray() {
 181         return toArray(new char[length()]);
 182     }
 183
 184
 185     /**
 186      * Create a new chromosome with the {@link CharacterGene#DEFAULT_CHARACTERS}
 187      * char set as valid characters.
 188      *
 189      * @param length the {@code length} of the new chromosome.
 190      * @return a new {@code CharacterChromosome} with the given parameter
 191      * @throws IllegalArgumentException if the {@code length} is smaller than
 192      *         one.
 193      */
 194     public static CharacterChromosome of(final int length) {
 195         return new CharacterChromosome(
 196             CharacterGene.seq(DEFAULT_CHARACTERS, length)
 197         );
 198     }
 199
 200     /**
 201      * Create a new chromosome from the given genes (given as string).
 202      *
 203      * @param alleles the character genes.
 204      * @param validChars the valid characters.
 205      * @return a new {@code CharacterChromosome} with the given parameter
 206      * @throws IllegalArgumentException if the genes string is empty.
 207      */
 208     public static CharacterChromosome of(
 209         final String alleles,
 210         final CharSeq validChars
 211     ) {
 212         final IntRef index = new IntRef();
 213         final Supplier<CharacterGene> geneFactory = () -> CharacterGene.of(
 214             alleles.charAt(index.value++), validChars
 215         );
 216
 217         final ISeq<CharacterGene> genes =
 218             MSeq.<CharacterGene>ofLength(alleles.length())
 219                 .fill(geneFactory)
 220                 .toISeq();
 221
 222         return new CharacterChromosome(genes);
 223     }
 224
 225     /**
 226      * Create a new chromosome from the given genes (given as string).
 227      *
 228      * @param alleles the character genes.
 229      * @return a new {@code CharacterChromosome} with the given parameter
 230      * @throws IllegalArgumentException if the genes string is empty.
 231      */
 232     public static CharacterChromosome of(final String alleles) {
 233         return of(alleles, DEFAULT_CHARACTERS);
 234     }
 235
 236
 237     /* *************************************************************************
 238      *  Java object serialization
 239      * ************************************************************************/
 240
 241     private void writeObject(final ObjectOutputStream out)
 242         throws IOException
 243     {
 244         out.defaultWriteObject();
 245
 246         out.writeInt(length());
 247         out.writeObject(_validCharacters);
 248
 249         for (CharacterGene gene : _genes) {
 250             out.writeChar(gene.getAllele().charValue());
 251         }
 252     }
 253
 254     private void readObject(final ObjectInputStream in)
 255         throws IOException, ClassNotFoundException
 256     {
 257         in.defaultReadObject();
 258
 259         final int length = in.readInt();
 260         _validCharacters = (CharSeq)in.readObject();
 261
 262         final MSeq<CharacterGene> genes = MSeq.ofLength(length);
 263         for (int i = 0; i < length; ++i) {
 264             final CharacterGene gene = CharacterGene.of(
 265                 in.readChar(),
 266                 _validCharacters
 267             );
 268             genes.set(i, gene);
 269         }
 270
 271         _genes = genes.toISeq();
 272     }
 273
 274     /* *************************************************************************
 275      *  JAXB object serialization
 276      * ************************************************************************/
 277
 278     @XmlRootElement(name = "character-chromosome")
 279     @XmlType(name = "org.jenetics.CharacterChromosome")
 280     @XmlAccessorType(XmlAccessType.FIELD)
 281     final static class Model {
 282
 283         @XmlAttribute(name = "length", required = true)
 284         public int length;
 285
 286         @XmlElement(name = "valid-alleles", required = true, nillable = false)
 287         public String validCharacters;
 288
 289         @XmlElement(name = "alleles", required = true, nillable = false)
 290         public String genes;
 291
 292         public final static class Adapter
 293             extends XmlAdapter<Model, CharacterChromosome>
 294         {
 295             @Override
 296             public Model marshal(final CharacterChromosome value) {
 297                 final Model m = new Model();
 298                 m.length = value.length();
 299                 m.validCharacters = value._validCharacters.toString();
 300                 m.genes = value.toString();
 301                 return m;
 302             }
 303
 304             @Override
 305             public CharacterChromosome unmarshal(final Model m) {
 306                 return CharacterChromosome.of(
 307                     m.genes,
 308                     new CharSeq(m.validCharacters)
 309                 );
 310             }
 311         }
 312     }
 313 }
 |