View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.rng.core.source64;
18  
19  import java.util.Arrays;
20  import java.util.stream.Stream;
21  import org.apache.commons.rng.LongJumpableUniformRandomProvider;
22  import org.apache.commons.rng.SplittableUniformRandomProvider;
23  import org.apache.commons.rng.UniformRandomProvider;
24  import org.apache.commons.rng.core.RandomAssert;
25  import org.junit.jupiter.api.Test;
26  import org.junit.jupiter.params.provider.Arguments;
27  
28  /**
29   * Test for {@link L128X1024Mix}.
30   */
31  class L128X1024MixTest extends AbstractLXMTest {
32  
33      /**
34       * Factory to create a composite LXM generator that is equivalent
35       * to the RNG under test.
36       */
37      private static class Factory implements LXMGeneratorFactory {
38          static final Factory INSTANCE = new Factory();
39  
40          @Override
41          public int lcgSeedSize() {
42              return 4;
43          }
44  
45          @Override
46          public int xbgSeedSize() {
47              return 16;
48          }
49  
50          @Override
51          public LXMGenerator create(long[] seed) {
52              return new LXMGenerator(getMix(),
53                                      new LCG128(seed[0], seed[1], seed[2], seed[3]),
54                                      new XBGXoRoShiRo1024(Arrays.copyOfRange(seed, 4, 20), false));
55          }
56      }
57  
58      @Override
59      LXMGeneratorFactory getFactory() {
60          return Factory.INSTANCE;
61      }
62  
63      @Override
64      LongJumpableUniformRandomProvider create(long[] seed) {
65          return new L128X1024Mix(seed);
66      }
67  
68      @Override
69      Stream<Arguments> getReferenceData() {
70          /*
71           * Reference data from JDK 19:
72           * java.util.random.RandomGeneratorFactory.of("L128X1024MixRandom").create(seed)
73           *
74           * Full byte[] seed created using SecureRandom.nextBytes. The seed was converted
75           * to long[] by filling the long bits sequentially starting at the most significant
76           * byte matching the method used by the JDK, e.g.
77           * long[] result = new long[seed.length / Long.BYTES];
78           * ByteBuffer.wrap(seed).order(ByteOrder.BIG_ENDIAN).asLongBuffer().get(result);
79           *
80           * Note: Seed order: LCG addition; LCG state; XBG state.
81           */
82          return Stream.of(
83              Arguments.of(
84                  new long[] {
85                      0x6b58aa6ffc337cacL, 0x7554ffc31477c792L, 0xadb09543e412c559L, 0xaec37b44eedbebebL,
86                      0x1b5f8ce14fd365aaL, 0xdd9583b20d633d9aL, 0x047b8ee58629d33dL, 0x1455a9f0a1b5072cL,
87                      0x22176a92ad7fc152L, 0xdd5787b7217de80fL, 0xf2a39d303e489c65L, 0xc639427ce47fdf8fL,
88                      0x719635b081f3f914L, 0xa697379a497e7e39L, 0x9e7ae3aa56a287ccL, 0x8b4abd91a352faa5L,
89                      0x7b5f405155546a12L, 0x5b4043b9f1140d8fL, 0x2cb19f45483f80fbL, 0x0b6e5226e1c85467L,
90                  },
91                  new long[] {
92                      0x5fa2cf23d60cf67cL, 0xc31c2b6451aa2fbaL, 0xd2af323c077ee4d4L, 0x213bed298b3ad585L,
93                      0xdcce8c3e6f63d6c6L, 0x3dfc05a23b884532L, 0xbcbfe3860bef2eaaL, 0xf656a285e4ebbce1L,
94                      0x8f9505806a414372L, 0xbcff459696a30316L, 0xa700a8d63166a0aeL, 0x6407b055a4f0b3c7L,
95                      0xe77333b14d15309aL, 0x70a9155fd1c1961bL, 0xdfc035a8c748ae7eL, 0x534f5830fe5297caL,
96                      0xca187d9d2eab2437L, 0xcc3a1e20a36fa6abL, 0xf8f4960737866c0cL, 0x7eab49fd524b840dL,
97                      0x9937413f08979628L, 0x017565584f1da654L, 0x13c76265c74cc0a6L, 0x54de60aea30cedecL,
98                      0xe80ad8897a74b5a8L, 0xcd1555f1abbf30acL, 0x015d519e2a4c7d53L, 0xad32c13b44c39ffbL,
99                      0xcd6a12650b3753f8L, 0x1486ea548da30363L, 0x98987c807f9660d0L, 0x6bb14b89a9643040L,
100                     0x8ee4d97ec0bced99L, 0x3b9e0ee8a39a959aL, 0x5565cd513ab34ef9L, 0xd81ed95e235db404L,
101                     0x9167e57917401421L, 0x30808415959689a4L, 0x1b868f963e2be44cL, 0x70f98922267d2397L,
102                 }),
103             Arguments.of(
104                 new long[] {
105                     0x72831df890850049L, 0x14d5fad4e42f9302L, 0xde0b08b519b5ed35L, 0xb074db75c9a488eeL,
106                     0x9b32cb087f31bb65L, 0xc47709977d2f66bdL, 0x801689b1d45ccec6L, 0x17b9a964bd7c2914L,
107                     0xf4691614d2280435L, 0x8e891da749b9afc6L, 0xe452871043428ec9L, 0x3412688e450d367cL,
108                     0xb47eaadd6c656be4L, 0x4e4c09a9d9055ec9L, 0x60e549d120c759caL, 0xb1e0ebc749dc7df4L,
109                     0xf479ceebad6b798aL, 0xb71d9e212eb1d1c1L, 0x28f0025d7748addaL, 0x6063774bbe188331L,
110                 },
111                 new long[] {
112                     0x237759030495d6bdL, 0xa1085516169c5723L, 0xf2938d898f81a4dcL, 0x3f2472fa6229549fL,
113                     0x7b5c7d86db5cd897L, 0x2a3e9a1a243ab91fL, 0xad94f5d540a46bccL, 0x7cf02d130867296eL,
114                     0x9ad5f8a5e883b2b2L, 0xc37ac97fff9ba5bdL, 0xf1d836c448e74e62L, 0xdface229fa5babe0L,
115                     0x83fac2cce3a51eeeL, 0xfde459054fb9a650L, 0xf2289c9c7a3ce827L, 0x6096deea7085c16fL,
116                     0xa7542a7e16638f15L, 0x0f38a3642d12078aL, 0x46f08e525547a329L, 0x6ffec9295514502cL,
117                     0xef0ae056313ac76aL, 0x0972748d1e10ce75L, 0x45d76330939da7abL, 0x49a51c499b44c48fL,
118                     0xcda6ac64fcb7e891L, 0xe08859838fb0fec5L, 0xbd1e49427e9460d3L, 0x69ab2b69ce6a6aacL,
119                     0xc4cf49487adaf18fL, 0xf18641ff23c6d099L, 0xe25d8d4195a84f10L, 0x85602ba0e16337cfL,
120                     0x118f4640b8f3550bL, 0xae642cb3a6d01717L, 0x5d3f27a3d6534f66L, 0xbf4ed49c67cd4a4cL,
121                     0x1400824879988551L, 0xad2a6637c4512f53L, 0xf424063005575699L, 0xb29f63cbd1acb668L,
122                 }),
123             Arguments.of(
124                 new long[] {
125                     0x1362c961e1630fbeL, 0xa15f80cdcb56460fL, 0x54a55905815c1d21L, 0x3ae5f0c7bb27dddcL,
126                     0x829c93e6c7c7025bL, 0xb0213f4c376814c1L, 0xba8cbf51f44bb2a5L, 0xeb34355868993b1fL,
127                     0x08f3cda12137f730L, 0x4059c90010dc3b11L, 0xf7268debee731db0L, 0xba1e6900e52effb0L,
128                     0x9901ff51f11fa35bL, 0x28d5e83d8aee75ceL, 0xf38c8641eb866c6dL, 0x9cfa85edc14efaa0L,
129                     0x9e55a1737705d52bL, 0x15a494ad0cf92e68L, 0x74b70ce02553f7ddL, 0x1270569fe023553eL,
130                 },
131                 new long[] {
132                     0x6959d677d00dd35dL, 0x06faab2179b4dbe7L, 0x40ffae141e27250dL, 0x77fdf94f98ee84bfL,
133                     0x981562b903976493L, 0x54036193c77a82fbL, 0x2cf0959da786b980L, 0x7b2481c1a56508dcL,
134                     0x319b4e1e4fc56d20L, 0xc54d3ad54cfd1499L, 0xbb32cf5518dd6be9L, 0xaa4e32f37f7a2586L,
135                     0xf67aacc627b86195L, 0x88980c4616943de3L, 0xb837ab119857807dL, 0x0cfbc2544dbf48b8L,
136                     0xe8b9884fa0ae4e34L, 0x489aaa0d0627a22cL, 0x5443cebef68ea0a6L, 0x5ca4968dfd31b40aL,
137                     0x74cfc71092585a27L, 0x0bda495018792daeL, 0x654affcb7eedad76L, 0xfcb97ca8b72c4382L,
138                     0x89b6d82c5e526ef0L, 0x1d7c02820d6de8d5L, 0x69fe9b84565391a2L, 0xecca48b5a815e5c5L,
139                     0x8f1503297cd02494L, 0x440ee5546a18b02cL, 0xf45519c36b910074L, 0x43dc905fa1732ccbL,
140                     0x27440d7f50533e2eL, 0xab553d44b699875bL, 0x6162c477b201aabbL, 0x5a1addc6a8151187L,
141                     0x33e56bf53aacefb4L, 0x108e02cfdb44c699L, 0xc985a4c385edf80dL, 0x4384e8799019d966L,
142                 }));
143     }
144 
145     /**
146      * Test split with zero bits from the source. This should be robust to escape the state
147      * of all zero bits that will create an invalid state for the xor-based generator (XBG).
148      */
149     @Test
150     void testSplitWithZeroBits() {
151         final UniformRandomProvider zeroSource = () -> 0;
152         final long[] seed = new long[Factory.INSTANCE.seedSize()];
153         // Here we copy the split which sets the LCG increment to odd
154         seed[(Factory.INSTANCE.lcgSeedSize() / 2) - 1] = 1;
155         final SplittableUniformRandomProvider rng1 = new L128X1024Mix(seed);
156         final SplittableUniformRandomProvider rng2 = rng1.split(zeroSource);
157         RandomAssert.assertNextLongNotEquals(seed.length * 2, rng1, rng2);
158 
159         // Since we know how the zero seed is amended
160         long z = 0;
161         for (int i = Factory.INSTANCE.lcgSeedSize(); i < seed.length; i++) {
162             seed[i] = LXMSupport.lea64(z);
163             z += LXMSupport.GOLDEN_RATIO_64;
164         }
165         final SplittableUniformRandomProvider rng3 = new L128X1024Mix(seed);
166         final SplittableUniformRandomProvider rng4 = rng1.split(zeroSource);
167         RandomAssert.assertNextLongEquals(seed.length * 2, rng3, rng4);
168     }
169 }