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 — <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 }
|