-
Notifications
You must be signed in to change notification settings - Fork 1.6k
<random>: Fix parameter initialization of piecewise_constant_distribution and piecewise_linear_distribution #1032
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
Changes from all commits
4d895ae
176efd4
3708a87
f13643d
8627d9d
2a07e1e
0ea47b4
1fef5f7
45cb97b
7055abe
dca316a
29d8314
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -4528,17 +4528,16 @@ public: | |
| struct param_type : _Mypbase { // parameter package | ||
| using distribution_type = piecewise_constant_distribution; | ||
|
|
||
| param_type() { | ||
| _Bvec.push_back(0); | ||
| _Bvec.push_back(1); | ||
| } | ||
| param_type() : _Bvec{0, 1} {} | ||
|
|
||
| template <class _InIt1, class _InIt2> | ||
| param_type(_InIt1 _First1, _InIt1 _Last1, _InIt2 _First2) : _Mypbase(_Noinit), _Bvec(_First1, _Last1) { | ||
| if (2 <= _Bvec.size()) { | ||
| for (size_t _Idx = 0; _Idx < _Bvec.size() - 1; ++_Idx) { | ||
| this->_Pvec.push_back(static_cast<double>(*_First2++)); | ||
| } | ||
| } else { // default construct | ||
| _Bvec = {0, 1}; | ||
| } | ||
|
|
||
| _Init(); | ||
|
|
@@ -4548,18 +4547,12 @@ public: | |
| param_type(initializer_list<_Ty> _Ilist, _Fn _Func) : _Mypbase(_Noinit) { | ||
| if (2 <= _Ilist.size()) { | ||
| _Bvec.assign(_Ilist); | ||
| } else { // default construct | ||
| _Bvec.push_back(0); | ||
| _Bvec.push_back(1); | ||
| } | ||
|
|
||
| _Ty _Low = _Bvec.front(); | ||
| _Ty _Range = _Bvec.back() - _Low; | ||
| size_t _Count = _Bvec.size() - 1; | ||
|
|
||
| _Range /= static_cast<_Ty>(_Count); | ||
| for (size_t _Idx = 0; _Idx < _Count; ++_Idx) { | ||
| _Pvec.push_back(_Func(_Low + _Idx * _Range)); | ||
| for (size_t _Idx = 0; _Idx < _Bvec.size() - 1; ++_Idx) { | ||
| this->_Pvec.push_back(_Func(_Ty{0.5} * (_Bvec[_Idx] + _Bvec[_Idx + 1]))); | ||
| } | ||
| } else { // default construct | ||
| _Bvec = {0, 1}; | ||
| } | ||
|
|
||
| _Init(); | ||
|
|
@@ -4726,11 +4719,12 @@ public: | |
| using result_type = _Ty; | ||
|
|
||
| struct param_type : _Mypbase { // parameter package | ||
| // TRANSITION, ABI: stores probability densities (N + 1 elements) in _Mybase::_Pvec | ||
| // this breaks invariants of discrete_distribution<size_t>::param_type | ||
| using distribution_type = piecewise_linear_distribution; | ||
|
|
||
| param_type() { | ||
| _Bvec.push_back(0); | ||
| _Bvec.push_back(1); | ||
| param_type() : _Bvec{0, 1} { | ||
| this->_Pvec.push_back(1.0); | ||
| } | ||
|
|
||
| template <class _InIt1, class _InIt2> | ||
|
|
@@ -4739,6 +4733,8 @@ public: | |
| for (size_t _Idx = 0; _Idx < _Bvec.size(); ++_Idx) { | ||
| this->_Pvec.push_back(static_cast<double>(*_First2++)); | ||
| } | ||
| } else { // default construct | ||
| _Bvec = {0, 1}; | ||
| } | ||
|
|
||
| _Init(); | ||
|
|
@@ -4748,18 +4744,12 @@ public: | |
| param_type(initializer_list<_Ty> _Ilist, _Fn _Func) : _Mypbase(_Noinit) { | ||
| if (2 <= _Ilist.size()) { | ||
| _Bvec.assign(_Ilist); | ||
| } else { // default construct | ||
| _Bvec.push_back(0); | ||
| _Bvec.push_back(1); | ||
| } | ||
|
|
||
| _Ty _Low = _Bvec.front(); | ||
| _Ty _Range = _Bvec.back() - _Low; | ||
| size_t _Count = _Bvec.size(); | ||
|
|
||
| _Range /= static_cast<_Ty>(_Count); | ||
| for (size_t _Idx = 0; _Idx < _Count; ++_Idx) { | ||
| this->_Pvec.push_back(_Func(_Low + _Idx * _Range)); | ||
| for (const auto& _Bval : _Bvec) { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. At work I would ask for std::transform but here meh
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. And here, range-based transform would be too good for meh, since I expect it to be very short and clear, and enabling |
||
| this->_Pvec.push_back(_Func(_Bval)); | ||
| } | ||
| } else { // default construct | ||
| _Bvec = {0, 1}; | ||
| } | ||
|
|
||
| _Init(); | ||
|
|
@@ -4769,12 +4759,12 @@ public: | |
| param_type(size_t _Count, _Ty _Low, _Ty _High, _Fn _Func) : _Mypbase(_Noinit) { | ||
| _Ty _Range = _High - _Low; | ||
| _STL_ASSERT(_Ty{0} < _Range, "invalid range for piecewise_linear_distribution"); | ||
| if (_Count < 2) { | ||
| _Count = 2; | ||
| if (_Count < 1) { | ||
| _Count = 1; | ||
| } | ||
|
|
||
| _Range /= static_cast<double>(_Count); | ||
| for (size_t _Idx = 0; _Idx < _Count; ++_Idx) { // compute _Bvec and _Pvec | ||
| for (size_t _Idx = 0; _Idx <= _Count; ++_Idx) { // compute _Bvec and _Pvec | ||
| _Ty _Bval = _Low + _Idx * _Range; | ||
| _Bvec.push_back(_Bval); | ||
| this->_Pvec.push_back(_Func(_Bval)); | ||
|
|
@@ -4799,20 +4789,27 @@ public: | |
| return _Ans; | ||
| } | ||
|
|
||
| _NODISCARD double _Piece_probability(const size_t _Idx) const { | ||
| return 0.5 * (this->_Pvec[_Idx] + this->_Pvec[_Idx + 1]) | ||
| * static_cast<double>(_Bvec[_Idx + 1] - _Bvec[_Idx]); | ||
| } | ||
|
|
||
| void _Init(bool _Renorm = true) { // initialize | ||
| size_t _Size = this->_Pvec.size(); | ||
| size_t _Idx; | ||
|
|
||
| if (_Renorm) { | ||
| if (this->_Pvec.empty()) { | ||
| this->_Pvec.push_back(1.0); // make empty vector degenerate | ||
| if (this->_Pvec.empty()) { // make empty vector degenerate | ||
| this->_Pvec = {1.0, 1.0}; | ||
| } else { // normalize probabilities | ||
| double _Sum = 0; | ||
|
|
||
| _STL_ASSERT(0.0 <= this->_Pvec[0], "invalid probability for " | ||
| "piecewise_linear_distribution"); | ||
| for (_Idx = 1; _Idx < _Size; ++_Idx) { // sum all probabilities | ||
| _STL_ASSERT(0.0 <= this->_Pvec[_Idx], "invalid probability for " | ||
| "piecewise_linear_distribution"); | ||
| _Sum += 0.5 * (this->_Pvec[_Idx - 1] + this->_Pvec[_Idx]); | ||
| _Sum += _Piece_probability(_Idx - 1); | ||
| } | ||
|
|
||
| _STL_ASSERT(0.0 < _Sum, "invalid probability vector for " | ||
|
|
@@ -4825,9 +4822,9 @@ public: | |
| } | ||
| } | ||
|
|
||
| this->_Pcdf.assign(1, 0.5 * (this->_Pvec[0] + this->_Pvec[1])); | ||
| this->_Pcdf.assign(1, _Piece_probability(0)); | ||
| for (_Idx = 2; _Idx < _Size; ++_Idx) { | ||
| this->_Pcdf.push_back(0.5 * (this->_Pvec[_Idx - 1] + this->_Pvec[_Idx]) + this->_Pcdf[_Idx - 2]); | ||
| this->_Pcdf.push_back(_Piece_probability(_Idx - 1) + this->_Pcdf[_Idx - 2]); | ||
| } | ||
| } | ||
|
|
||
|
|
@@ -4894,14 +4891,14 @@ public: | |
| _In(_Istr, _Val); | ||
| _Par0._Pvec.push_back(_Val); | ||
| } | ||
| _Par0._Init(false); // don't renormalize, just compute CDF | ||
|
|
||
| _Par._Bvec.clear(); | ||
| for (size_t _Idx = _Par._Pvec.size(); 0 < _Idx; --_Idx) { // get a value and add to intervals vector | ||
| _Par0._Bvec.clear(); | ||
| for (size_t _Idx = _Par0._Pvec.size(); 0 < _Idx; --_Idx) { // get a value and add to intervals vector | ||
| double _Val; | ||
| _In(_Istr, _Val); | ||
| _Par._Bvec.push_back(_Val); | ||
| _Par0._Bvec.push_back(_Val); | ||
| } | ||
| _Par0._Init(false); // don't renormalize, just compute CDF | ||
| return _Istr; | ||
| } | ||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we need to reserve here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are several more occurrences in
discrete_distribution,piecewise_constant_distributionandpiecewise_linear_distributionwhere we could havereserved before populatingvectors. Perhaps for another "performance" PR?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A separate performance PR would make sense. Cautionary note: a single
reserveaftervectorconstruction is fine, but we should be careful to avoidreservein anything that the user can call in a loop for a singlevector, as that can trigger quadratic complexity. I'm specifically thinking aboutdist.param(const param_type&)here.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A pattern like this
STL/stl/inc/random
Lines 247 to 251 in 1fef5f7
is ideally replaced with range-based algorithm, which would result in transformed iterators, and the vector would reserve automatically at least for random-access iterator.
Maybe just create issue for now and wait for ranges?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This needs to work in C++14 mode and thus will not have ranges avaialble.