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