https://mooseframework.inl.gov
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 
12 MooseRandomPerturbation::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 
24 uint32_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 
38 uint32_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 
52 uint32_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 
72 uint32_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 
91 uint32_t
92 MooseRandomPerturbation::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 
102 unsigned 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 
117 uint32_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.
static uint32_t mix32(uint32_t x)
Bijective 32-bit avalanche hash (finalizer from Murmur3 / degski hash).
const uint32_t _k0
Lower 32 bits of the seed, used as the first subkey in the round function.
uint32_t permute(uint32_t x) const
Map x to its permuted index in [0, n).
const uint32_t _k1
Upper 32 bits of the seed, used as the second subkey in the round function.
T round(T x)
Definition: MathUtils.h:77
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 invert(uint32_t y) const
Recover the original index from a permuted value, i.e.
const uint32_t _half_mask
Bitmask of width _half_bits, used to keep half-block arithmetic in range.
const unsigned int _half_bits
Number of bits in each Feistel half-block: ceil((ceil(log2(n)) + 1) / 2)
uint32_t roundFunction(uint32_t half, unsigned int round) const
Keyed round function F(half, round) used in each Feistel step.
const unsigned int _rounds
Number of Feistel rounds to apply per permute/invert call.
uint32_t invertPadded(uint32_t y) const
Invert one full pass of the Feistel network by running rounds in reverse.
static unsigned int ceilLog2(uint32_t n)
Return the number of bits needed to represent values in [0, n-1], i.e.
const unsigned int _n
Size of the permutation domain [0, n)