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.lang.String.format;
023 import static org.jenetics.util.object.eq;
024 import static org.jenetics.util.object.hashCodeOf;
025
026 import java.io.IOException;
027 import java.io.ObjectInputStream;
028 import java.io.ObjectOutputStream;
029
030 import javolution.text.CharArray;
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.ISeq;
040
041 /**
042 * CharacterChromosome which represents character sequences.
043 *
044 * @author <a href="mailto:franz.wilhelmstoetter@gmx.at">Franz Wilhelmstötter</a>
045 * @since 1.0
046 * @version 1.0 — <em>$Date: 2013-12-05 $</em>
047 */
048 public class CharacterChromosome
049 extends
050 AbstractChromosome<CharacterGene>
051 implements
052 CharSequence,
053 XMLSerializable
054 {
055 private static final long serialVersionUID = 1L;
056
057 private transient CharSeq _validCharacters;
058
059 /**
060 * Create a new chromosome with the {@link CharacterGene#DEFAULT_CHARACTERS}
061 * char set as valid characters.
062 *
063 * @param length the {@code length} of the new chromosome.
064 * @throws IllegalArgumentException if the {@code length} is smaller than
065 * one.
066 */
067 public CharacterChromosome(final int length) {
068 super(
069 new Array<CharacterGene>(length).fill(
070 CharacterGene.valueOf(CharacterGene.DEFAULT_CHARACTERS)
071 ).toISeq()
072 );
073 _validCharacters = CharacterGene.DEFAULT_CHARACTERS;
074 _valid = true;
075 }
076
077 /**
078 * Create a new chromosome with the {@code validCharacters} char set as
079 * valid characters.
080 *
081 * @param validCharacters the valid characters for this chromosome.
082 * @param length the length of the new chromosome.
083 * @throws NullPointerException if the {@code validCharacters} is
084 * {@code null}.
085 * @throws IllegalArgumentException if the {@code length} is smaller than
086 * one.
087 */
088 public CharacterChromosome(final CharSeq validCharacters, final int length) {
089 super(
090 new Array<CharacterGene>(length).fill(
091 CharacterGene.valueOf(validCharacters)
092 ).toISeq()
093 );
094 _validCharacters = validCharacters;
095 _valid = true;
096 }
097
098 /**
099 * Create a new chromosome from the given {@code genes} array. The genes
100 * array is copied, so changes to the given genes array doesn't effect the
101 * genes of this chromosome.
102 *
103 * @param genes the genes that form the chromosome.
104 * @throws NullPointerException if the given gene array is {@code null}.
105 * @throws IllegalArgumentException if the length of the gene array is
106 * smaller than one.
107 */
108 public CharacterChromosome(final ISeq<CharacterGene> genes) {
109 super(genes);
110 _validCharacters = genes.get(0).getValidCharacters();
111 }
112
113 /**
114 * Create a new chromosome from the given genes (given as string).
115 *
116 * @param genes the character genes.
117 * @param validCharacters the valid characters.
118 * @throws IllegalArgumentException if not all genes are in the set of valid
119 * characters or the genes string is empty.
120 */
121 public CharacterChromosome(final String genes, final CharSeq validCharacters) {
122 super(
123 new Array<CharacterGene>(genes.length()).fill(new Factory<CharacterGene>() {
124 private int _index = 0;
125 @Override
126 public CharacterGene newInstance() {
127 final char c = genes.charAt(_index++);
128 if (!validCharacters.contains(c)) {
129 throw new IllegalArgumentException(format(
130 "Character '%s' not in valid characters %s",
131 c, validCharacters
132 ));
133 }
134 return CharacterGene.valueOf(c, validCharacters);
135 }
136 }).toISeq()
137 );
138
139 _validCharacters = validCharacters;
140 }
141
142 /**
143 * Create a new chromosome from the given genes (given as string).
144 *
145 * @param genes the character genes.
146 * @throws IllegalArgumentException if not all genes are in the set of valid
147 * characters or the genes is an empty string.
148 */
149 public CharacterChromosome(final String genes) {
150 this(genes, CharacterGene.DEFAULT_CHARACTERS);
151 }
152
153 /**
154 * Return a more specific view of this chromosome factory.
155 *
156 * @return a more specific view of this chromosome factory.
157 *
158 * @deprecated No longer needed after adding new factory methods to the
159 * {@link Array} class.
160 */
161 @Deprecated
162 @SuppressWarnings("unchecked")
163 public Factory<CharacterChromosome> asFactory() {
164 return (Factory<CharacterChromosome>)(Object)this;
165 }
166
167 @Override
168 public char charAt(final int index) {
169 return getGene(index).getAllele();
170 }
171
172 @Override
173 public CharacterChromosome subSequence(final int start, final int end) {
174 return new CharacterChromosome(_genes.subSeq(start, end));
175 }
176
177 /**
178 * @throws NullPointerException if the given gene array is {@code null}.
179 */
180 @Override
181 public CharacterChromosome newInstance(final ISeq<CharacterGene> genes) {
182 return new CharacterChromosome(genes);
183 }
184
185 /**
186 * Create a new, <em>random</em> chromosome.
187 */
188 @Override
189 public CharacterChromosome newInstance() {
190 return new CharacterChromosome(_validCharacters, length());
191 }
192
193 @Override
194 public int hashCode() {
195 return hashCodeOf(getClass()).
196 and(super.hashCode()).
197 and(_validCharacters).value();
198 }
199
200 @Override
201 public boolean equals(final Object obj) {
202 if (obj == this) {
203 return true;
204 }
205 if (obj == null || getClass() != obj.getClass()) {
206 return false;
207 }
208
209 final CharacterChromosome cc = (CharacterChromosome)obj;
210 return super.equals(obj) && eq(_validCharacters, cc._validCharacters);
211 }
212
213 @Override
214 public String toString() {
215 final StringBuilder out = new StringBuilder();
216 for (CharacterGene gene : this) {
217 out.append(gene);
218 }
219 return out.toString();
220 }
221
222
223 /* *************************************************************************
224 * Property access methods
225 * ************************************************************************/
226
227 /**
228 * Return a {@link Function} which returns the gene array from this
229 * {@link Chromosome}.
230 */
231 public static final Function<Chromosome<CharacterGene>, ISeq<CharacterGene>>
232 Genes = AbstractChromosome.genes();
233
234 /**
235 * Return a {@link Function} which returns the first {@link Gene} from this
236 * {@link Chromosome}.
237 */
238 public static final Function<Chromosome<CharacterGene>, CharacterGene>
239 Gene = AbstractChromosome.gene();
240
241 /**
242 * Return a {@link Function} which returns the {@link Gene} with the given
243 * {@code index} from this {@link Chromosome}.
244 */
245 public static final Function<Chromosome<CharacterGene>, CharacterGene>
246 Gene(final int index)
247 {
248 return AbstractChromosome.gene(index);
249 }
250
251 /* *************************************************************************
252 * XML object serialization
253 * ************************************************************************/
254
255 static final XMLFormat<CharacterChromosome>
256 XML = new XMLFormat<CharacterChromosome>(CharacterChromosome.class)
257 {
258 private static final String LENGTH = "length";
259 private static final String VALID_CHARS = "valid-characters";
260
261 @Override
262 public CharacterChromosome newInstance(
263 final Class<CharacterChromosome> cls, final InputElement xml
264 )
265 throws XMLStreamException
266 {
267 final int length = xml.getAttribute(LENGTH, 0);
268 final CharSeq validCharacters = new CharSeq(xml.getAttribute(
269 VALID_CHARS, CharacterGene.DEFAULT_CHARACTERS.toString()
270 ));
271
272 final Array<CharacterGene> array = new Array<>(length);
273 final CharArray values = xml.getText();
274 for (int i = 0; i < length; ++i) {
275 array.set(i, CharacterGene.valueOf(values.charAt(i), validCharacters));
276 }
277 return new CharacterChromosome(array.toISeq());
278 }
279 @Override
280 public void write(final CharacterChromosome chromosome, final OutputElement xml)
281 throws XMLStreamException
282 {
283 xml.setAttribute(LENGTH, chromosome.length());
284 xml.setAttribute(VALID_CHARS, chromosome._validCharacters.toString());
285 final StringBuilder out = new StringBuilder(chromosome.length());
286 for (CharacterGene gene : chromosome) {
287 out.append(gene.getAllele().charValue());
288 }
289 xml.addText(out.toString());
290 }
291 @Override
292 public void read(final InputElement element, final CharacterChromosome chromosome) {
293 }
294
295 };
296
297 /* *************************************************************************
298 * Java object serialization
299 * ************************************************************************/
300
301 private void writeObject(final ObjectOutputStream out)
302 throws IOException
303 {
304 out.defaultWriteObject();
305
306 out.writeInt(length());
307 out.writeObject(_validCharacters);
308
309 for (CharacterGene gene : _genes) {
310 out.writeChar(gene.getAllele().charValue());
311 }
312 }
313
314 private void readObject(final ObjectInputStream in)
315 throws IOException, ClassNotFoundException
316 {
317 in.defaultReadObject();
318
319 final int length = in.readInt();
320 _validCharacters = (CharSeq)in.readObject();
321
322 final Array<CharacterGene> genes = new Array<>(length);
323 for (int i = 0; i < length; ++i) {
324 final CharacterGene gene = CharacterGene.valueOf(
325 in.readChar(),
326 _validCharacters
327 );
328 genes.set(i, gene);
329 }
330
331 _genes = genes.toISeq();
332 }
333
334 }
335
336
|