Skip to content

P1068R11 Vector API for random number generation #6904

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Apr 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
133 changes: 133 additions & 0 deletions source/algorithms.tex
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
\ref{alg.sorting} & Sorting and related operations & \\ \rowsep
\ref{numeric.ops} & Generalized numeric operations & \tcode{<numeric>} \\ \rowsep
\ref{specialized.algorithms} & Specialized \tcode{<memory>} algorithms & \tcode{<memory>} \\ \rowsep
\ref{alg.rand} & Specialized \tcode{<random>} algorithms & \tcode{<random>} \\ \rowsep
\ref{alg.c.library} & C library algorithms & \tcode{<cstdlib>} \\
\end{libsumtab}

Expand Down Expand Up @@ -11667,6 +11668,138 @@
\end{codeblock}
\end{itemdescr}

\rSec1[alg.rand]{Specialized \tcode{<random>} algorithms}

\rSec2[alg.rand.general]{General}

\pnum
The contents specified in \ref{alg.rand}
are declared in the header \libheaderrefx{random}{rand.synopsis}.

\rSec2[alg.rand.generate]{\tcode{generate_random}}

\begin{itemdecl}
template<class R, class G>
requires @\libconcept{output_range}@<R, invoke_result_t<G&>> && @\libconcept{uniform_random_bit_generator}@<remove_cvref_t<G>>
constexpr borrowed_iterator_t<R> ranges::generate_random(R&& r, G&& g);
\end{itemdecl}

\begin{itemdescr}
\pnum
\effects
\begin{itemize}
\item
Calls \tcode{g.generate_random(std::forward<R>(r))}
if this expression is well-formed.
\item
Otherwise, if \tcode{R} models \tcode{sized_range},
fills \tcode{r} with \tcode{ranges::size(r)} values of
type \tcode{invoke_result_t<G\&>} by performing
an unspecified number of invocations of
the form \tcode{g()} or \tcode{g.generate_random(s)},
if such an expression is well-formed for a value \tcode{N} and
an object \tcode{s} of type \tcode{span<invoke_result_t<G\&>, N>}.
\begin{note}
Values of \tcode{N} can differ between invocations.
\end{note}
\item
Otherwise, calls \tcode{ranges::generate(std::forward<R>(r), ref(g))}.
\end{itemize}

\pnum
\returns
\tcode{ranges::end(r)}.

\pnum
\remarks
The effects of \tcode{generate_random(r, g)} shall be equivalent to
\tcode{ranges::generate(std::for\-ward<R>(r), ref(g))}.
Comment on lines +11715 to +11716
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we turn this into Preconditions?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Uh, why? This is a constraint on the implementation, not the user.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ranges::generate_random potentially calls a generate_random member function, and the generate_random member function is only provided by the user code (at this moment). In such a case, the equivalency can't be achieved if the generate_random member function doesn't have equivalent effects.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, this is a requirement on user code

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

... But only if the generator has a suitable member function that gets used here.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok. So, going back to the original concern here: should this be a Precondition instead?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jwakely any thoughts?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, but maybe we should do that as an LWG issue, since I think it needs something non-trivial like "if the first or second bullet below is used, then the behaviour is equivalent to the third bullet" ... but in proper standardese.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK -- the new WD is in the mailing, so please feel free to file issues against N4981!

\begin{note}
This implies that \tcode{g.generate_random(a)} fills \tcode{a}
with the same values as produced by invocation of \tcode{g()}.
\end{note}
\end{itemdescr}

\begin{itemdecl}
template<class G, @\libconcept{output_iterator}@<invoke_result_t<G&>> O, @\libconcept{sentinel_for}@<O> S>
requires @\libconcept{uniform_random_bit_generator}@<remove_cvref_t<G>>
constexpr O ranges::generate_random(O first, S last, G&& g);
\end{itemdecl}

\begin{itemdescr}
\pnum
\effects
Equivalent to:
\begin{codeblock}
return generate_random(subrange<O, S>(std::move(first), last), g);
\end{codeblock}
\end{itemdescr}

\begin{itemdecl}
template<class R, class G, class D>
requires @\libconcept{output_range}@<R, invoke_result_t<D&, G&>> && @\libconcept{invocable}@<D&, G&> &&
@\libconcept{uniform_random_bit_generator}@<remove_cvref_t<G>>
constexpr borrowed_iterator_t<R> ranges::generate_random(R&& r, G&& g, D&& d);
\end{itemdecl}

\begin{itemdescr}
\pnum
\effects
\begin{itemize}
\item
Calls \tcode{d.generate_random(std::forward<R>(r), g)}
if this expression is well-formed.
\item
Otherwise, if \tcode{R} models \tcode{sized_range},
fills \tcode{r} with \tcode{ranges::size(r)} values of
type \tcode{invoke_result_t<D\&, G\&>}
by performing an unspecified number of invocations of
the form \tcode{invoke(d, g)} or \tcode{d.generate_random(s, g)},
if such an expression is well-formed
for a value \tcode{N} and
an object \tcode{s} of type \tcode{span<invoke_result_t<D\&, G\&>, N>}.
\begin{note}
Values of N can differ between invocations.
\end{note}
\item
Otherwise, calls
\begin{codeblock}
ranges::generate(std::forward<R>(r), [&d, &g] { return invoke(d, g); });
\end{codeblock}
\end{itemize}

\pnum
\returns
\tcode{ranges::end(r)}

\pnum
\remarks
The effects of \tcode{generate_random(r, g, d)} shall be equivalent to
\begin{codeblock}
ranges::generate(std::forward<R>(r), [&d, &g] { return invoke(d, g); })}
\end{codeblock}
\begin{note}
This implies that \tcode{d.generate_random(a, g)}
fills \tcode{a} with the values with the same random distribution
as produced by invocation of \tcode{invoke(d, g)}.
\end{note}
\end{itemdescr}

\begin{itemdecl}
template<class G, class D, @\libconcept{output_iterator}@<invoke_result_t<D&, G&>> O, @\libconcept{sentinel_for}@<O> S>
requires @\libconcept{invocable}@<D&, G&> && @\libconcept{uniform_random_bit_generator}@<remove_cvref_t<G>>
constexpr O ranges::generate_random(O first, S last, G&& g, D&& d);
\end{itemdecl}

\begin{itemdescr}
\pnum
\effects
Equivalent to:
\begin{codeblock}
return generate_random(subrange<O, S>(std::move(first), last), g, d);
\end{codeblock}
\end{itemdescr}

\rSec1[alg.c.library]{C library algorithms}

\pnum
Expand Down
21 changes: 21 additions & 0 deletions source/numerics.tex
Original file line number Diff line number Diff line change
Expand Up @@ -1432,6 +1432,27 @@
template<class RealType, size_t digits, class URBG>
RealType generate_canonical(URBG& g);

namespace ranges {
// \ref{alg.rand.generate}, \tcode{generate_random}
template<class R, class G>
requires @\libconcept{output_range}@<R, invoke_result_t<G&>> &&
@\libconcept{uniform_random_bit_generator}@<remove_cvref_t<G>>
constexpr borrowed_iterator_t<R> generate_random(R&& r, G&& g);

template<class G, @\libconcept{output_iterator}@<invoke_result_t<G&>> O, @\libconcept{sentinel_for}@<O> S>
requires @\libconcept{uniform_random_bit_generator}@<remove_cvref_t<G>>
constexpr O generate_random(O first, S last, G&& g);

template<class R, class G, class D>
requires @\libconcept{output_range}@<R, invoke_result_t<D&, G&>> && @\libconcept{invocable}@<D&, G&> &&
@\libconcept{uniform_random_bit_generator}@<remove_cvref_t<G>>
constexpr borrowed_iterator_t<R> generate_random(R&& r, G&& g, D&& d);

template<class G, class D, @\libconcept{output_iterator}@<invoke_result_t<D&, G&>> O, @\libconcept{sentinel_for}@<O> S>
requires @\libconcept{invocable}@<D&, G&> && @\libconcept{uniform_random_bit_generator}@<remove_cvref_t<G>>
constexpr O generate_random(O first, S last, G&& g, D&& d);
}

// \ref{rand.dist.uni.int}, class template \tcode{uniform_int_distribution}
template<class IntType = int>
class uniform_int_distribution;
Expand Down
1 change: 1 addition & 0 deletions source/support.tex
Original file line number Diff line number Diff line change
Expand Up @@ -740,6 +740,7 @@
#define @\defnlibxname{cpp_lib_ranges_enumerate}@ 202302L // also in \libheader{ranges}, \libheader{version}
#define @\defnlibxname{cpp_lib_ranges_find_last}@ 202207L // also in \libheader{algorithm}
#define @\defnlibxname{cpp_lib_ranges_fold}@ 202207L // also in \libheader{algorithm}
#define @\defnlibxname{cpp_lib_ranges_generate_random}@ 202403L // also in \libheader{random}
#define @\defnlibxname{cpp_lib_ranges_iota}@ 202202L // also in \libheader{numeric}
#define @\defnlibxname{cpp_lib_ranges_join_with}@ 202202L // freestanding, also in \libheader{ranges}
#define @\defnlibxname{cpp_lib_ranges_repeat}@ 202207L // freestanding, also in \libheader{ranges}
Expand Down