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