CharacterGene.java
001 /*
002  * Java Genetic Algorithm Library (jenetics-1.6.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.object.eq;
024 
025 import java.util.Random;
026 
027 import javax.xml.bind.annotation.XmlAccessType;
028 import javax.xml.bind.annotation.XmlAccessorType;
029 import javax.xml.bind.annotation.XmlAttribute;
030 import javax.xml.bind.annotation.XmlRootElement;
031 import javax.xml.bind.annotation.XmlType;
032 import javax.xml.bind.annotation.XmlValue;
033 import javax.xml.bind.annotation.adapters.XmlAdapter;
034 import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
035 
036 import javolution.lang.Realtime;
037 import javolution.text.Text;
038 import javolution.xml.XMLFormat;
039 import javolution.xml.XMLSerializable;
040 import javolution.xml.stream.XMLStreamException;
041 
042 import org.jenetics.internal.util.HashBuilder;
043 import org.jenetics.internal.util.model.ModelType;
044 import org.jenetics.internal.util.model.ValueType;
045 
046 import org.jenetics.util.Array;
047 import org.jenetics.util.CharSeq;
048 import org.jenetics.util.Factory;
049 import org.jenetics.util.Function;
050 import org.jenetics.util.ISeq;
051 import org.jenetics.util.RandomRegistry;
052 
053 /**
054  * Character gene implementation.
055  *
056  @author <a href="mailto:franz.wilhelmstoetter@gmx.at">Franz Wilhelmstötter</a>
057  @since 1.0
058  @version 1.6 &mdash; <em>$Date: 2014-03-03 $</em>
059  */
060 @XmlJavaTypeAdapter(CharacterGene.Model.Adapter.class)
061 public final class CharacterGene
062     implements
063         Gene<Character, CharacterGene>,
064         Comparable<CharacterGene>,
065         Realtime,
066         XMLSerializable
067 {
068     private static final long serialVersionUID = 1L;
069 
070     /**
071      * The default character set used by this gene.
072      */
073     public static final CharSeq DEFAULT_CHARACTERS = new CharSeq(
074         CharSeq.expand("0-9a-zA-Z"+
075         " !\"$%&/()=?`{[]}\\+~*#';.:,-_<>|@^'"
076     );
077 
078     private final Character _character;
079     private final CharSeq _validCharacters;
080     private final Boolean _valid;
081 
082     private CharacterGene(final CharSeq chars, final int index) {
083         _character = chars.get(index);
084         _validCharacters = chars;
085         _valid = true;
086     }
087 
088     /**
089      * Create a new character gene from the given {@code character} and the
090      * given set of valid characters.
091      *
092      @param character the char this gene represents
093      @param validChars the set of valid characters.
094      @throws NullPointerException if one of the arguments is {@code null}.
095      */
096     public CharacterGene(final Character character, final CharSeq validChars) {
097         _character = requireNonNull(character);
098         _validCharacters = requireNonNull(validChars);
099         _valid = _validCharacters.contains(_character);
100     }
101 
102     @Override
103     public boolean isValid() {
104         return _valid;
105     }
106 
107     @Override
108     public Character getAllele() {
109         return _character;
110     }
111 
112     /**
113      * Return the {@code char} value of this character gene.
114      *
115      @return the {@code char} value.
116      */
117     public char charValue() {
118         return _character;
119     }
120 
121     /**
122      * Test, if the given character is valid.
123      *
124      @param character The character to test.
125      @return true if the character is valid, false otherwise.
126      */
127     public boolean isValidCharacter(final Character character) {
128         return _validCharacters.contains(character);
129     }
130 
131     /**
132      * Retunr a (unmodifiable) set of valid characters.
133      *
134      @return the {@link CharSeq} of valid characters.
135      */
136     public CharSeq getValidCharacters() {
137         return _validCharacters;
138     }
139 
140     @Deprecated
141     @Override
142     public CharacterGene copy() {
143         return of(_character, _validCharacters);
144     }
145 
146     /**
147      @see java.lang.Character#compareTo(java.lang.Character)
148      @param that The other gene to compare.
149      @return the value 0 if the argument Character is equal to this Character;
150      *         a value less than 0 if this Character is numerically less than
151      *         the Character argument; and a value greater than 0 if this
152      *         Character is numerically greater than the Character argument
153      *         (unsigned comparison). Note that this is strictly a numerical
154      *         comparison; it is not local-dependent.
155      */
156     @Override
157     public int compareTo(final CharacterGene that) {
158         return getAllele().compareTo(that.getAllele());
159     }
160 
161     /**
162      * Return the {@link Factory} view of this gene.
163      *
164      @return the {@link Factory} view of this gene.
165      *
166      @deprecated No longer needed after adding new factory methods to the
167      *             {@link Array} class.
168      */
169     @Deprecated
170     Factory<CharacterGene> asFactory() {
171         return this;
172     }
173 
174     @Override
175     public int hashCode() {
176         return HashBuilder.of(getClass()).and(_character).and(_validCharacters).value();
177     }
178 
179     @Override
180     public boolean equals(final Object obj) {
181         if (obj == this) {
182             return true;
183         }
184         if (!(obj instanceof CharacterGene)) {
185             return false;
186         }
187         CharacterGene gene = (CharacterGene)obj;
188         return eq(_character, gene._character&&
189                 eq(_validCharacters, gene._validCharacters);
190     }
191 
192     @Override
193     public String toString() {
194         return _character.toString();
195     }
196 
197     @Override
198     public Text toText() {
199         return Text.valueOf(_character);
200     }
201 
202 
203     /* *************************************************************************
204      *  Property access methods.
205      * ************************************************************************/
206 
207     /**
208      * Converter for accessing the allele from a given gene.
209      */
210     public static final Function<CharacterGene, Character> Allele =
211         new Function<CharacterGene, Character>() {
212             @Override public Character apply(final CharacterGene value) {
213                 return value._character;
214             }
215         };
216 
217     /**
218      * Converter for accessing the valid characters from a given gene.
219      */
220     public static final Function<CharacterGene, CharSeq> ValidCharacters =
221         new Function<CharacterGene, CharSeq>() {
222             @Override public CharSeq apply(final CharacterGene value) {
223                 return value._validCharacters;
224             }
225         };
226 
227 
228     /* *************************************************************************
229      *  Factory methods
230      * ************************************************************************/
231 
232     @Override
233     public CharacterGene newInstance() {
234         return of(_validCharacters);
235     }
236 
237     /**
238      * Create a new character gene from the given character. If the character
239      * is not within the {@link #getValidCharacters()}, an invalid gene will be
240      * created.
241      *
242      @param character the character value of the created gene.
243      @return a new character gene.
244      @throws NullPointerException if the given {@code character} is
245      *         {@code null}.
246      */
247     public CharacterGene newInstance(final Character character) {
248         return of(character, _validCharacters);
249     }
250 
251 
252     /* *************************************************************************
253      *  Static object creation methods
254      * ************************************************************************/
255 
256     /**
257      * Create a new CharacterGene with a randomly chosen character from the
258      * set of valid characters.
259      *
260      @param validCharacters the valid characters for this gene.
261      @return a new valid, <em>random</em> gene,
262      @throws NullPointerException if the {@code validCharacters} are
263      *         {@code null}.
264      */
265     public static CharacterGene of(final CharSeq validCharacters) {
266         return new CharacterGene(
267             validCharacters,
268             RandomRegistry.getRandom().nextInt(validCharacters.length())
269         );
270     }
271 
272     /**
273      @deprecated Use {@link #of(org.jenetics.util.CharSeq)} instead.
274      */
275     @Deprecated
276     public static CharacterGene valueOf(final CharSeq validCharacters) {
277         return of(validCharacters);
278     }
279 
280     /**
281      * Create a new character gene from the given character. If the character
282      * is not within the {@link #DEFAULT_CHARACTERS}, an invalid gene will be
283      * created.
284      *
285      @param character the character value of the created gene.
286      @return a new character gene.
287      @throws NullPointerException if the given {@code character} is
288      *         {@code null}.
289      */
290     public static CharacterGene of(final Character character) {
291         return new CharacterGene(character, DEFAULT_CHARACTERS);
292     }
293 
294     /**
295      @deprecated Use {@link #of(Character)} instead.
296      */
297     @Deprecated
298     public static CharacterGene valueOf(final Character character) {
299         return of(character);
300     }
301 
302     /**
303      * Create a new random character gene, chosen from the
304      {@link #DEFAULT_CHARACTERS}.
305      *
306      @return a new random character gene.
307      */
308     public static CharacterGene of() {
309         return new CharacterGene(
310             DEFAULT_CHARACTERS,
311             RandomRegistry.getRandom().nextInt(DEFAULT_CHARACTERS.length())
312         );
313     }
314 
315     /**
316      @deprecated Use {@link #of()} instead.
317      */
318     @Deprecated
319     public static CharacterGene valueOf() {
320         return of();
321     }
322 
323     /**
324      * Create a new CharacterGene from the give character.
325      *
326      @param character The allele.
327      @throws NullPointerException if one of the arguments is {@code null}.
328      @throws IllegalArgumentException if the {@code validCharacters} are empty.
329      */
330     public static CharacterGene of(
331         final char character,
332         final CharSeq validCharacters
333     ) {
334         return new CharacterGene(character, validCharacters);
335     }
336 
337     /**
338      @deprecated Use {@link #of(char, org.jenetics.util.CharSeq)} instead.
339      */
340     @Deprecated
341     public static CharacterGene valueOf(
342         final Character character,
343         final CharSeq validCharacters
344     ) {
345         return of(character, validCharacters);
346     }
347 
348     static ISeq<CharacterGene> seq(final CharSeq characters, final int length) {
349         final Random random = RandomRegistry.getRandom();
350         final int charsLength = characters.length();
351 
352         final Array<CharacterGene> genes = new Array<>(length);
353         for (int i = 0; i < length; ++i) {
354             final CharacterGene gene = new CharacterGene(
355                 characters, random.nextInt(charsLength)
356             );
357             genes.set(i, gene);
358         }
359         return genes.toISeq();
360     }
361 
362     /* *************************************************************************
363      *  XML object serialization
364      * ************************************************************************/
365 
366     static final XMLFormat<CharacterGene>
367     XML = new XMLFormat<CharacterGene>(CharacterGene.class)
368     {
369         private static final String VALID_CHARS = "valid-characters";
370 
371         @Override
372         public CharacterGene newInstance(
373             final Class<CharacterGene> cls, final InputElement xml
374         )
375             throws XMLStreamException
376         {
377             final String validCharacters = xml.getAttribute(
378                 VALID_CHARS,
379                 DEFAULT_CHARACTERS.toString()
380             );
381             final String character = xml.getText().toString();
382 
383             return CharacterGene.of(
384                 character.charAt(0),
385                 new CharSeq(validCharacters)
386             );
387         }
388         @Override
389         public void write(final CharacterGene gene, final OutputElement xml)
390             throws XMLStreamException
391         {
392             xml.setAttribute(VALID_CHARS, gene.getValidCharacters().toString());
393             xml.addText(gene._character.toString());
394         }
395         @Override
396         public void read(final InputElement element, final CharacterGene gene) {
397         }
398     };
399 
400 
401     /* *************************************************************************
402      *  JAXB object serialization
403      * ************************************************************************/
404 
405     @XmlRootElement(name = "org.jenetics.CharacterGene")
406     @XmlType(name = "org.jenetics.CharacterGene")
407     @XmlAccessorType(XmlAccessType.FIELD)
408     final static class Model {
409 
410         @XmlAttribute(name = "valid-characters")
411         public String validCharacters;
412 
413         @XmlValue
414         public String value;
415 
416         @ValueType(CharacterGene.class)
417         @ModelType(Model.class)
418         public final static class Adapter
419             extends XmlAdapter<Model, CharacterGene>
420         {
421             @Override
422             public Model marshal(final CharacterGene value) {
423                 final Model m = new Model();
424                 m.validCharacters = value.getValidCharacters().toString();
425                 m.value = value.getAllele().toString();
426                 return m;
427             }
428 
429             @Override
430             public CharacterGene unmarshal(final Model m) {
431                 return CharacterGene.of(
432                     m.value.charAt(0),
433                     new CharSeq(m.validCharacters)
434                 );
435             }
436         }
437     }
438 
439 }