Skip to content

Commit f6256f1

Browse files
burblebeetkoeppe
authored andcommitted
P2075R6 Philox as an extension of the C++ RNG engines
Editorial notes (all in [rand.eng.philox]): * Omit colon before "long sentence" list in p1. * Use ":=" to denote definitions (of $Z$ and $key^q_k$).
1 parent 3de9b1c commit f6256f1

File tree

3 files changed

+281
-0
lines changed

3 files changed

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

30653312
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
30663313
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -3662,6 +3909,36 @@
36623909
need not generate identical sequences across implementations.
36633910
\end{note}
36643911
\end{itemdescr}%
3912+
3913+
\indexlibraryglobal{philox4x32}%
3914+
\begin{itemdecl}
3915+
using philox4x32 =
3916+
philox_engine<uint_fast32_t, 32, 4, 10,
3917+
0xD2511F53, 0x9E3779B9, 0xCD9E8D57, 0xBB67AE85>;
3918+
\end{itemdecl}
3919+
3920+
\begin{itemdescr}
3921+
\pnum
3922+
\required
3923+
The $10000^\text{th}$ consecutive invocation
3924+
a default-constructed object of type \tcode{philox4x32}
3925+
produces the value $1955073260$.
3926+
\end{itemdescr}%
3927+
3928+
\indexlibraryglobal{philox4x64}%
3929+
\begin{itemdecl}
3930+
using philox4x64 =
3931+
philox_engine<uint_fast64_t, 64, 4, 10,
3932+
0xD2E7470EE14C6C93, 0x9E3779B97F4A7C15, 0xCA5A826395121157, 0xBB67AE8584CAA73B>;
3933+
\end{itemdecl}
3934+
3935+
\begin{itemdescr}
3936+
\pnum
3937+
\required
3938+
The $10000^\text{th}$ consecutive invocation
3939+
a default-constructed object of type \tcode{philox4x64}
3940+
produces the value $3409172418970261260$.
3941+
\end{itemdescr}%
36653942
\indextext{random number generation!predefined engines and adaptors|)}%
36663943
\indextext{random number engine adaptor!with predefined parameters|)}%
36673944
\indextext{random number engine!with predefined parameters|)}

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)