LongChromosome.java
001 /*
002  * Java Genetic Algorithm Library (jenetics-6.3.0).
003  * Copyright (c) 2007-2021 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 java.util.Objects.requireNonNull;
023 import static io.jenetics.internal.util.SerialIO.readInt;
024 import static io.jenetics.internal.util.SerialIO.readLong;
025 import static io.jenetics.internal.util.SerialIO.writeInt;
026 import static io.jenetics.internal.util.SerialIO.writeLong;
027 
028 import java.io.DataInput;
029 import java.io.DataOutput;
030 import java.io.IOException;
031 import java.io.InvalidObjectException;
032 import java.io.ObjectInputStream;
033 import java.io.Serializable;
034 import java.util.function.Function;
035 import java.util.stream.IntStream;
036 import java.util.stream.LongStream;
037 import java.util.stream.Stream;
038 
039 import io.jenetics.util.ISeq;
040 import io.jenetics.util.IntRange;
041 import io.jenetics.util.LongRange;
042 import io.jenetics.util.MSeq;
043 
044 /**
045  * Numeric chromosome implementation which holds 64 bit integer numbers.
046  *
047  @see LongGene
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.6
054  @version 6.1
055  */
056 public class LongChromosome
057     extends AbstractBoundedChromosome<Long, LongGene>
058     implements
059         NumericChromosome<Long, LongGene>,
060         Serializable
061 {
062     private static final long serialVersionUID = 3L;
063 
064     /**
065      * Create a new chromosome from the given {@code genes} and the allowed
066      * length range of the chromosome.
067      *
068      @since 4.0
069      *
070      @param genes the genes that form the chromosome.
071      @param lengthRange the allowed length range of the chromosome
072      @throws NullPointerException if one of the arguments is {@code null}.
073      @throws IllegalArgumentException if the length of the gene sequence is
074      *         empty, doesn't match with the allowed length range, the minimum
075      *         or maximum of the range is smaller or equal zero or the given
076      *         range size is zero.
077      */
078     protected LongChromosome(
079         final ISeq<LongGene> genes,
080         final IntRange lengthRange
081     ) {
082         super(genes, lengthRange);
083     }
084 
085     @Override
086     public LongChromosome newInstance(final ISeq<LongGene> genes) {
087         return new LongChromosome(genes, lengthRange());
088     }
089 
090     @Override
091     public LongChromosome newInstance() {
092         return of(_min, _max, lengthRange());
093     }
094 
095     /**
096      * Maps the gene alleles of this chromosome, given as {@code long[]} array,
097      * by applying the given mapper function {@code f}. The mapped gene values
098      * are then wrapped into a newly created chromosome.
099      *
100      <pre>{@code
101      * final LongChromosome chromosome = ...;
102      * final LongChromosome halved = chromosome.map(Main::half);
103      *
104      * static long[] half(final long[] values) {
105      *     for (int i = 0; i < values.length; ++i) {
106      *         values[i] /= 2;
107      *     }
108      *     return values;
109      * }
110      * }</pre>
111      *
112      @since 6.1
113      *
114      @param f the mapper function
115      @return a newly created chromosome with the mapped gene values
116      @throws NullPointerException if the mapper function is {@code null}.
117      @throws IllegalArgumentException if the length of the mapped
118      *         {@code long[]} array is empty or doesn't match with the allowed
119      *         length range
120      */
121     public LongChromosome map(final Function<? super long[]long[]> f) {
122         requireNonNull(f);
123 
124         final var range = LongRange.of(_min, _max);
125         final var genes = LongStream.of(f.apply(toArray()))
126             .mapToObj(v -> LongGene.of(v, range))
127             .collect(ISeq.toISeq());
128 
129         return newInstance(genes);
130     }
131 
132     /**
133      * Returns a sequential stream of the alleles with this chromosome as its
134      * source.
135      *
136      @since 4.3
137      *
138      @return a sequential stream of alleles
139      */
140     public LongStream longStream() {
141         return IntStream.range(0, length()).mapToLong(this::longValue);
142     }
143 
144     /**
145      * Returns an long array containing all of the elements in this chromosome
146      * in proper sequence.  If the chromosome fits in the specified array, it is
147      * returned therein. Otherwise, a new array is allocated with the length of
148      * this chromosome.
149      *
150      @since 3.0
151      *
152      @param array the array into which the elements of this chromosomes are to
153      *        be stored, if it is big enough; otherwise, a new array is
154      *        allocated for this purpose.
155      @return an array containing the elements of this chromosome
156      @throws NullPointerException if the given {@code array} is {@code null}
157      */
158     public long[] toArray(final long[] array) {
159         final long[] a = array.length >= length() ? array : new long[length()];
160         for (int i = length(); --i >= 0;) {
161             a[i= longValue(i);
162         }
163 
164         return a;
165     }
166 
167     /**
168      * Returns an long array containing all of the elements in this chromosome
169      * in proper sequence.
170      *
171      @since 3.0
172      *
173      @return an array containing the elements of this chromosome
174      */
175     public long[] toArray() {
176         return toArray(new long[length()]);
177     }
178 
179 
180     /* *************************************************************************
181      * Static factory methods.
182      * ************************************************************************/
183 
184     /**
185      * Create a new {@code LongChromosome} with the given genes.
186      *
187      @param genes the genes of the chromosome.
188      @return a new chromosome with the given genes.
189      @throws NullPointerException if the given {@code genes} are {@code null}
190      @throws IllegalArgumentException if the length of the genes array is
191      *         empty or the given {@code genes} doesn't have the same range.
192      */
193     public static LongChromosome of(final LongGene... genes) {
194         checkGeneRange(Stream.of(genes).map(LongGene::range));
195         return new LongChromosome(ISeq.of(genes), IntRange.of(genes.length));
196     }
197 
198     /**
199      * Create a new {@code LongChromosome} with the given genes.
200      *
201      @since 4.3
202      *
203      @param genes the genes of the chromosome.
204      @return a new chromosome with the given genes.
205      @throws NullPointerException if the given {@code genes} are {@code null}
206      @throws IllegalArgumentException if the of the genes iterable is empty or
207      *         the given {@code genes} doesn't have the same range.
208      */
209     public static LongChromosome of(final Iterable<LongGene> genes) {
210         final ISeq<LongGene> values = ISeq.of(genes);
211         checkGeneRange(values.stream().map(LongGene::range));
212         return new LongChromosome(values, IntRange.of(values.length()));
213     }
214 
215     /**
216      * Create a new random chromosome.
217      *
218      @since 4.0
219      *
220      @param min the min value of the {@link LongGene}s (inclusively).
221      @param max the max value of the {@link LongGene}s (inclusively).
222      @param lengthRange the allowed length range of the chromosome.
223      @return a new {@code IntegerChromosome} with the given parameter
224      @throws IllegalArgumentException if the length of the gene sequence is
225      *         empty, doesn't match with the allowed length range, the minimum
226      *         or maximum of the range is smaller or equal zero or the given
227      *         range size is zero.
228      @throws NullPointerException if the given {@code lengthRange} is
229      *         {@code null}
230      */
231     public static LongChromosome of(
232         final long min,
233         final long max,
234         final IntRange lengthRange
235     ) {
236         final ISeq<LongGene> values = LongGene.seq(min, max, lengthRange);
237         return new LongChromosome(values, lengthRange);
238     }
239 
240     /**
241      * Create a new random {@code LongChromosome}.
242      *
243      @param min the min value of the {@link LongGene}s (inclusively).
244      @param max the max value of the {@link LongGene}s (inclusively).
245      @param length the length of the chromosome.
246      @return a new {@code LongChromosome} with the given gene parameters.
247      @throws IllegalArgumentException if the {@code length} is smaller than
248      *         one.
249      */
250     public static LongChromosome of(
251         final long min,
252         final long max,
253         final int length
254     ) {
255         return of(min, max, IntRange.of(length));
256     }
257 
258     /**
259      * Create a new random chromosome.
260      *
261      @since 4.0
262      *
263      @param range the integer range of the chromosome.
264      @param lengthRange the allowed length range of the chromosome.
265      @return a new {@code LongChromosome} with the given parameter
266      @throws IllegalArgumentException if the length of the gene sequence is
267      *         empty, doesn't match with the allowed length range, the minimum
268      *         or maximum of the range is smaller or equal zero or the given
269      *         range size is zero.
270      @throws NullPointerException if the given {@code lengthRange} is
271      *         {@code null}
272      */
273     public static LongChromosome of(
274         final LongRange range,
275         final IntRange lengthRange
276     ) {
277         return of(range.min(), range.max(), lengthRange);
278     }
279 
280     /**
281      * Create a new random {@code LongChromosome}.
282      *
283      @since 3.2
284      *
285      @param range the long range of the chromosome.
286      @param length the length of the chromosome.
287      @return a new random {@code LongChromosome}
288      @throws NullPointerException if the given {@code range} is {@code null}
289      @throws IllegalArgumentException if the {@code length} is smaller than
290      *         one.
291      */
292     public static LongChromosome of(final LongRange range, final int length) {
293         return of(range.min(), range.max(), length);
294     }
295 
296     /**
297      * Create a new random {@code LongChromosome} of length one.
298      *
299      @param min the minimal value of this chromosome (inclusively).
300      @param max the maximal value of this chromosome (inclusively).
301      @return a new {@code LongChromosome} with the given gene parameters.
302      */
303     public static LongChromosome of(final long min, final long max) {
304         return of(min, max, 1);
305     }
306 
307     /**
308      * Create a new random {@code LongChromosome} of length one.
309      *
310      @since 3.2
311      *
312      @param range the long range of the chromosome.
313      @return a new random {@code LongChromosome} of length one
314      @throws NullPointerException if the given {@code range} is {@code null}
315      */
316     public static LongChromosome of(final LongRange range) {
317         return of(range.min(), range.max());
318     }
319 
320 
321 
322     /* *************************************************************************
323      *  Java object serialization
324      * ************************************************************************/
325 
326     private Object writeReplace() {
327         return new Serial(Serial.LONG_CHROMOSOME, this);
328     }
329 
330     private void readObject(final ObjectInputStream stream)
331         throws InvalidObjectException
332     {
333         throw new InvalidObjectException("Serialization proxy required.");
334     }
335 
336     void write(final DataOutput outthrows IOException {
337         writeInt(length(), out);
338         writeInt(lengthRange().min(), out);
339         writeInt(lengthRange().max(), out);
340         writeLong(_min, out);
341         writeLong(_max, out);
342 
343         for (int i = 0, n = length(); i < n; ++i) {
344             writeLong(longValue(i), out);
345         }
346     }
347 
348     static LongChromosome read(final DataInput inthrows IOException {
349         final var length = readInt(in);
350         final var lengthRange = IntRange.of(readInt(in), readInt(in));
351         final var min = readLong(in);
352         final var max = readLong(in);
353 
354         final MSeq<LongGene> values = MSeq.ofLength(length);
355         for (int i = 0; i < length; ++i) {
356             values.set(i, LongGene.of(readLong(in), min, max));
357         }
358 
359         return new LongChromosome(values.toISeq(), lengthRange);
360     }
361 
362 }