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