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.internal.math; 021 022import static java.util.Objects.requireNonNull; 023import static io.jenetics.internal.math.Probabilities.isOne; 024import static io.jenetics.internal.math.Probabilities.isZero; 025import static io.jenetics.internal.util.Requires.probability; 026 027import java.util.random.RandomGenerator; 028import java.util.stream.IntStream; 029 030/** 031 * Some random helper functions. 032 * 033 * @author <a href="mailto:franz.wilhelmstoetter@gmail.com">Franz Wilhelmstötter</a> 034 * @since 1.4 035 * @version 7.0 036 */ 037public final class Randoms { 038 private Randoms() {} 039 040 public static byte nextByte(final RandomGenerator random) { 041 return (byte)random.nextInt(Byte.MIN_VALUE, Byte.MAX_VALUE + 1); 042 } 043 044 public static char nextChar(final RandomGenerator random) { 045 record Limits() { 046 private static final int LEFT = '0'; 047 private static final int RIGHT = 'z' + 1; 048 } 049 050 char c = '\0'; 051 do { 052 c = (char)random.nextInt(Limits.LEFT, Limits.RIGHT); 053 } while (!((c <= 57 || c >= 65) && (c <= 90 || c >= 97))); 054 055 return c; 056 } 057 058 public static short nextShort(final RandomGenerator random) { 059 return (short)random.nextInt(Short.MIN_VALUE, Short.MAX_VALUE + 1); 060 } 061 062 public static String nextASCIIString( 063 final int length, 064 final RandomGenerator random 065 ) { 066 final char[] chars = new char[length]; 067 for (int i = 0; i < length; ++i) { 068 chars[i] = (char)random.nextInt(32, 127); 069 } 070 071 return new String(chars); 072 } 073 074 public static String nextASCIIString(final RandomGenerator random) { 075 return nextASCIIString(random.nextInt(5, 20), random); 076 } 077 078 /** 079 * Create an {@code IntStream} which creates random indexes within the 080 * given range and the index probability. 081 * 082 * @since 3.0 083 * 084 * @param random the random engine used for calculating the random 085 * indexes 086 * @param start the start index (inclusively) 087 * @param end the end index (exclusively) 088 * @param p the index selection probability 089 * @return a new random index stream 090 * @throws IllegalArgumentException if {@code p} is not a 091 * valid probability. 092 */ 093 public static IntStream indexes( 094 final RandomGenerator random, 095 final int start, 096 final int end, 097 final double p 098 ) { 099 requireNonNull(random); 100 probability(p); 101 102 if (isZero(p)) { 103 return IntStream.empty(); 104 } else if (isOne(p)) { 105 return IntStream.range(start, end); 106 } else { 107 final int P = Probabilities.toInt(p); 108 return IntStream.range(start, end) 109 .filter(i -> random.nextInt() < P); 110 } 111 } 112 113 114 /** 115 * Create an {@code IntStream} which creates random indexes within the 116 * given range and the index probability. 117 * 118 * @since 3.0 119 * 120 * @param random the random engine used for calculating the random 121 * indexes 122 * @param n the end index (exclusively). The start index is zero. 123 * @param p the index selection probability 124 * @return a new random index stream 125 * @throws IllegalArgumentException if {@code p} is not a 126 * valid probability. 127 * @throws NullPointerException if the given {@code random} 128 * engine is {@code null}. 129 */ 130 public static IntStream indexes( 131 final RandomGenerator random, 132 final int n, 133 final double p 134 ) { 135 return indexes(random, 0, n, p); 136 } 137 138 /** 139 * Create a new <em>seed</em> byte array of the given length. 140 * 141 * @see #seed(byte[]) 142 * @see #seed() 143 * 144 * @param length the length of the returned byte array. 145 * @return a new <em>seed</em> byte array of the given length 146 * @throws NegativeArraySizeException if the given length is smaller 147 * than zero. 148 */ 149 public static byte[] seedBytes(final int length) { 150 return seed(new byte[length]); 151 } 152 153 /** 154 * Fills the given byte array with random bytes, created by successive 155 * calls of the {@link #seed()} method. 156 * 157 * @see #seed() 158 * 159 * @param seed the byte array seed to fill with random bytes. 160 * @return the given byte array, for method chaining. 161 * @throws NullPointerException if the {@code seed} array is 162 * {@code null}. 163 */ 164 public static byte[] seed(final byte[] seed) { 165 for (int i = 0, len = seed.length; i < len;) { 166 int n = Math.min(len - i, Long.SIZE/Byte.SIZE); 167 168 for (long x = seed(); n-- > 0; x >>= Byte.SIZE) { 169 seed[i++] = (byte)x; 170 } 171 } 172 173 return seed; 174 } 175 176 /** 177 * Calculating a 64-bit seed value which can be used for initializing 178 * PRNGs. This method uses a combination of {@code System.nanoTime()} 179 * and {@code new Object().hashCode()} calls to create a reasonable safe 180 * seed value: 181 * 182 * {@snippet lang="java": 183 * public static long seed() { 184 * return seed(System.nanoTime()); 185 * } 186 * } 187 * 188 * This method passes all the statistical tests of the 189 * <a href="http://www.phy.duke.edu/~rgb/General/dieharder.php"> 190 * dieharder</a> test suite—executed on a linux machine with 191 * JDK version 1.7. <em>Since there is no prove that this will the case 192 * for every Java version and OS, it is recommended to only use this 193 * method for seeding other PRNGs.</em> 194 * 195 * @see #seed(long) 196 * 197 * @return the random seed value. 198 */ 199 public static long seed() { 200 return seed(System.nanoTime()); 201 } 202 203 /** 204 * Uses the given {@code base} value to create a reasonable safe seed 205 * value. This is done by combining it with values of 206 * {@code new Object().hashCode()}: 207 * 208 * {@snippet lang="java": 209 * public static long seed(final long base) { 210 * final long objectHashSeed = ((long)(new Object().hashCode()) << 32) | 211 * new Object().hashCode(); 212 * long seed = base^objectHashSeed; 213 * seed ^= seed << 17; 214 * seed ^= seed >>> 31; 215 * seed ^= seed << 8; 216 * return seed; 217 * } 218 * } 219 * 220 * @param base the base value of the seed to create 221 * @return the created seed value. 222 */ 223 public static long seed(final long base) { 224 return mix(base, ObjectSeed.seed()); 225 } 226 227 private static long mix(final long a, final long b) { 228 long c = a^b; 229 c ^= c << 17; 230 c ^= c >>> 31; 231 c ^= c << 8; 232 return c; 233 } 234 235 private static final class ObjectSeed { 236 private static long seed() { 237 return (long)new ObjectSeed().hashCode() << 32 | 238 new ObjectSeed().hashCode(); 239 } 240 } 241 242}