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