DoubleGene.java
001 /*
002  * Java Genetic Algorithm Library (jenetics-8.0.0).
003  * Copyright (c) 2007-2024 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.Hashes.hash;
023 import static io.jenetics.util.RandomRegistry.random;
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.Serial;
031 import java.io.Serializable;
032 
033 import io.jenetics.util.DoubleRange;
034 import io.jenetics.util.ISeq;
035 import io.jenetics.util.IntRange;
036 import io.jenetics.util.MSeq;
037 import io.jenetics.util.Mean;
038 
039 /**
040  * Implementation of the NumericGene which holds a 64-bit floating point number.
041  *
042  <p>This is a <a href="https://docs.oracle.com/javase/8/docs/api/java/lang/doc-files/ValueBased.html">
043  * value-based</a> class; use of identity-sensitive operations (including
044  * reference equality ({@code ==}), identity hash code, or synchronization) on
045  * instances of {@code DoubleGene} may have unpredictable results and should
046  * be avoided.
047  *
048  @see DoubleChromosome
049  *
050  * @implNote
051  * This class is immutable and thread-safe.
052  *
053  @author <a href="mailto:franz.wilhelmstoetter@gmail.com">Franz Wilhelmstötter</a>
054  @since 1.6
055  @version 6.0
056  */
057 public final class DoubleGene
058     implements
059         NumericGene<Double, DoubleGene>,
060         Mean<DoubleGene>,
061         Comparable<DoubleGene>,
062         Serializable
063 {
064 
065     @Serial
066     private static final long serialVersionUID = 2L;
067 
068     private final double _allele;
069     private final double _min;
070     private final double _max;
071 
072     /**
073      * Create a new random {@code DoubleGene} with the given value and the
074      * given range. If the {@code value} isn't within the interval [min, max),
075      * no exception is thrown. In this case the method
076      {@link DoubleGene#isValid()} returns {@code false}.
077      *
078      @param allele the value of the gene.
079      @param min the minimal valid value of this gene (inclusively).
080      @param max the maximal valid value of this gene (exclusively).
081      */
082     private DoubleGene(final double allele, final double min, final double max) {
083         _allele = allele;
084         _min = min;
085         _max = max;
086     }
087 
088     @Override
089     public Double allele() {
090         return _allele;
091     }
092 
093     @Override
094     public Double min() {
095         return _min;
096     }
097 
098     @Override
099     public Double max() {
100         return _max;
101     }
102 
103     /**
104      * Return the range of {@code this} gene.
105      *
106      @since 4.4
107      *
108      @return the range of {@code this} gene
109      */
110     public DoubleRange range() {
111         return DoubleRange.of(_min, _max);
112     }
113 
114     @Override
115     public byte byteValue() {
116         return (byte)_allele;
117     }
118 
119     @Override
120     public short shortValue() {
121         return (short)_allele;
122     }
123 
124     @Override
125     public int intValue() {
126         return (int)_allele;
127     }
128 
129     @Override
130     public long longValue() {
131         return (long)_allele;
132     }
133 
134     @Override
135     public float floatValue() {
136         return (float)_allele;
137     }
138 
139     @Override
140     public double doubleValue() {
141          return _allele;
142     }
143 
144     @Override
145     public boolean isValid() {
146         return
147             Double.isFinite(_allele&&
148             Double.isFinite(_min&&
149             Double.isFinite(_max&&
150             Double.compare(_allele, _min>= &&
151             Double.compare(_allele, _max0;
152     }
153 
154     @Override
155     public int compareTo(final DoubleGene other) {
156         return Double.compare(_allele, other._allele);
157     }
158 
159     @Override
160     public DoubleGene mean(final DoubleGene that) {
161         // (a - a/2) + b/2
162         // https://hal.archives-ouvertes.fr/hal-00576641v1/document
163         return of((_allele - _allele/2.0+ that._allele/2.0, _min, _max);
164     }
165 
166     /**
167      * Create a new gene from the given {@code value} and the gene context.
168      *
169      @since 5.0
170      @param allele the value of the new gene.
171      @return a new gene with the given value.
172      */
173     public DoubleGene newInstance(final double allele) {
174         return DoubleGene.of(allele, _min, _max);
175     }
176 
177     @Override
178     public DoubleGene newInstance(final Double allele) {
179         return of(allele, _min, _max);
180     }
181 
182     @Override
183     public DoubleGene newInstance(final Number allele) {
184         return of(allele.doubleValue(), _min, _max);
185     }
186 
187     @Override
188     public DoubleGene newInstance() {
189         return of(random().nextDouble(_min, _max), _min, _max);
190     }
191 
192     @Override
193     public int hashCode() {
194         return hash(_allele, hash(_min, hash(_max)));
195     }
196 
197     @Override
198     public boolean equals(final Object obj) {
199         return obj == this ||
200             obj instanceof DoubleGene other &&
201             Double.compare(other._allele, _allele== &&
202             Double.compare(other._min, _min== &&
203             Double.compare(other._max, _max== 0;
204     }
205 
206     @Override
207     public String toString() {
208         return String.format("[%s]", _allele);
209     }
210 
211 
212     /* *************************************************************************
213      * Static factory methods.
214      * ************************************************************************/
215 
216     /**
217      * Create a new random {@code DoubleGene} with the given value and the
218      * given range. If the {@code value} isn't within the interval [min, max),
219      * no exception is thrown. In this case the method
220      {@link DoubleGene#isValid()} returns {@code false}.
221      *
222      @param allele the value of the gene.
223      @param min the minimal valid value of this gene (inclusively).
224      @param max the maximal valid value of this gene (exclusively).
225      @return a new {@code DoubleGene} with the given parameter
226      */
227     public static DoubleGene of(
228         final double allele,
229         final double min,
230         final double max
231     ) {
232         return new DoubleGene(allele, min, max);
233     }
234 
235     /**
236      * Create a new random {@code DoubleGene} with the given value and the
237      * given range. If the {@code value} isn't within the interval [min, max),
238      * no exception is thrown. In this case the method
239      {@link DoubleGene#isValid()} returns {@code false}.
240      *
241      @since 3.2
242      *
243      @param allele the value of the gene.
244      @param range the double range to use
245      @return a new random {@code DoubleGene}
246      @throws NullPointerException if the given {@code range} is {@code null}.
247      */
248     public static DoubleGene of(final double allele, final DoubleRange range) {
249         return of(allele, range.min(), range.max());
250     }
251 
252     /**
253      * Create a new random {@code DoubleGene}. It is guaranteed that the value
254      * of the {@code DoubleGene} lies in the interval [min, max).
255      *
256      @param min the minimal valid value of this gene (inclusively).
257      @param max the maximal valid value of this gene (exclusively).
258      @return a new {@code DoubleGene} with the given parameter
259      @throws IllegalArgumentException if {@code min} is not finite,
260      *         or {@code max} is not finite, or {@code min}
261      *         is greater than or equal to {@code max}
262      */
263     public static DoubleGene of(final double min, final double max) {
264         return of(random().nextDouble(min, max), min, max);
265     }
266 
267     /**
268      * Create a new random {@code DoubleGene}. It is guaranteed that the value
269      * of the {@code DoubleGene} lies in the interval [min, max).
270      *
271      @since 3.2
272      *
273      @param range the double range to use
274      @return a new {@code DoubleGene} with the given parameter
275      @throws NullPointerException if the given {@code range} is {@code null}.
276      @throws IllegalArgumentException if {@code min} is not finite,
277      *         or {@code max} is not finite, or {@code min}
278      *         is greater than or equal to {@code max}
279      */
280     public static DoubleGene of(final DoubleRange range) {
281         return of(range.min(), range.max());
282     }
283 
284     static ISeq<DoubleGene> seq(
285         final double min,
286         final double max,
287         final IntRange lengthRange
288     ) {
289         final var random = random();
290         final var length = random.nextInt(lengthRange.min(), lengthRange.max());
291 
292         return MSeq.<DoubleGene>ofLength(length)
293             .fill(() -> new DoubleGene(random.nextDouble(min, max), min, max))
294             .toISeq();
295     }
296 
297 
298     /* *************************************************************************
299      *  Java object serialization
300      * ************************************************************************/
301 
302     @Serial
303     private Object writeReplace() {
304         return new SerialProxy(SerialProxy.DOUBLE_GENE, this);
305     }
306 
307     @Serial
308     private void readObject(final ObjectInputStream stream)
309         throws InvalidObjectException
310     {
311         throw new InvalidObjectException("Serialization proxy required.");
312     }
313 
314     void write(final DataOutput outthrows IOException {
315         out.writeDouble(_allele);
316         out.writeDouble(_min);
317         out.writeDouble(_max);
318     }
319 
320     static DoubleGene read(final DataInput inthrows IOException {
321         return of(in.readDouble(), in.readDouble(), in.readDouble());
322     }
323 
324 }