001 /*
002 * Java Genetic Algorithm Library (jenetics-5.1.0).
003 * Copyright (c) 2007-2019 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@gmail.com)
019 */
020 package io.jenetics;
021
022 import static io.jenetics.CharacterGene.DEFAULT_CHARACTERS;
023 import static io.jenetics.internal.util.Hashes.hash;
024 import static io.jenetics.internal.util.SerialIO.readInt;
025 import static io.jenetics.internal.util.SerialIO.readString;
026 import static io.jenetics.internal.util.SerialIO.writeInt;
027 import static io.jenetics.internal.util.SerialIO.writeString;
028
029 import java.io.DataInput;
030 import java.io.DataOutput;
031 import java.io.IOException;
032 import java.io.InvalidObjectException;
033 import java.io.ObjectInputStream;
034 import java.io.Serializable;
035 import java.util.Objects;
036 import java.util.function.Supplier;
037
038 import io.jenetics.internal.util.IntRef;
039 import io.jenetics.util.CharSeq;
040 import io.jenetics.util.ISeq;
041 import io.jenetics.util.IntRange;
042 import io.jenetics.util.MSeq;
043
044 /**
045 * CharacterChromosome which represents character sequences.
046 *
047 * @see CharacterGene
048 *
049 * @implNote
050 * This class is immutable and thread-safe.
051 *
052 * @author <a href="mailto:franz.wilhelmstoetter@gmail.com">Franz Wilhelmstötter</a>
053 * @since 1.0
054 * @version 5.0
055 */
056 public class CharacterChromosome
057 extends
058 VariableChromosome<CharacterGene>
059 implements
060 CharSequence,
061 Serializable
062 {
063 private static final long serialVersionUID = 3L;
064
065 private transient final CharSeq _validCharacters;
066
067 /**
068 * Create a new chromosome from the given {@code genes} array. The genes
069 * array is copied, so changes to the given genes array doesn't effect the
070 * genes of this chromosome.
071 *
072 * @since 4.0
073 *
074 * @param genes the genes that form the chromosome.
075 * @param lengthRange the allowed length range of the chromosome.
076 * @throws NullPointerException if the given gene array is {@code null}.
077 * @throws IllegalArgumentException if the length of the gene array is
078 * smaller than one.
079 */
080 protected CharacterChromosome(
081 final ISeq<CharacterGene> genes,
082 final IntRange lengthRange
083 ) {
084 super(genes, lengthRange);
085 _validCharacters = genes.get(0).getValidCharacters();
086 }
087
088 @Override
089 public char charAt(final int index) {
090 return getGene(index).charValue();
091 }
092
093 @Override
094 public CharacterChromosome subSequence(final int start, final int end) {
095 return new CharacterChromosome(_genes.subSeq(start, end), lengthRange());
096 }
097
098 /**
099 * @throws NullPointerException if the given gene array is {@code null}.
100 */
101 @Override
102 public CharacterChromosome newInstance(final ISeq<CharacterGene> genes) {
103 return new CharacterChromosome(genes, lengthRange());
104 }
105
106 /**
107 * Create a new, <em>random</em> chromosome.
108 */
109 @Override
110 public CharacterChromosome newInstance() {
111 return of(_validCharacters, lengthRange());
112 }
113
114 @Override
115 public int hashCode() {
116 return hash(super.hashCode(), hash(_validCharacters));
117 }
118
119 @Override
120 public boolean equals(final Object obj) {
121 return obj == this ||
122 obj != null &&
123 getClass() == obj.getClass() &&
124 Objects.equals(_validCharacters, ((CharacterChromosome)obj)._validCharacters) &&
125 super.equals(obj);
126 }
127
128 @Override
129 public String toString() {
130 return new String(toArray());
131 }
132
133 /**
134 * Returns an char array containing all of the elements in this chromosome
135 * in proper sequence. If the chromosome fits in the specified array, it is
136 * returned therein. Otherwise, a new array is allocated with the length of
137 * this chromosome.
138 *
139 * @since 3.0
140 *
141 * @param array the array into which the elements of this chromosomes are to
142 * be stored, if it is big enough; otherwise, a new array is
143 * allocated for this purpose.
144 * @return an array containing the elements of this chromosome
145 * @throws NullPointerException if the given {@code array} is {@code null}
146 */
147 public char[] toArray(final char[] array) {
148 final char[] a = array.length >= length()
149 ? array
150 : new char[length()];
151
152 for (int i = length(); --i >= 0;) {
153 a[i] = charAt(i);
154 }
155
156 return a;
157 }
158
159 /**
160 * Returns an char array containing all of the elements in this chromosome
161 * in proper sequence.
162 *
163 * @since 3.0
164 *
165 * @return an array containing the elements of this chromosome
166 */
167 public char[] toArray() {
168 return toArray(new char[length()]);
169 }
170
171
172 /* *************************************************************************
173 * Static factory methods.
174 * ************************************************************************/
175
176 /**
177 * Create a new chromosome with the {@code validCharacters} char set as
178 * valid characters.
179 *
180 * @since 4.3
181 *
182 * @param validCharacters the valid characters for this chromosome.
183 * @param lengthRange the allowed length range of the chromosome.
184 * @return a new {@code CharacterChromosome} with the given parameter
185 * @throws NullPointerException if the {@code validCharacters} is
186 * {@code null}.
187 * @throws IllegalArgumentException if the length of the gene sequence is
188 * empty, doesn't match with the allowed length range, the minimum
189 * or maximum of the range is smaller or equal zero or the given
190 * range size is zero.
191 */
192 public static CharacterChromosome of(
193 final CharSeq validCharacters,
194 final IntRange lengthRange
195 ) {
196 return new CharacterChromosome(
197 CharacterGene.seq(validCharacters, lengthRange),
198 lengthRange
199 );
200 }
201
202 /**
203 * Create a new chromosome with the {@link CharacterGene#DEFAULT_CHARACTERS}
204 * char set as valid characters.
205 *
206 * @param lengthRange the allowed length range of the chromosome.
207 * @return a new {@code CharacterChromosome} with the given parameter
208 * @throws IllegalArgumentException if the {@code length} is smaller than
209 * one.
210 */
211 public static CharacterChromosome of(final IntRange lengthRange) {
212 return of(DEFAULT_CHARACTERS, lengthRange);
213 }
214
215 /**
216 * Create a new chromosome with the {@code validCharacters} char set as
217 * valid characters.
218 *
219 * @since 4.3
220 *
221 * @param validCharacters the valid characters for this chromosome.
222 * @param length the {@code length} of the new chromosome.
223 * @return a new {@code CharacterChromosome} with the given parameter
224 * @throws NullPointerException if the {@code validCharacters} is
225 * {@code null}.
226 * @throws IllegalArgumentException if the length of the gene sequence is
227 * empty, doesn't match with the allowed length range, the minimum
228 * or maximum of the range is smaller or equal zero or the given
229 * range size is zero.
230 */
231 public static CharacterChromosome of(
232 final CharSeq validCharacters,
233 final int length
234 ) {
235 return of(validCharacters, IntRange.of(length));
236 }
237
238 /**
239 * Create a new chromosome with the {@link CharacterGene#DEFAULT_CHARACTERS}
240 * char set as valid characters.
241 *
242 * @param length the {@code length} of the new chromosome.
243 * @return a new {@code CharacterChromosome} with the given parameter
244 * @throws IllegalArgumentException if the {@code length} is smaller than
245 * one.
246 */
247 public static CharacterChromosome of(final int length) {
248 return of(DEFAULT_CHARACTERS, length);
249 }
250
251 /**
252 * Create a new chromosome from the given genes (given as string).
253 *
254 * @param alleles the character genes.
255 * @param validChars the valid characters.
256 * @return a new {@code CharacterChromosome} with the given parameter
257 * @throws IllegalArgumentException if the genes string is empty.
258 */
259 public static CharacterChromosome of(
260 final String alleles,
261 final CharSeq validChars
262 ) {
263 final IntRef index = new IntRef();
264 final Supplier<CharacterGene> geneFactory = () -> CharacterGene.of(
265 alleles.charAt(index.value++), validChars
266 );
267
268 final ISeq<CharacterGene> genes =
269 MSeq.<CharacterGene>ofLength(alleles.length())
270 .fill(geneFactory)
271 .toISeq();
272
273 return new CharacterChromosome(genes, IntRange.of(alleles.length()));
274 }
275
276 /**
277 * Create a new chromosome from the given genes (given as string).
278 *
279 * @param alleles the character genes.
280 * @return a new {@code CharacterChromosome} with the given parameter
281 * @throws IllegalArgumentException if the genes string is empty.
282 */
283 public static CharacterChromosome of(final String alleles) {
284 return of(alleles, DEFAULT_CHARACTERS);
285 }
286
287
288 /* *************************************************************************
289 * Java object serialization
290 * ************************************************************************/
291
292 private Object writeReplace() {
293 return new Serial(Serial.CHARACTER_CHROMOSOME, this);
294 }
295
296 private void readObject(final ObjectInputStream stream)
297 throws InvalidObjectException
298 {
299 throw new InvalidObjectException("Serialization proxy required.");
300 }
301
302 void write(final DataOutput out) throws IOException {
303 writeInt(lengthRange().getMin(), out);
304 writeInt(lengthRange().getMax(), out);
305 writeString(_validCharacters.toString(), out);
306 writeString(toString(), out);
307 }
308
309 static CharacterChromosome read(final DataInput in) throws IOException {
310 final IntRange lengthRange = IntRange.of(readInt(in), readInt(in));
311 final CharSeq validCharacters = new CharSeq(readString(in));
312 final String chars = readString(in);
313
314 final MSeq<CharacterGene> values = MSeq.ofLength(chars.length());
315 for (int i = 0, n = chars.length(); i < n; ++i) {
316 values.set(i, CharacterGene.of(chars.charAt(i), validCharacters));
317 }
318
319 return new CharacterChromosome(values.toISeq(), lengthRange);
320 }
321
322 }
|