Skip to content

Commit e12cbde

Browse files
authored
Merge 2024-06 LWG Motion 10
P2075R6 Philox as an extension of the C++ RNG engines
2 parents 3de9b1c + e2565b6 commit e12cbde

File tree

4 files changed

+274
-0
lines changed

4 files changed

+274
-0
lines changed

source/macros.tex

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -546,6 +546,9 @@
546546
\newcommand{\cv}{\ifmmode\mathit{cv}\else\cvqual{cv}\fi}
547547
\newcommand{\numconst}[1]{\textsl{#1}}
548548
\newcommand{\logop}[1]{\textsc{#1}}
549+
\DeclareMathOperator{\mullo}{mullo}
550+
\DeclareMathOperator{\mulhi}{mulhi}
551+
\newcommand{\cedef}{\mathrel{\mathop:}=} % "colon-equals definition"
549552

550553
%%--------------------------------------------------
551554
%% Environments for code listings.

source/numerics.tex

Lines changed: 269 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1409,6 +1409,10 @@
14091409
template<class Engine, size_t k>
14101410
class shuffle_order_engine;
14111411

1412+
// \ref{rand.eng.philox}, class template \tcode{philox_engine}
1413+
template<class UIntType, size_t w, size_t n, size_t r, UIntType... consts>
1414+
class philox_engine;
1415+
14121416
// \ref{rand.predef}, engines and engine adaptors with predefined parameters
14131417
using minstd_rand0 = @\seebelow@;
14141418
using minstd_rand = @\seebelow@;
@@ -1419,6 +1423,8 @@
14191423
using ranlux24 = @\seebelow@;
14201424
using ranlux48 = @\seebelow@;
14211425
using knuth_b = @\seebelow@;
1426+
using philox4x32 = @\seebelow@;
1427+
using philox4x64 = @\seebelow@;
14221428

14231429
using default_random_engine = @\seebelow@;
14241430

@@ -3061,6 +3067,239 @@
30613067
otherwise sets $c$ to $0$.
30623068
\end{itemdescr}
30633069

3070+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3071+
% philox_engine engine:
3072+
3073+
\rSec3[rand.eng.philox]{Class template \tcode{philox_engine}}%
3074+
\indexlibraryglobal{philox_engine}%
3075+
3076+
\pnum
3077+
A \tcode{philox_engine} random number engine produces
3078+
unsigned integer random numbers in the closed interval \crange{0}{$m$},
3079+
where $m = 2^w - 1$ and
3080+
the template parameter $w$ defines the range of the produced numbers.
3081+
The state of a \tcode{philox_engine} object consists of
3082+
a sequence $X$ of $n$ unsigned integer values of width $w$,
3083+
a sequence $K$ of $n/2$ values of \tcode{result_type},
3084+
a sequence $Y$ of $n$ values of \tcode{result_type}, and
3085+
a scalar $i$, where
3086+
\begin{itemize}
3087+
\item
3088+
$X$ is the interpretation of the unsigned integer \term{counter} value
3089+
$Z \cedef \sum_{j = 0}^{n - 1} X_j \cdot 2^{wj}$ of $n \cdot w$ bits,
3090+
\item
3091+
$K$ are keys, which are generated once from the seed (see constructors below)
3092+
and remain constant unless the \tcode{seed} function\iref{rand.req.eng} is invoked,
3093+
\item
3094+
$Y$ stores a batch of output values, and
3095+
\item
3096+
$i$ is an index for an element of the sequence $Y$.
3097+
\end{itemize}
3098+
3099+
\pnum
3100+
The generation algorithm returns $Y_i$,
3101+
the value stored in the $i^{th}$ element of $Y$ after applying
3102+
the transition algorithm.
3103+
3104+
\pnum
3105+
The state transition is performed as if by the following algorithm:
3106+
\begin{codeblock}
3107+
@$i$@ = @$i$@ + 1
3108+
if (@$i$@ == @$n$@) {
3109+
@$Y$@ = Philox(@$K$@, @$X$@) // \seebelow
3110+
@$Z$@ = @$Z$@ + 1
3111+
@$i$@ = 0
3112+
}
3113+
\end{codeblock}
3114+
3115+
\pnum
3116+
The \tcode{Philox} function maps the length-$n/2$ sequence $K$ and
3117+
the length-$n$ sequence $X$ into a length-$n$ output sequence $Y$.
3118+
Philox applies an $r$-round substitution-permutation network to the values in $X$.
3119+
A single round of the generation algorithm performs the following steps:
3120+
\begin{itemize}
3121+
\item
3122+
The output sequence $X'$ of the previous round
3123+
($X$ in case of the first round)
3124+
is permuted to obtain the intermediate state $V$:
3125+
\begin{codeblock}
3126+
@$V_j = X'_{f_n(j)}$@
3127+
\end{codeblock}
3128+
where $j = 0, \dotsc, n - 1$ and
3129+
$f_n(j)$ is defined in \tref{rand.eng.philox.f}.
3130+
3131+
\begin{floattable}{Values for the word permutation $\bm{f}_{\bm{n}}\bm{(j)}$}{rand.eng.philox.f}
3132+
{l|l|l|l|l|l|l|l|l|l|l|l|l|l|l|l|l|l}
3133+
\topline
3134+
\multicolumn{2}{|c|}{$\bm{f}_{\bm{n}}\bm{(j)}$} & \multicolumn{16}{c|}{$\bm{j}$} \\ \cline{3-18}
3135+
\multicolumn{2}{|c|}{}
3136+
& 0 & 1 & 2 & 3 & 4 & 5 & 6 & 7 & 8 & 9 & 10 & 11 & 12 & 13 & 14 & 15 \\ \hline
3137+
$\bm{n} $ & 2 & 0 & 1 & \multicolumn{14}{c|}{} \\ \cline{2-18}
3138+
& 4 & 0 & 3 & 2 & 1 & \multicolumn{12}{c|}{} \\ \cline{2-18}
3139+
& 8 & 2 & 1 & 4 & 7 & 6 & 5 & 0 & 3 & \multicolumn{8}{c|}{} \\ \cline{2-18}
3140+
& 16 & 0 & 9 & 2 & 13 & 6 & 11 & 4 & 15 & 10 & 7 & 12 & 3 & 14 & 5 & 8 & 1 \\ \cline{2-18}
3141+
\end{floattable}
3142+
\begin{note}
3143+
For $n = 2$ the sequence is not permuted.
3144+
\end{note}
3145+
3146+
\item
3147+
The following computations are applied to the elements of the $V$ sequence:
3148+
\begin{codeblock}
3149+
@$X_{2k + 0} = \mullo(V_{2k + 1}, M_{k}, w)$@
3150+
@$X_{2k + 1} = \mulhi(V_{2k + 1}, M_{k}, w) \xor \mathit{key}^q_k \xor V_{2k}$@
3151+
\end{codeblock}
3152+
where:
3153+
\begin{itemize}
3154+
\item
3155+
$\mullo(\tcode{a}, \tcode{b}, \tcode{w})$ is
3156+
the low half of the modular multiplication of \tcode{a} and \tcode{b}:
3157+
$(\tcode{a} \cdot \tcode{b}) \mod 2^w$,
3158+
3159+
\item
3160+
$\mulhi(\tcode{a}, \tcode{b}, \tcode{w})$ is
3161+
the high half of the modular multiplication of \tcode{a} and \tcode{b}:
3162+
$(\left\lfloor (\tcode{a} \cdot \tcode{b}) / 2^w \right\rfloor)$,
3163+
3164+
\item
3165+
$k = 0, \dotsc, n/2 - 1$ is the index in the sequences,
3166+
3167+
\item
3168+
$q = 0, \dotsc, r - 1$ is the index of the round,
3169+
3170+
\item
3171+
$\mathit{key}^q_k$ is the $k^\text{th}$ round key for round $q$,
3172+
$\mathit{key}^q_k \cedef (K_k + q \cdot C_k) \mod 2^w$,
3173+
3174+
\item
3175+
$K_k$ are the elements of the key sequence $K$,
3176+
3177+
\item
3178+
$M_k$ is \tcode{multipliers[$k$]}, and
3179+
3180+
\item
3181+
$C_k$ is \tcode{round_consts[$k$]}.
3182+
\end{itemize}
3183+
\end{itemize}
3184+
3185+
\pnum
3186+
After $r$ applications of the single-round function,
3187+
\tcode{Philox} returns the sequence $Y = X'$.
3188+
3189+
\indexlibraryglobal{philox_engine}%
3190+
\indexlibrarymember{result_type}{philox_engine}%
3191+
\begin{codeblock}
3192+
namespace std {
3193+
template<class UIntType, size_t w, size_t n, size_t r, UIntType... consts>
3194+
class philox_engine {
3195+
static constexpr size_t @\exposid{array-size}@ = n / 2; // \expos
3196+
public:
3197+
// types
3198+
using result_type = UIntType;
3199+
3200+
// engine characteristics
3201+
static constexpr size_t word_size = w;
3202+
static constexpr size_t word_count = n;
3203+
static constexpr size_t round_count = r;
3204+
static constexpr array<result_type, @\exposid{array-size}@> multipliers;
3205+
static constexpr array<result_type, @\exposid{array-size>}@ round_consts;
3206+
static constexpr result_type min() { return 0; }
3207+
static constexpr result_type max() { return m - 1; }
3208+
static constexpr result_type default_seed = 20111115u;
3209+
3210+
// constructors and seeding functions
3211+
philox_engine() : philox_engine(default_seed) {}
3212+
explicit philox_engine(result_type value);
3213+
template<class Sseq> explicit philox_engine(Sseq& q);
3214+
void seed(result_type value = default_seed);
3215+
template<class Sseq> void seed(Sseq& q);
3216+
3217+
void set_counter(const array<result_type, n>& counter);
3218+
3219+
// equality operators
3220+
friend bool operator==(const philox_engine& x, const philox_engine& y);
3221+
3222+
// generating functions
3223+
result_type operator()();
3224+
void discard(unsigned long long z);
3225+
3226+
// inserters and extractors
3227+
template<class charT, class traits>
3228+
friend basic_ostream<charT, traits>&
3229+
operator<<(basic_ostream<charT, traits>& os, const philox_engine& x);
3230+
template<class charT, class traits>
3231+
friend basic_istream<charT, traits>&
3232+
operator>>(basic_istream<charT, traits>& is, philox_engine& x);
3233+
};
3234+
}
3235+
\end{codeblock}
3236+
3237+
\pnum
3238+
\mandates
3239+
\begin{itemize}
3240+
\item \tcode{sizeof...(consts) == n} is \tcode{true}, and
3241+
\item \tcode{n == 2 || n == 4 || n == 8 || n == 16} is \tcode{true}, and
3242+
\item \tcode{0 < r} is \tcode{true}, and
3243+
\item \tcode{0 < w \&\& w <= numeric_limits<UIntType>::digits} is \tcode{true}.
3244+
\end{itemize}
3245+
3246+
\pnum
3247+
The template parameter pack \tcode{consts} represents
3248+
the $M_k$ and $C_k$ constants which are grouped as follows:
3249+
$[ M_0, C_0, M_1, C_1, M_2, C_2, \dotsc, M_{n/2 - 1}, C_{n/2 - 1} ]$.
3250+
3251+
\pnum
3252+
The textual representation consists of the values of
3253+
$K_0, \dotsc, K_{n/2 - 1}, X_{0}, \dotsc, X_{n - 1}, i$, in that order.
3254+
\begin{note}
3255+
The stream extraction operator can reconstruct $Y$ from $K$ and $X$, as needed.
3256+
\end{note}
3257+
3258+
\indexlibraryctor{philox_engine}
3259+
\begin{itemdecl}
3260+
explicit philox_engine(result_type value);
3261+
\end{itemdecl}
3262+
3263+
\begin{itemdescr}
3264+
\pnum
3265+
\effects
3266+
Sets the $K_0$ element of sequence $K$ to $\tcode{value} \mod 2^w$.
3267+
All elements of sequences $X$ and $K$ (except $K_0$) are set to \tcode{0}.
3268+
The value of $i$ is set to $n - 1$.
3269+
\end{itemdescr}
3270+
3271+
\indexlibraryctor{philox_engine}
3272+
\begin{itemdecl}
3273+
template<class Sseq> explicit philox_engine(Sseq& q);
3274+
\end{itemdecl}
3275+
3276+
\begin{itemdescr}
3277+
\pnum
3278+
\effects
3279+
With $p = \left\lceil w / 32 \right\rceil$ and
3280+
an array (or equivalent) \tcode{a} of length $(n/2) \cdot p$,
3281+
invokes \tcode{q.generate(a + 0, a + n / 2 * $p$)} and
3282+
then iteratively for $k = 0, \dotsc, n/2 - 1$,
3283+
sets $K_k$ to
3284+
$\left(\sum_{j = 0}^{p - 1} a_{k p + j} \cdot 2^{32j} \right) \mod 2^w$.
3285+
All elements of sequence $X$ are set to \tcode{0}.
3286+
The value of $i$ is set to $n - 1$.
3287+
\end{itemdescr}
3288+
3289+
\indexlibrarymember{set_counter}{philox_engine}%
3290+
\begin{itemdecl}
3291+
void set_counter(const array<result_type, n>& c);
3292+
\end{itemdecl}
3293+
3294+
\begin{itemdescr}
3295+
\pnum
3296+
\effects
3297+
For $j = 0, \dotsc, n - 1$ sets $X_j$ to $C_{n - 1 - j} \mod 2^w$.
3298+
The value of $i$ is set to $n - 1$.
3299+
\begin{note}
3300+
The counter is the value $Z$ introduced at the beginning of this subclause.
3301+
\end{note}
3302+
\end{itemdescr}
30643303

30653304
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
30663305
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -3662,6 +3901,36 @@
36623901
need not generate identical sequences across implementations.
36633902
\end{note}
36643903
\end{itemdescr}%
3904+
3905+
\indexlibraryglobal{philox4x32}%
3906+
\begin{itemdecl}
3907+
using philox4x32 =
3908+
philox_engine<uint_fast32_t, 32, 4, 10,
3909+
0xD2511F53, 0x9E3779B9, 0xCD9E8D57, 0xBB67AE85>;
3910+
\end{itemdecl}
3911+
3912+
\begin{itemdescr}
3913+
\pnum
3914+
\required
3915+
The $10000^\text{th}$ consecutive invocation
3916+
a default-constructed object of type \tcode{philox4x32}
3917+
produces the value $1955073260$.
3918+
\end{itemdescr}%
3919+
3920+
\indexlibraryglobal{philox4x64}%
3921+
\begin{itemdecl}
3922+
using philox4x64 =
3923+
philox_engine<uint_fast64_t, 64, 4, 10,
3924+
0xD2E7470EE14C6C93, 0x9E3779B97F4A7C15, 0xCA5A826395121157, 0xBB67AE8584CAA73B>;
3925+
\end{itemdecl}
3926+
3927+
\begin{itemdescr}
3928+
\pnum
3929+
\required
3930+
The $10000^\text{th}$ consecutive invocation
3931+
a default-constructed object of type \tcode{philox4x64}
3932+
produces the value $3409172418970261260$.
3933+
\end{itemdescr}%
36653934
\indextext{random number generation!predefined engines and adaptors|)}%
36663935
\indextext{random number engine adaptor!with predefined parameters|)}%
36673936
\indextext{random number engine!with predefined parameters|)}

source/std.tex

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
\usepackage{color} % define colors for strikeouts and underlines
2525
\usepackage{amsmath} % additional math symbols
2626
\usepackage{mathrsfs} % mathscr font
27+
\usepackage{bm}
2728
\usepackage[final]{microtype}
2829
\usepackage[splitindex,original]{imakeidx}
2930
\usepackage{multicol}

source/support.tex

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -731,6 +731,7 @@
731731
#define @\defnlibxname{cpp_lib_optional_range_support}@ 202406L // freestanding, also in \libheader{optional}
732732
#define @\defnlibxname{cpp_lib_out_ptr}@ 202311L // freestanding, also in \libheader{memory}
733733
#define @\defnlibxname{cpp_lib_parallel_algorithm}@ 201603L // also in \libheader{algorithm}, \libheader{numeric}
734+
#define @\defnlibxname{cpp_lib_philox_engine}@ 202406L // also in \libheader{random}
734735
#define @\defnlibxname{cpp_lib_polymorphic_allocator}@ 201902L // also in \libheader{memory_resource}
735736
#define @\defnlibxname{cpp_lib_print}@ 202406L // also in \libheader{print}, \libheader{ostream}
736737
#define @\defnlibxname{cpp_lib_quoted_string_io}@ 201304L // also in \libheader{iomanip}

0 commit comments

Comments
 (0)