9 #ifndef IMPBASE_PIECEWISE_LINEAR_DISTRIBUTION_H
10 #define IMPBASE_PIECEWISE_LINEAR_DISTRIBUTION_H
12 #include <IMP/base/base_config.h>
14 #include <boost/version.hpp>
15 #include <boost/random/uniform_real.hpp>
23 IMPBASE_BEGIN_NAMESPACE
31 template <
class T=
double>
36 mutable boost::uniform_real<> un_;
37 double get_divider(
int divider)
const {
38 return dividers_[divider];
40 double get_accum(
int divider)
const {
41 return accum_[divider];
43 double get_slope(
int divider)
const {
44 return (weights_[divider+1]-weights_[divider])
45 /(dividers_[divider+1]-dividers_[divider]);
47 double get_weight(
int divider)
const {
48 return weights_[divider]; }
52 dividers_.push_back(0);
53 dividers_.push_back(1);
56 weights_.push_back(1);
57 weights_.push_back(1);
64 template <
class LIt,
class WIt>
67 dividers_(locations_begin,
69 accum_(std::distance(locations_begin, locations_end)),
70 weights_(std::distance(locations_begin, locations_end)),
72 for (
unsigned int i=0; i< weights_.size(); ++i) {
73 weights_[i]=*weights_begin;
77 for (
unsigned int i=1; i< accum_.size(); ++i) {
78 double wid=(dividers_[i]-dividers_[i-1]);
79 accum_[i]= accum_[i-1]+wid*.5*(weights_[i-1]+weights_[i]);
81 double total=accum_.back();
82 #if IMP_HAS_CHECKS >= IMP_INTERNAL
83 for (
unsigned int i=1; i< dividers_.size(); ++i) {
84 if (dividers_[i] <= dividers_[i-1]) {
85 std::cerr <<
"Found non-monotonic locations: ";
86 std::copy(locations_begin, locations_end,
87 std::ostream_iterator<double>(std::cerr,
", "));
88 std::cerr << std::endl;
89 throw std::logic_error(
"Locations are not strictly increasing");
93 if (std::abs(total-1.0) > .05){
94 std::cerr <<
"Found weight " << total << std::endl;
95 std::cerr <<
"Locations: [";
96 std::copy(locations_begin, locations_end,
97 std::ostream_iterator<double>(std::cerr,
", "));
98 std::cerr <<
"]" << std::endl;
99 std::cerr <<
"Weights: [";
100 std::copy(weights_.begin(), weights_.end(),
101 std::ostream_iterator<double>(std::cerr,
", "));
102 std::cerr <<
"]" << std::endl;
105 (
"The total weight of the distribution is not close to 1");
109 for (
unsigned int i=0; i< accum_.size(); ++i) {
125 double operator()(RNG& rng)
const {
128 = std::upper_bound(accum_.begin()+1, accum_.end(), rn);
129 if (it == accum_.end()) {
130 std::cerr <<
"Hit end " << rn <<
" " << accum_.back() << std::endl;
131 return dividers_.back();
133 int offset= it-accum_.begin()-1;
134 double pd= get_weight(offset);
135 double ad= get_accum(offset);
136 double sd= get_slope(offset);
138 double radix=std::sqrt(pd*pd+2*leftd*sd);
141 xmd= (-pd + radix)/sd;
143 xmd= (-pd + radix)/(sd);
147 std::cerr <<
"negative " << std::endl;
152 return xmd+get_divider(offset);
159 IMPBASE_END_NAMESPACE