| 
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.util.Objects.requireNonNull;
 023 import static org.jenetics.internal.util.Equality.eq;
 024
 025 import java.io.Serializable;
 026 import java.util.Random;
 027
 028 import javax.xml.bind.annotation.XmlAccessType;
 029 import javax.xml.bind.annotation.XmlAccessorType;
 030 import javax.xml.bind.annotation.XmlAttribute;
 031 import javax.xml.bind.annotation.XmlRootElement;
 032 import javax.xml.bind.annotation.XmlType;
 033 import javax.xml.bind.annotation.XmlValue;
 034 import javax.xml.bind.annotation.adapters.XmlAdapter;
 035 import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
 036
 037 import org.jenetics.internal.util.Equality;
 038 import org.jenetics.internal.util.Hash;
 039
 040 import org.jenetics.util.CharSeq;
 041 import org.jenetics.util.ISeq;
 042 import org.jenetics.util.MSeq;
 043 import org.jenetics.util.RandomRegistry;
 044
 045 /**
 046  * Character gene implementation.
 047  *
 048  * <p>This is a <a href="https://docs.oracle.com/javase/8/docs/api/java/lang/doc-files/ValueBased.html">
 049  * value-based</a> class; use of identity-sensitive operations (including
 050  * reference equality ({@code ==}), identity hash code, or synchronization) on
 051  * instances of {@code CharacterGene} may have unpredictable results and should
 052  * be avoided.
 053  *
 054  * @author <a href="mailto:franz.wilhelmstoetter@gmx.at">Franz Wilhelmstötter</a>
 055  * @since 1.0
 056  * @version 2.0 — <em>$Date: 2014-12-28 $</em>
 057  */
 058 @XmlJavaTypeAdapter(CharacterGene.Model.Adapter.class)
 059 public final class CharacterGene
 060     implements
 061         Gene<Character, CharacterGene>,
 062         Comparable<CharacterGene>,
 063         Serializable
 064 {
 065     private static final long serialVersionUID = 2L;
 066
 067     /**
 068      * The default character set used by this gene.
 069      */
 070     public static final CharSeq DEFAULT_CHARACTERS = new CharSeq(
 071         "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" +
 072         " !\"$%&/()=?`{[]}\\+~*#';.:,-_<>|@^'"
 073     );
 074
 075     private final Character _character;
 076     private final CharSeq _validCharacters;
 077     private final Boolean _valid;
 078
 079     private CharacterGene(final CharSeq chars, final int index) {
 080         _character = chars.get(index);
 081         _validCharacters = chars;
 082         _valid = true;
 083     }
 084
 085     /**
 086      * Create a new character gene from the given {@code character} and the
 087      * given set of valid characters.
 088      *
 089      * @param character the char this gene represents
 090      * @param validChars the set of valid characters.
 091      * @throws NullPointerException if one of the arguments is {@code null}.
 092      */
 093     CharacterGene(final Character character, final CharSeq validChars) {
 094         _character = requireNonNull(character);
 095         _validCharacters = requireNonNull(validChars);
 096         _valid = _validCharacters.contains(_character);
 097     }
 098
 099     @Override
 100     public boolean isValid() {
 101         return _valid;
 102     }
 103
 104     @Override
 105     public Character getAllele() {
 106         return _character;
 107     }
 108
 109     /**
 110      * Return the {@code char} value of this character gene.
 111      *
 112      * @return the {@code char} value.
 113      */
 114     public char charValue() {
 115         return _character;
 116     }
 117
 118     /**
 119      * Test, if the given character is valid.
 120      *
 121      * @param character The character to test.
 122      * @return true if the character is valid, false otherwise.
 123      */
 124     public boolean isValidCharacter(final Character character) {
 125         return _validCharacters.contains(character);
 126     }
 127
 128     /**
 129      * Return a (unmodifiable) set of valid characters.
 130      *
 131      * @return the {@link CharSeq} of valid characters.
 132      */
 133     public CharSeq getValidCharacters() {
 134         return _validCharacters;
 135     }
 136
 137     /**
 138      * @see java.lang.Character#compareTo(java.lang.Character)
 139      * @param that The other gene to compare.
 140      * @return the value 0 if the argument Character is equal to this Character;
 141      *         a value less than 0 if this Character is numerically less than
 142      *         the Character argument; and a value greater than 0 if this
 143      *         Character is numerically greater than the Character argument
 144      *         (unsigned comparison). Note that this is strictly a numerical
 145      *         comparison; it is not local-dependent.
 146      */
 147     @Override
 148     public int compareTo(final CharacterGene that) {
 149         return getAllele().compareTo(that.getAllele());
 150     }
 151
 152     @Override
 153     public int hashCode() {
 154         return Hash.of(getClass())
 155             .and(_character)
 156             .and(_validCharacters).value();
 157     }
 158
 159     @Override
 160     public boolean equals(final Object obj) {
 161         return Equality.of(this, obj).test(gene ->
 162             eq(_character, gene._character) &&
 163             eq(_validCharacters, gene._validCharacters)
 164         );
 165     }
 166
 167     @Override
 168     public String toString() {
 169         return _character.toString();
 170     }
 171
 172
 173     /* *************************************************************************
 174      *  Factory methods
 175      * ************************************************************************/
 176
 177     @Override
 178     public CharacterGene newInstance() {
 179         return of(_validCharacters);
 180     }
 181
 182     /**
 183      * Create a new character gene from the given character. If the character
 184      * is not within the {@link #getValidCharacters()}, an invalid gene will be
 185      * created.
 186      *
 187      * @param character the character value of the created gene.
 188      * @return a new character gene.
 189      * @throws NullPointerException if the given {@code character} is
 190      *         {@code null}.
 191      */
 192     public CharacterGene newInstance(final Character character) {
 193         return of(character, _validCharacters);
 194     }
 195
 196
 197     /* *************************************************************************
 198      *  Static object creation methods
 199      * ************************************************************************/
 200
 201     /**
 202      * Create a new CharacterGene with a randomly chosen character from the
 203      * set of valid characters.
 204      *
 205      * @param validCharacters the valid characters for this gene.
 206      * @return a new valid, <em>random</em> gene,
 207      * @throws NullPointerException if the {@code validCharacters} are
 208      *         {@code null}.
 209      */
 210     public static CharacterGene of(final CharSeq validCharacters) {
 211         return new CharacterGene(
 212             validCharacters,
 213             RandomRegistry.getRandom().nextInt(validCharacters.length())
 214         );
 215     }
 216
 217     /**
 218      * Create a new character gene from the given character. If the character
 219      * is not within the {@link #DEFAULT_CHARACTERS}, an invalid gene will be
 220      * created.
 221      *
 222      * @param character the character value of the created gene.
 223      * @return a new character gene.
 224      * @throws NullPointerException if the given {@code character} is
 225      *         {@code null}.
 226      */
 227     public static CharacterGene of(final Character character) {
 228         return new CharacterGene(character, DEFAULT_CHARACTERS);
 229     }
 230
 231     /**
 232      * Create a new random character gene, chosen from the
 233      * {@link #DEFAULT_CHARACTERS}.
 234      *
 235      * @return a new random character gene.
 236      */
 237     public static CharacterGene of() {
 238         return new CharacterGene(
 239             DEFAULT_CHARACTERS,
 240             RandomRegistry.getRandom().nextInt(DEFAULT_CHARACTERS.length())
 241         );
 242     }
 243
 244     /**
 245      * Create a new CharacterGene from the give character.
 246      *
 247      * @param character The allele.
 248      * @param validCharacters the valid characters fo the new gene
 249      * @return a new {@code CharacterGene} with the given parameter
 250      * @throws NullPointerException if one of the arguments is {@code null}.
 251      * @throws IllegalArgumentException if the {@code validCharacters} are empty.
 252      */
 253     public static CharacterGene of(
 254         final char character,
 255         final CharSeq validCharacters
 256     ) {
 257         return new CharacterGene(character, validCharacters);
 258     }
 259
 260     static ISeq<CharacterGene> seq(final CharSeq chars, final int length) {
 261         final Random r = RandomRegistry.getRandom();
 262
 263         return MSeq.<CharacterGene>ofLength(length)
 264             .fill(() -> new CharacterGene(chars, r.nextInt(chars.length())))
 265             .toISeq();
 266     }
 267
 268     /* *************************************************************************
 269      *  JAXB object serialization
 270      * ************************************************************************/
 271
 272     @XmlRootElement(name = "character-gene")
 273     @XmlType(name = "org.jenetics.CharacterGene")
 274     @XmlAccessorType(XmlAccessType.FIELD)
 275     final static class Model {
 276
 277         @XmlAttribute(name = "valid-alleles", required = true)
 278         public String validCharacters;
 279
 280         @XmlValue
 281         public String value;
 282
 283         public final static class Adapter
 284             extends XmlAdapter<Model, CharacterGene>
 285         {
 286             @Override
 287             public Model marshal(final CharacterGene value) {
 288                 final Model m = new Model();
 289                 m.validCharacters = value.getValidCharacters().toString();
 290                 m.value = value.getAllele().toString();
 291                 return m;
 292             }
 293
 294             @Override
 295             public CharacterGene unmarshal(final Model m) {
 296                 return CharacterGene.of(
 297                     m.value.charAt(0),
 298                     new CharSeq(m.validCharacters)
 299                 );
 300             }
 301         }
 302     }
 303
 304 }
 |