<html>
<head>
  <title>Further Issues with Random Number Generators in the Library TR Proposal</title>
  <meta Author="Jens Maurer" content="proposal">
</head>

<body bgcolor="#FFFFFF" text="#000000">

<font size=-1>
Jens Maurer &lt;Jens.Maurer@gmx.net&gt;
<br>
2004-02-14
<br>
Document N1609 = 04-0049
<p>
<code>$Id: pre-sydney-paper.html,v 1.4 2004/02/14 00:12:15 jmaurer Exp $</code>
</font>

<h1>More on Issues with Random Number Generators in the Library TR Proposal</h1>

<h2>Issue 6 of N1535: Should Random Number Initializers Take Iterators by Reference or by Value?</h2>

(See also the thread started with Pete Becker's message
c++std-lib-10785.)
<p>
The concern is that section 5.1.1, table 5.2 (Pseudo-random number
engine requirements), specifies that engines can be constructed and
seeded using an iterator range [it1, it2) of unsigned integral
values.  It appears surprising to the user that, unlike any other
function or class in the standard library, the iterators are not both
passed by value, but it1 is passed by reference, and is modified
during the construction or seeding.
<p>
Any solution has to satisfy the following requirements (see also
section III.E of N1452):
<ul>
<li>Engine constructors and seeding are visible and meant to be used
by users.
<li>Engines may be compounded of other engines; the compounding engine
must be able to initialize its compounds.
<li>Engines may have a large state (up to several KB) that should not
be initialized twice for efficiency reasons.
</ul>

There are two solutions to remedy this problem.  The first keeps the
iterator range, but passes the iterators by value.  In order to avoid
initializing the (potentially large) state of the engine twice, this
requires that engines have a "construct, but don't seed" special
constructor overload, similar to the "nothrow_t" overload of
<code>operator new</code>.
<p>
The second avoids iterator ranges altogether, and instead passes a
generator (i.e. zero-argument function object) by reference.  There is
a chance of ambiguous single-argument constructor and seeding
overloads here, because most engines can be initialized with an "int"
seed as well, but library implementors already have acquired a means
to deal with the situation for the similar case of two-argument
<code>std::vector</code> constructors.  The advantage of passing a
generator by reference is that the user can easily decide the
behaviour on "end-of-sequence" to be "throw an exception" or "warp
around", thereby reducing the complexity of the requirements
specifications of the random number library.  As outlined in N1452,
section III.E, it is also easier to make a generator out of an
iterator compared to the reverse, because a generator has less
requirements.
<p>
After this discussion, I propose to move to a generator-based
approach.  (Note: The pre-TR random number library in Boost used this
approach, but failed to fix the "overload" problem, so the iterator
range approach was tried in the TR proposal - and failed due to
reasonable design concerns.)
<p>
<b>Proposed resolution</b>
<p>
In section 5.1.1 [tr.rand.req], replace in the paragraph before table 5.2
<blockquote>
... <code>it1</code> is an lvalue and <code>it2</code> is a (possibly
const) value of an input iterator type <code>It</code> having an unsigned
integral value type, ...
</blockquote>

by

<blockquote>
... <code>g</code> is an lvalue of a zero-argument function object
returning values of unsigned integral type, ...
</blockquote>

In the same section, replace in table 5.2 the table row for
<code>X(it1, it2)</code> by
<blockquote>
expression: <code>X(g)</code> 
<p>
return type: (none)
<p>
pre/post-condition: creates an engine with the initial internal state
given by the results of successive invocations of <code>g</code>.
Throws what and when <code>g</code> throws.
<p>
complexity: O(size of state)
</blockquote>

In the same section, replace in table 5.2 the table row for
<code>u.seed(it1, it2)</code> by
<blockquote>
expression: <code>u.seed(g)</code>
<p>
return type: void
<p>
pre/post-conditions: sets the internal state of <code>u</code> so that
<code>u == X(g)</code>.  If an invocation of <code>g</code> throws,
that exception is rethrown, and further use of <code>u</code> (except
destruction) is undefined until a <code>seed</code> member function
has been executed without throwing an exception.
<p>
complexity: same as <code>X(g)</code>
</blockquote>

After table 5.2, add a new paragraph following the one starting
"Additional Requirements":
<blockquote>
For every pseudo-random number engine defined in this clause:
<ul>
<li>the constructor
<pre>template&lt;class Gen> X(Gen& g)
</pre>
shall have the same effect as
<pre>X(static_cast&lt;Gen&gt;(g))
</pre>
if <code>Gen</code> is a fundamental type.
<p>
<li>
The member function of the form
<pre>template&lt;class Gen> void seed(Gen& g)
</pre>
shall have the same effect as
<pre>X(static_cast&lt;Gen&gt;(g))
</pre>
if <code>Gen</code> is a fundamental type.
</ul>
[Note: The casts make <code>g</code> an rvalue, unsuitable for binding
to a reference.]
</blockquote>

<p>
[Note to editor: The following changes intend to morph "dereferencing
*first" to "invoking g" only.  However, complete text has been
given.]
<p>

In section 5.1.4.1 [tr.rand.eng.lcong], replace the constructor
<code>template&lt;class In&gt; linear_congruential(In&amp; first, In
last)</code>
by
<blockquote>
<pre>template&lt;class Gen&gt; linear_congruental(Gen& g)</pre>
<strong>Effects:</strong> If <code>c</code> mod <code>m</code> = 0 and
<code>g()</code> mod <code>m</code> = 0, sets the state x(i) of the
engine to 1 mod <code>m</code>, else sets the state x(i) of the engine
to <code>g()</code> mod <code>m</code>.<br>
<br>
<strong>Complexity:</strong> Exactly one invocation of <code>g</code>.
</blockquote>
<p>
Furthermore, adjust the class synopsis accordingly.

<p>
In section 5.1.4.2 [tr.rand.eng.mers], replace the description of the
constructor <code>template&lt;class In&gt; mersenne_twister(In&amp;
first, In last)</code>
by
<blockquote>
<pre>template&lt;class Gen&gt; mersenne_twister(Gen& g)</pre>
<strong>Effects:</strong> Given the values z[0] ... z[n-1] obtained by
successive invocations of <code>g</code>, sets x(-n) ... x(-1) to z[0]
mod 2<sup>w</sup> ... z[n-1] mod 2<sup>w</sup>.
<br>
<strong>Complexity:</strong> Exactly <code>n</code> invocations of
<code>g</code>.
</blockquote>
Furthermore, remove the description of the <code>seed(first,
last)</code> function, it is subsumed by table 5.2 and the description
of the constructor, and adjust the class synopsis accordingly.

<p>
In section 5.1.4.3 [tr.rand.eng.sub], replace the description of the
constructor <code>template&lt;class In&gt; subtract_with_carry(In&amp;
first, In last)</code>
by
<blockquote>
<pre>template&lt;class Gen&gt; subtract_with_carry(Gen& g)</pre>
<strong>Effects:</strong> With n=(w+31)/32 (rounded downward) and given the
values z[0] ... z[n*r-1] obtained by successive invocations of
<code>g</code>, sets x(-r) ... x(-1) to
(z<sub>0</sub> * 2<sup>32</sup> + ... + z<sub>n-1</sub> *
2<sup>32*(n-1)</sup>) mod m ... (z<sub>(r-1)*n</sub> * 2<sup>32</sup>
+ ... + z<sub>r-1</sub> * 2<sup>32*(n-1)</sup>) mod m.  If x(-1) == 0,
sets carry(-1) = 1, else sets carry(-1) = 0.
<br>
<strong>Complexity:</strong> Exactly <code>r*n</code> invocations of
<code>g</code>.
</blockquote>

Furthermore, remove the description of the <code>seed(first,
last)</code> function, it is subsumed by table 5.2 and the description
of the constructor, and adjust the class synopsis accordingly.

<p>
In section 5.1.4.4 [tr.rand.eng.sub1], replace the description of the
constructor <code>template&lt;class In&gt; subtract_with_carry_01(In&amp;
first, In last)</code>
by
<blockquote>
<pre>template&lt;class Gen&gt; subtract_with_carry_01(Gen& g)</pre>
<strong>Effects:</strong> With n=(w+31)/32 (rounded downward) and given
the values z<sub>0</sub> ... z<sub>n*r-1</sub> obtained by
successive invocations of <code>g</code>, sets x(-r) ... x(-1) to
(z<sub>0</sub> * 2<sup>32</sup> + ... + z<sub>n-1</sub> *
2<sup>32*(n-1)</sup>) * 2<sup>-w</sup> mod 1 ... (z<sub>(r-1)*n</sub>
* 2<sup>32</sup> + ... + z<sub>r-1</sub> * 2<sup>32*(n-1)</sup>) *
2<sup>-w</sup> mod 1.  If x(-1) == 0, sets carry(-1) = 2<sup>-w</sup>,
else sets carry(-1) = 0.
<br>
<strong>Complexity:</strong> Exactly <code>r*n</code> invocations of
<code>g</code>.
</blockquote>

Furthermore, remove the description of the <code>seed(first,
last)</code> function, it is subsumed by table 5.2 and the description
of the constructor, and adjust the class synopsis accordingly.

<p>
In section 5.1.4.5 [tr.rand.eng.disc], replace the description of the
constructor  <code>template&lt;class In&gt; discard_block(In&amp;
first, In last)</code>
by
<blockquote>
<pre>template&lt;class Gen&gt; discard_block(Gen& g)</pre>
<strong>Effects:</strong> Constructs a <code>discard_block</code>
engine.  To construct the subobject <em>b</em>, invokes the
<code>b(g)</code> constructor.  Sets <code>n = 0</code>.
</blockquote>

Furthermore, remove the description of the <code>seed(first,
last)</code> function, it is subsumed by table 5.2 and the description
of the constructor, and adjust the class synopsis accordingly.

<p>
In section 5.1.4.6 [tr.rand.eng.xor], replace the description of the
constructor  <code>template&lt;class In&gt; xor_combine(In&amp;
first, In last)</code>
by
<blockquote>
<pre>template&lt;class Gen&gt; xor_combine(Gen& g)</pre>
<strong>Effects:</strong> Constructs a <code>xor_combine</code>
engine.  To construct the subobject <em>b1</em>, invokes the
<code>b1(g)</code> constructor.  Then, to construct the subobject
<em>b2</em>, invokes the <code>b2(g)</code> constructor.
</blockquote>

Furthermore, remove the description of the <code>seed(first,
last)</code> function, it is subsumed by table 5.2 and the description
of the constructor, and adjust the class synopsis accordingly.

</blockquote>


<h2>Issue 7 of N1535: Global comparison operators overspecified</h2>

The concern is that section 5.1.1, table 5.2 (Pseudo-random number engine
requirements) specifies that each of the following must be valid
expressions:
<pre>x == y
x != y
</pre>
Redundantly, each of the engines is specified to have global
operators for each of these operations.  This restricts the
implementation choices of the library implementor, for no good
reason.
<p>
The following wording change removes the overspecification.
<p>
<b>Proposed resolution</b>
<p>
In section 5.1.1 [tr.rand.req], table 5.2, replace in the
pre-/post-condition column for x == y
<blockquote>
== is an equivalence relation.  The current state x(i) of x is equal
to the current state y(j) of y.
</blockquote>
by
<blockquote>
== is an equivalence relation.  Given the current state
<code>x(i)</code> of <code>x</code> and the current state
<code>y(j)</code> of <code>y</code>, returns <code>true</code> if
<code>x(i+k)</code> is equal to <code>y(j+k)</code> for all integer
<code>k</code> &gt;= 0, <code>false</code> otherwise.
</blockquote>

In section 5.1.4.1 [tr.rand.eng.lcong], remove the prototypes for
operator== and operator!= from the synopsis.
<p>
In section 5.1.4.2 [tr.rand.eng.mers], remove the prototypes for
operator== and operator!= from the synopsis.
<p>
In section 5.1.4.3 [tr.rand.eng.sub], remove the prototypes for
operator== and operator!= from the synopsis.
<p>
In section 5.1.4.4 [tr.rand.eng.sub1], remove the prototypes for
operator== and operator!= from the synopsis.
<p>
In section 5.1.4.5 [tr.rand.eng.disc], remove the prototypes for
operator== and operator!= from the synopsis.
<p>
In section 5.1.4.6 [tr.rand.eng.xor], remove the prototypes for
operator== and operator!= from the synopsis.


<h2>Issue 23 of N1535: Streaming underspecified</h2>

Of concern are the following operators:
<pre>os &lt;&lt; x
is >> x
</pre>

The concern here is twofold: First, similar to issue 7 of N1535 (see
above), the streaming operators are described in section 5.1.1, table
5.2 (Pseudo-random number engine requirements), and each engine has a
specific declaration, which restricts implementation choices.  Second,
after discussion on the core reflector, the consensus was that it is
desirable to have a portable external representation of the engine
state.  This can be done if a sequence of unsigned longs is
written/read, where the representation of each unsigned long requires
at most 32 bits.
<p>
Mixing streaming with seeding does not appear advisable, because
seeding may have employ one-way hash functions that interfere with the
goal of streaming, namely to completely restore the state.

<p>
<b>Proposed resolution</b>
<p>
After table 5.2, add a new paragraph following the one starting
"Additional Requirements":
<blockquote>
If a textual representation was written by <code>os &lt;&lt; x</code>
and that representation was read by <code>is >> v</code>, then <code>x
== v</code>, provided that no intervening invocations of
<code>x</code> or <code>v</code> have occurred.
</blockquote>

In section 5.1.4.1 [tr.rand.eng.lcong], remove the prototypes for
operator&lt;&lt; and operator>> from the synopsis.  Also, remove the
description of operator&lt;&lt;.  Add after "The size of the state
x(i) is 1.":
<blockquote>
The textual representation is the value of <code>x(i)</code>.
</blockquote>

<p>
In section 5.1.4.2 [tr.rand.eng.mers], remove the prototypes for
operator&lt;&lt; and operator>> from the synopsis.  Also, remove the
description of operator&lt;&lt;.  Add after "The size of the state
x(i) is n.":
<blockquote>
The textual representation is the values of x(i-n), ..., x(i-1), in
that order.
</blockquote>
<p>
In section 5.1.4.3 [tr.rand.eng.sub], remove the prototypes for
operator&lt;&lt; and operator>> from the synopsis.  Also, remove the
description of operator&lt;&lt;.   Add after "The size of the state is
r.":
<blockquote>
The textual representation is the values of x(i-r), ..., x(i-1),
carry(i-1), in that order.
</blockquote>
<p>
In section 5.1.4.4 [tr.rand.eng.sub1], remove the prototypes for
operator&lt;&lt; and operator>> from the synopsis.  Also, remove the
description of operator&lt;&lt;.  Add after "The size of the state is
r.":
<blockquote>
With n = (w+31)/32 (rounded downward) and integer numbers z[k,j] such
that x(i-k)*2<sup>w</sup> = z[k,0] + z[k,1] * 2<sup>32</sup> +
z[k,n-1] * 2<sup>32(n-1)</sup>, the textual representation is
the values of z[r,0], ... z[r,n-1], ... z[1,0], ... z[1,n-1],
carry(i-1)*2<sup>w</sup>, in that order.
[Note: The algorithm ensures that only integer numbers representable
in 32 bits are written.]

</blockquote>
<p>
In section 5.1.4.5 [tr.rand.eng.disc], remove the prototypes for
operator&lt;&lt; and operator>> from the synopsis.  Also, remove the
description of operator&lt;&lt;.  Add after "The size of the state is
the size of b plus 1.":
<blockquote>
The textual representation is the textual representation of <em>b</em>
followed by the value of <code>n</code>.
</blockquote>

<p>
In section 5.1.4.6 [tr.rand.eng.xor], remove the prototypes for
operator&lt;&lt; and operator>> from the synopsis.  Also, remove the
description of operator&lt;&lt;.  Add after "The size of the state is
the size of the state of b1 plus the size of the state of b2.":
<blockquote>
The textual representation is the textual representation of
<em>b1</em> followed by the textual representation of <em>b2</em>.
</blockquote>


<h2>New Issue J17</h2>

Section 5.1.1 [tr.rand.req], table 5.2, specifies that the streaming
operators take <code>std::ostream</code> and
<code>std::istream</code>.  This does not take wide streams nor the
template nature of streams into account.

<p>
<b>Suggested resolution</b>
<p>
Replace <code>std::ostream</code> and <code>std::istream</code> by
appropriate templates or template instantiations, or decide that
writing/reading state to/from narrow streams is sufficient.


<h2>Acknowledgements</h2>

Thanks to Pete Becker for preparing N1535 and raising some of the
issues on the library reflector.
</body>
</html>