CharacterGene.java
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 &mdash; <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 }