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