https://mooseframework.inl.gov
Loading...
Searching...
No Matches
MooseRandomPerturbation.C
Go to the documentation of this file.
1//* This file is part of the MOOSE framework
2//* https://mooseframework.inl.gov
3//*
4//* All rights reserved, see COPYRIGHT for full restrictions
5//* https://github.com/idaholab/moose/blob/master/COPYRIGHT
6//*
7//* Licensed under LGPL 2.1, please see LICENSE for details
8//* https://www.gnu.org/licenses/lgpl-2.1.html
9
11
12MooseRandomPerturbation::MooseRandomPerturbation(uint64_t seed, unsigned int n, unsigned int rounds)
13 : _k0(static_cast<uint32_t>(seed)),
14 _k1(static_cast<uint32_t>(seed >> 32)),
15 _n(n),
16 _half_bits((ceilLog2(n) + 1) / 2),
17 _half_mask((uint32_t(1) << _half_bits) - 1),
18 _rounds(rounds)
19{
20 mooseAssert(_n > 0, "n must be > 0");
21 mooseAssert(_rounds > 0, "rounds must be greater than 0.");
22}
23
24uint32_t
26{
27 mooseAssert(x < _n, "x must be < n");
28
29 uint32_t y = x;
30 do
31 {
32 y = permutePadded(y);
33 } while (y >= _n);
34
35 return y;
36}
37
38uint32_t
40{
41 mooseAssert(y < _n, "y must be < n");
42
43 uint32_t x = y;
44 do
45 {
46 x = invertPadded(x);
47 } while (x >= _n);
48
49 return x;
50}
51
52uint32_t
54{
55 // Split x into the upper (L) and lower (R) half_bits-wide halves.
56 uint32_t L = x >> _half_bits;
57 uint32_t R = x & _half_mask;
58
59 for (unsigned int r = 0; r < _rounds; ++r)
60 {
61 // Standard balanced Feistel step: new_L = R, new_R = L XOR F(R).
62 const uint32_t F = roundFunction(R, r);
63 const uint32_t newL = R;
64 const uint32_t newR = (L ^ F) & _half_mask;
65 L = newL;
66 R = newR;
67 }
68
69 return ((L & _half_mask) << _half_bits) | (R & _half_mask);
70}
71
72uint32_t
74{
75 uint32_t L = (y >> _half_bits) & _half_mask;
76 uint32_t R = y & _half_mask;
77
78 // Run rounds in reverse; recover prev_R = L then prev_L = R XOR F(prev_R).
79 for (int r = static_cast<int>(_rounds) - 1; r >= 0; --r)
80 {
81 const uint32_t prevR = L;
82 const uint32_t F = roundFunction(prevR, static_cast<unsigned int>(r));
83 const uint32_t prevL = (R ^ F) & _half_mask;
84 L = prevL;
85 R = prevR;
86 }
87
88 return ((L & _half_mask) << _half_bits) | (R & _half_mask);
89}
90
91uint32_t
92MooseRandomPerturbation::roundFunction(uint32_t half, unsigned int round) const
93{
94 uint32_t x = half;
95 x ^= _k0;
96 x += 0x9e3779b9U * static_cast<uint32_t>(round + 1); // round-dependent constant
97 x ^= _k1;
98 x = mix32(x);
99 return x & _half_mask;
100}
101
102unsigned int
104{
105 mooseAssert(n > 0, "n must be > 0");
106
107 unsigned int bits = 0;
108 uint32_t v = n - 1;
109 while (v > 0)
110 {
111 ++bits;
112 v >>= 1;
113 }
114 return bits;
115}
116
117uint32_t
119{
120 x ^= x >> 16;
121 x *= 0x7feb352dU;
122 x ^= x >> 15;
123 x *= 0x846ca68bU;
124 x ^= x >> 16;
125 return x;
126}
MooseRandomPerturbation(uint64_t seed, unsigned int n, unsigned int rounds=8)
Construct a permutation of [0, n) keyed by seed.
const uint32_t _k0
Lower 32 bits of the seed, used as the first subkey in the round function.
const unsigned int _n
Size of the permutation domain [0, n)
uint32_t invert(uint32_t y) const
Recover the original index from a permuted value, i.e.
const uint32_t _k1
Upper 32 bits of the seed, used as the second subkey in the round function.
const unsigned int _half_bits
Number of bits in each Feistel half-block: ceil((ceil(log2(n)) + 1) / 2)
const unsigned int _rounds
Number of Feistel rounds to apply per permute/invert call.
static uint32_t mix32(uint32_t x)
Bijective 32-bit avalanche hash (finalizer from Murmur3 / degski hash).
static unsigned int ceilLog2(uint32_t n)
Return the number of bits needed to represent values in [0, n-1], i.e.
const uint32_t _half_mask
Bitmask of width _half_bits, used to keep half-block arithmetic in range.
uint32_t permute(uint32_t x) const
Map x to its permuted index in [0, n).
uint32_t permutePadded(uint32_t x) const
Apply one full pass of the balanced Feistel network over the padded domain [0, 2^(2*half_bits)).
uint32_t roundFunction(uint32_t half, unsigned int round) const
Keyed round function F(half, round) used in each Feistel step.
uint32_t invertPadded(uint32_t y) const
Invert one full pass of the Feistel network by running rounds in reverse.