Title
Bogus requirements for piecewise_linear_distribution
Status
new
Section
[rand.dist.samp.pconst] [rand.dist.samp.plinear]
Submitter
Jonathan Wakely

Created on 2024-02-04.00:00:00 last changed 3 days ago

Messages

Date: 2025-10-11.10:14:37

Proposed resolution:

This wording is relative to N5014.

  1. Modify [rand.dist.samp.pconst] as indicated:

    template<class InputIteratorB, class InputIteratorW>
      piecewise_constant_distribution(InputIteratorB firstB, InputIteratorB lastB,
                                      InputIteratorW firstW);
    

    -4- Mandates: Both of

    1. (4.1) — is_convertible_v<iterator_traits<InputIteratorB>::value_type, result_typedouble>

    2. (4.2) — is_convertible_v<iterator_traits<InputIteratorW>::value_type, result_typedouble>

    are `true`.

    […]

    template<class UnaryOperation>
      piecewise_constant_distribution(initializer_list<RealType> bl, UnaryOperation fw);
    

    -7- Mandates: is_invocable_r_v<result_typedouble, UnaryOperation&, result_typedouble> is `true`.

    […]

    template<class UnaryOperation>
      piecewise_constant_distribution(size_t nw, RealType xmin, RealType xmax, UnaryOperation fw);
    

    -10- Mandates: is_invocable_r_v<result_typedouble, UnaryOperation&, result_typedouble> is `true`.

    […]

  2. Modify [rand.dist.samp.plinear] as indicated:

    template<class InputIteratorB, class InputIteratorW>
      piecewise_linear_distribution(InputIteratorB firstB, InputIteratorB lastB,
                                    InputIteratorW firstW);
    

    -4- Mandates: Both of

    1. (4.1) — is_convertible_v<iterator_traits<InputIteratorB>::value_type, result_typedouble>

    2. (4.2) — is_convertible_v<iterator_traits<InputIteratorW>::value_type, result_typedouble>

    are `true`.

    […]

    template<class UnaryOperation>
      piecewise_linear_distribution(initializer_list<RealType> bl, UnaryOperation fw);
    

    -7- Mandates: is_invocable_r_v<result_typedouble, UnaryOperation&, result_typedouble> is `true`.

    […]

    template<class UnaryOperation>
      piecewise_linear_distribution(size_t nw, RealType xmin, RealType xmax, UnaryOperation fw);
    

    -10- Mandates: is_invocable_r_v<result_typedouble, UnaryOperation&, result_typedouble> is `true`.

    […]

Date: 2025-10-15.00:00:00

[ 2025-10-06; Hewill comments and provides wording ]

We should fix the constructor, otherwise the following should be rejected according to the standard:

#include <random>

struct Op {
  float operator()(float);
  void operator()(auto) = delete;
};

static_assert(!std::is_invocable_r_v<double, Op&, double>);

int main() {
  std::initializer_list<float> l;
  std::piecewise_linear_distribution<float> dist(l, Op{});
}

This is, because it violates Mandates. However, all three compilers accept it because Op& can take `float` and return `float`.

Date: 2024-03-15.00:00:00

[ 2024-03-12; Reflector poll ]

Set priority to 4 after reflector poll. The copy & paste error was fixed editorially.

Date: 2024-02-05.12:51:27

In the second constructor of [rand.dist.samp.plinear], P1719R2 replaced:


template<class InputIteratorB, class InputIteratorW>
  piecewise_linear_distribution(InputIteratorB firstB, InputIteratorB lastB,
                                InputIteratorW firstW);

Effects: [...] Moreover, the id-expressions iterator_traits<InputIteratorB>::value_type and iterator_traits<InputIteratorW>::value_type shall each denote a type that is convertible to double.

with

template<class InputIteratorB, class InputIteratorW>
  piecewise_linear_distribution(InputIteratorB firstB, InputIteratorB lastB,
                                InputIteratorW firstW);

Mandates: is_invocable_r_v<double, UnaryOperation&, double> is true.

Preconditions: [...]

Effects: [...]

This was a copy & paste error from the next constructor, and was obviously not intended. There is no UnaryOperation in that constructor.

A less obviously wrong issue is the use of double there in the first place. Shouldn't it be RealType instead? That seems to be incorrect throughout both [rand.dist.samp.pconst] and [rand.dist.samp.plinear], and was only partially fixed by LWG 1439.

Finally, the preconditions also say:

Preconditions: [...] If firstB == lastB or ++firstB == lastB, let n = 1, ρ0 = ρ1 = 1, b0 = 0, and b1 = 1. Otherwise, [firstB, lastB) forms a sequence b of length n + 1, the length of the sequence w starting from firstW is at least n, and any wk for kn are ignored by the distribution.

These are not preconditions. I think it is trying to say something like:

Preconditions: [...] [firstB, lastB) is a valid range and [firstW, firstW + (lastB - firstB)) is a valid range.

Effects: If firstB == lastB or ++firstB == lastB, let n = 1, ρ0 = ρ1 = 1, b0 = 0, and b1 = 1. Otherwise, let [firstB, lastB) form a sequence b0, …, bn, and let wk = *firstW++ for k = 0, …, n.

The equivalent constructor for piecewise_constant_distribution has similar problems with its preconditions in terms of n + 1.

History
Date User Action Args
2025-10-11 10:14:37adminsetmessages: + msg15145
2025-10-11 10:14:37adminsetmessages: + msg15144
2024-03-12 01:17:28adminsetmessages: + msg14001
2024-02-05 12:11:19adminsetmessages: + msg13946
2024-02-05 12:11:19adminrestored
2024-02-04 17:03:55adminretired
2024-02-04 17:03:55adminsetmessages: - msg13944, msg13945
2024-02-04 15:47:01adminsetmessages: + msg13945
2024-02-04 00:00:00admincreate