001 /*
002 * Java Genetic Algorithm Library (jenetics-4.4.0).
003 * Copyright (c) 2007-2019 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.lang.String.format;
023 import static io.jenetics.internal.util.Hashes.hash;
024 import static io.jenetics.util.RandomRegistry.getRandom;
025
026 import java.io.Serializable;
027 import java.util.Random;
028
029 import io.jenetics.internal.math.random;
030 import io.jenetics.util.ISeq;
031 import io.jenetics.util.IntRange;
032 import io.jenetics.util.MSeq;
033 import io.jenetics.util.Mean;
034
035 /**
036 * NumericGene implementation which holds a 32 bit integer number.
037 *
038 * <p>This is a <a href="https://docs.oracle.com/javase/8/docs/api/java/lang/doc-files/ValueBased.html">
039 * value-based</a> class; use of identity-sensitive operations (including
040 * reference equality ({@code ==}), identity hash code, or synchronization) on
041 * instances of {@code IntegerGene} may have unpredictable results and should
042 * be avoided.
043 *
044 * @see IntegerChromosome
045 *
046 * @implNote
047 * This class is immutable and thread-safe.
048 *
049 * @author <a href="mailto:franz.wilhelmstoetter@gmail.com">Franz Wilhelmstötter</a>
050 * @since 2.0
051 * @version 4.3
052 */
053 public final class IntegerGene
054 implements
055 NumericGene<Integer, IntegerGene>,
056 Mean<IntegerGene>,
057 Comparable<IntegerGene>,
058 Serializable
059 {
060
061 private static final long serialVersionUID = 2L;
062
063 private final int _value;
064 private final int _min;
065 private final int _max;
066
067 /**
068 * Create a new random {@code IntegerGene} with the given value and the
069 * given range. If the {@code value} isn't within the interval [min, max],
070 * no exception is thrown. In this case the method
071 * {@link IntegerGene#isValid()} returns {@code false}.
072 *
073 * @param value the value of the gene.
074 * @param min the minimal valid value of this gene (inclusively).
075 * @param max the maximal valid value of this gene (inclusively).
076 */
077 private IntegerGene(final int value, final int min, final int max) {
078 _value = value;
079 _min = min;
080 _max = max;
081 }
082
083 @Override
084 public Integer getAllele() {
085 return _value;
086 }
087
088 @Override
089 public Integer getMin() {
090 return _min;
091 }
092
093 @Override
094 public Integer getMax() {
095 return _max;
096 }
097
098 /**
099 * Return the range of {@code this} gene.
100 *
101 * @since 4.4
102 *
103 * @return the range of {@code this} gene
104 */
105 public IntRange range() {
106 return IntRange.of(_min, _max);
107 }
108
109 @Override
110 public byte byteValue() {
111 return (byte)_value;
112 }
113
114 @Override
115 public short shortValue() {
116 return (short)_value;
117 }
118
119 @Override
120 public int intValue() {
121 return _value;
122 }
123
124 @Override
125 public long longValue() {
126 return _value;
127 }
128
129 @Override
130 public float floatValue() {
131 return (float)_value;
132 }
133
134 @Override
135 public double doubleValue() {
136 return _value;
137 }
138
139 @Override
140 public boolean isValid() {
141 return _value >= _min && _value <= _max;
142 }
143
144 @Override
145 public int compareTo(final IntegerGene other) {
146 return Integer.compare(_value, other._value);
147 }
148
149 @Override
150 public IntegerGene newInstance(final Integer number) {
151 return IntegerGene.of(number, _min, _max);
152 }
153
154 @Override
155 public IntegerGene newInstance(final Number number) {
156 return IntegerGene.of(number.intValue(), _min, _max);
157 }
158
159 @Override
160 public IntegerGene newInstance() {
161 return IntegerGene.of(nextInt(getRandom(), _min, _max), _min, _max);
162 }
163
164 @Override
165 public IntegerGene mean(final IntegerGene that) {
166 return IntegerGene.of(_value + (that._value - _value)/2, _min, _max);
167 }
168
169 @Override
170 public int hashCode() {
171 return hash(_value, hash(_min, hash(_max, hash(getClass()))));
172 }
173
174 @Override
175 public boolean equals(final Object obj) {
176 return obj == this ||
177 obj instanceof IntegerGene &&
178 ((IntegerGene)obj)._value == _value &&
179 ((IntegerGene)obj)._min == _min &&
180 ((IntegerGene)obj)._max == _max;
181 }
182
183 @Override
184 public String toString() {
185 return String.format("[%s]", _value);
186 }
187
188 /* *************************************************************************
189 * Static factory methods.
190 * ************************************************************************/
191
192 /**
193 * Create a new random {@code IntegerGene} with the given value and the
194 * given range. If the {@code value} isn't within the interval [min, max],
195 * no exception is thrown. In this case the method
196 * {@link IntegerGene#isValid()} returns {@code false}.
197 *
198 * @param value the value of the gene.
199 * @param min the minimal valid value of this gene (inclusively).
200 * @param max the maximal valid value of this gene (inclusively).
201 * @return a new {@code IntegerGene} with the given {@code value}
202 */
203 public static IntegerGene of(final int value, final int min, final int max) {
204 return new IntegerGene(value, min, max);
205 }
206
207 /**
208 * Create a new random {@code IntegerGene} with the given value and the
209 * given range. If the {@code value} isn't within the interval [min, max],
210 * no exception is thrown. In this case the method
211 * {@link IntegerGene#isValid()} returns {@code false}.
212 *
213 * @since 3.2
214 *
215 * @param value the value of the gene.
216 * @param range the integer range to use
217 * @return a new {@code IntegerGene} with the give {@code value}
218 * @throws NullPointerException if the given {@code range} is {@code null}.
219 */
220 public static IntegerGene of(final int value, final IntRange range) {
221 return IntegerGene.of(value, range.getMin(), range.getMax());
222 }
223
224 /**
225 * Create a new random {@code IntegerGene}. It is guaranteed that the value of
226 * the {@code IntegerGene} lies in the interval [min, max].
227 *
228 * @param min the minimal valid value of this gene (inclusively).
229 * @param max the maximal valid value of this gene (inclusively).
230 * @return a new random {@code IntegerGene}
231 */
232 public static IntegerGene of(final int min, final int max) {
233 return of(nextInt(getRandom(), min, max), min, max);
234 }
235
236 /**
237 * Create a new random {@code IntegerGene}. It is guaranteed that the value of
238 * the {@code IntegerGene} lies in the interval [min, max].
239 *
240 * @since 3.2
241 *
242 * @param range the integer range to use
243 * @return a new random {@code IntegerGene}
244 * @throws NullPointerException if the given {@code range} is {@code null}.
245 */
246 public static IntegerGene of(final IntRange range) {
247 return of(nextInt(getRandom(), range.getMin(), range.getMax()), range);
248 }
249
250 static ISeq<IntegerGene> seq(
251 final int min,
252 final int max,
253 final IntRange lengthRange
254 ) {
255 final Random r = getRandom();
256
257 return MSeq.<IntegerGene>ofLength(random.nextInt(lengthRange, r))
258 .fill(() -> new IntegerGene(nextInt(r, min, max), min, max))
259 .toISeq();
260 }
261
262 /**
263 * Returns a pseudo-random, uniformly distributed int value between min and
264 * max (min and max included).
265 *
266 * @param random the random engine to use for calculating the random int
267 * value
268 * @param min lower bound for generated integer
269 * @param max upper bound for generated integer
270 * @return a random integer greater than or equal to {@code min} and
271 * less than or equal to {@code max}
272 * @throws IllegalArgumentException if {@code min > max}
273 * @throws NullPointerException if the given {@code random}
274 * engine is {@code null}.
275 */
276 static int nextInt(
277 final Random random,
278 final int min, final int max
279 ) {
280 if (min > max) {
281 throw new IllegalArgumentException(format(
282 "Min >= max: %d >= %d", min, max
283 ));
284 }
285
286 final int diff = max - min + 1;
287 int result = 0;
288
289 if (diff <= 0) {
290 do {
291 result = random.nextInt();
292 } while (result < min || result > max);
293 } else {
294 result = random.nextInt(diff) + min;
295 }
296
297 return result;
298 }
299
300 }
|