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