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) >= 0 &&
151 Double.compare(_allele, _max) < 0;
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) == 0 &&
202 Double.compare(other._min, _min) == 0 &&
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 out) throws IOException {
315 out.writeDouble(_allele);
316 out.writeDouble(_min);
317 out.writeDouble(_max);
318 }
319
320 static DoubleGene read(final DataInput in) throws IOException {
321 return of(in.readDouble(), in.readDouble(), in.readDouble());
322 }
323
324 }
|