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