145 throw InputError(
"SolverLDES (native engine): the Replayer at " + where_ +
146 " carries no samples");
150 const double half = mean_ * std::sqrt(3.0 * scv_);
153 if (!(a_ >= 0.0) || !(b_ > a_))
154 throw InputError(
"SolverLDES (native engine): the Uniform at " + where_ +
155 " implies a support reaching below zero; a non-negative "
156 "uniform requires an SCV of at most 1/3");
166 const double c = std::sqrt(scv_);
167 a_ = std::pow(c, -1.086);
168 b_ = mean_ / std::tgamma(1.0 + 1.0 / a_);
169 if (!(a_ > 0.0) || !(b_ > 0.0))
170 throw InputError(
"SolverLDES (native engine): the Weibull at " + where_ +
171 " has unusable moments");
176 const double c2p1 = scv_ + 1.0;
177 a_ = std::log(mean_ / std::sqrt(c2p1));
178 b_ = std::sqrt(std::log(c2p1));
180 throw InputError(
"SolverLDES (native engine): the Lognormal at " + where_ +
181 " has a zero log-variance");
188 a_ = std::sqrt(1.0 + 1.0 / scv_) + 1.0;
189 b_ = mean_ * (a_ - 1.0) / a_;
197 if (!(a_ > 0.0) || a_ > 1.0)
198 throw InputError(
"SolverLDES (native engine): the Geometric at " + where_ +
199 " has a success probability outside (0,1]");
210 const double var = scv_ * mean_ * mean_;
211 b_ = std::floor(std::sqrt(12.0 * var + 1.0) + 0.5);
212 a_ = mean_ - (b_ - 1.0) / 2.0;
214 throw InputError(
"SolverLDES (native engine): the DiscreteUniform at " +
215 where_ +
" has moments no (min,max) pair realises");
217 throw InputError(
"SolverLDES (native engine): the DiscreteUniform at " +
218 where_ +
" reaches below zero");
225 if (!(mean_ >= 0.0) || !(mean_ <= 1.0))
226 throw InputError(
"SolverLDES (native engine): the Bernoulli at " + where_ +
227 " has a mean outside [0,1]");
231 const double p = 1.0 - scv_ * mean_;
232 if (!(p > 0.0) || p > 1.0)
233 throw InputError(
"SolverLDES (native engine): the Binomial at " + where_ +
234 " has moments no (n,p) pair realises");
236 b_ = std::floor(mean_ / p + 0.5);
264 throw UnsupportedError(
"SolverLDES (native engine): the process at " + where_ +
265 " is of a family this engine does not sample");
271 double mean()
const {
return mean_; }
283 if (!has_schedule_)
return next(g);
284 return schedule_sample(g, from);
313 if (v != 0.0)
return v;
326 double draw(
Rng& g) {
337 const double v = trace_[trace_idx_];
338 trace_idx_ = (trace_idx_ + 1) % trace_.size();
341 return (v <= 0.0) ? 1e-9 : v;
360 return std::ceil(std::log(1.0 -
uniform01(g)) / std::log(1.0 - a_));
377 if (erlang_k_ <= 0)
return next_markovian(g);
379 for (
int i = 0; i < erlang_k_; ++i)
384 return next_markovian(g);
394 int phase()
const {
return has_phase_ ?
static_cast<int>(phase_) : -1; }
408 int last_batch()
const {
return last_batch_ > 0 ? last_batch_ : 1; }
409 bool marked()
const {
return !mark_.empty() || !seg_mark_.empty(); }
411 bool batched()
const {
return !batch_.empty() || !seg_batch_.empty(); }
413 if (has_phase_ && p >= 0 &&
static_cast<std::size_t
>(p) < map_.order()) {
414 phase_ =
static_cast<std::size_t
>(p);
420 void require_mean()
const {
421 if (!(mean_ > 0.0) || !std::isfinite(mean_))
422 throw InputError(
"SolverLDES (native engine): the process at " + where_ +
423 " has a mean that is neither finite nor positive");
425 void require_moments()
const {
427 if (!(scv_ > 0.0) || !std::isfinite(scv_))
428 throw InputError(
"SolverLDES (native engine): the process at " + where_ +
429 " has an SCV that is neither finite nor positive");
434 if (d.
D0.rows() == 0 || d.
D0.rows() != d.
D1.rows())
435 throw InputError(
"SolverLDES (native engine): the process at " + where_ +
436 " declares no (D0,D1) representation to sample");
437 const std::size_t K = d.
D0.rows();
440 for (std::size_t i = 0; i < K; ++i)
441 for (std::size_t j = 0; j < K; ++j) {
449 if (!(mean_ > 0.0)) {
452 throw InputError(
"SolverLDES (native engine): the process at " + where_ +
453 " has a non-positive mean under its (D0,D1) representation");
462 for (
const Matrix<T>& Dk : d.
Dmark) {
463 Matrix<double> m(K, K, 0.0);
464 for (std::size_t i = 0; i < K; ++i)
465 for (std::size_t j = 0; j < K; ++j)
466 m(i, j) = num_traits<T>::to_double(Dk(i, j));
478 for (
const Matrix<T>& Db : d.
Dmark) {
479 Matrix<double> m(K, K, 0.0);
480 for (std::size_t i = 0; i < K; ++i)
481 for (std::size_t j = 0; j < K; ++j)
482 m(i, j) = num_traits<T>::to_double(Db(i, j));
499 me_.reset(
new mam::MeSampler<double>(map_));
513 void recover_erlang() {
515 const std::size_t n = map_.order();
517 const double lambda = -map_.D0(0, 0);
518 if (!(lambda > 0.0))
return;
519 const double tol = 1e-12 * lambda;
520 for (std::size_t i = 0; i < n; ++i) {
521 if (std::fabs(-map_.D0(i, i) - lambda) > tol)
return;
522 for (std::size_t j = 0; j < n; ++j) {
523 if (j == i)
continue;
524 const double want = (j == i + 1) ? lambda : 0.0;
525 if (std::fabs(map_.D0(i, j) - want) > tol)
return;
528 for (std::size_t j = 0; j < n; ++j) {
529 const double want = (i + 1 == n && j == 0) ? lambda : 0.0;
530 if (std::fabs(map_.D1(i, j) - want) > tol)
return;
533 erlang_k_ =
static_cast<int>(n);
534 erlang_rate_ = lambda;
555 double next_map_java(Rng& g) {
556 const std::size_t n = map_.order();
560 const double lambda = map_.D1(0, 0);
561 return -std::log(g.aux.next_double()) / lambda;
566 const double r = g.aux.next_double();
568 for (std::size_t i = 0; i < n; ++i) {
578 std::vector<double> row(2 * n, 0.0);
581 const double rate = -map_.D0(phase_, phase_);
582 sample += -std::log(g.aux.next_double()) / rate;
583 for (std::size_t k = 0; k < n; ++k) {
584 row[k] = map_.D0(phase_, k);
585 row[n + k] = map_.D1(phase_, k);
588 std::size_t next_state = 2 * n - 1;
590 const double r = g.aux.next_double();
591 for (std::size_t j = 0; j < 2 * n; ++j) {
592 sum += row[j] / rate;
604 if (next_state >= 2 * n - 1 && go) {
610 phase_ = (next_state < n) ? next_state : next_state - n;
621 int sample_mark(std::size_t i, std::size_t j, Rng& g) {
622 const std::size_t C = mark_.size();
623 if (C == 0)
return 1;
625 for (std::size_t c = 0; c < C; ++c) total += std::max(0.0, mark_[c](i, j));
626 if (!(total > 0.0))
return 1;
627 const double r = g.aux.next_double() * total;
629 for (std::size_t c = 0; c < C; ++c) {
630 sum += std::max(0.0, mark_[c](i, j));
631 if (r < sum)
return static_cast<int>(c) + 1;
633 return static_cast<int>(C);
648 double next_mmap_java(Rng& g) {
649 const std::size_t n = map_.order();
651 const double lambda = map_.D1(0, 0);
652 const double time = -std::log(g.aux.next_double()) / lambda;
653 last_mark_ = sample_mark(0, 0, g);
659 const double r = g.aux.next_double();
661 for (std::size_t i = 0; i < n; ++i) {
671 std::vector<double> row(2 * n, 0.0);
673 const double rate = -map_.D0(phase_, phase_);
674 sample += -std::log(g.aux.next_double()) / rate;
675 for (std::size_t k = 0; k < n; ++k) {
676 row[k] = map_.D0(phase_, k);
677 row[n + k] = map_.D1(phase_, k);
680 std::size_t next_state = 2 * n - 1;
682 const double r = g.aux.next_double();
683 for (std::size_t j = 0; j < 2 * n; ++j) {
684 sum += row[j] / rate;
690 if (next_state >= n) {
691 const std::size_t dest = next_state - n;
692 last_mark_ = sample_mark(phase_, dest, g);
712 double next_bmap_java(Rng& g) {
713 const std::size_t n = map_.order();
714 const std::size_t B = batch_.size();
717 const double lambda = map_.D1(0, 0);
718 const double time = -std::log(g.aux.next_double()) / lambda;
720 for (std::size_t b = 0; b < B; ++b) total += batch_[b](0, 0);
722 const double r = g.aux.next_double() * total;
724 for (std::size_t b = 0; b < B; ++b) {
725 cum += batch_[b](0, 0);
727 last_batch_ =
static_cast<int>(b) + 1;
737 const double r = g.aux.next_double();
739 for (std::size_t i = 0; i < n; ++i) {
748 const std::size_t cols = n + B * n;
749 std::vector<double> row(cols, 0.0);
752 const double rate = -map_.D0(phase_, phase_);
753 sample += -std::log(g.aux.next_double()) / rate;
754 for (std::size_t k = 0; k < n; ++k) row[k] = map_.D0(phase_, k);
756 for (std::size_t b = 0; b < B; ++b)
757 for (std::size_t k = 0; k < n; ++k) row[n + b * n + k] = batch_[b](phase_, k);
758 std::size_t next_state = phase_;
761 const double r = g.aux.next_double();
762 for (std::size_t j = 0; j < cols; ++j) {
763 sum += row[j] / rate;
768 const std::size_t idx = j - n;
769 last_batch_ =
static_cast<int>(idx / n) + 1;
770 next_state = idx % n;
777 if (fired)
return sample;
781 double next_markovian(Rng& g) {
782 std::vector<double> out;
787 return next_map_java(g);
790 return next_mmap_java(g);
793 return next_bmap_java(g);
801 return me_->next(g.mc);
807 std::vector<double> a_next;
812 std::vector<double> start;
813 if (has_phase_ && phase_known_) {
814 start.assign(map_.order(), 0.0);
818 if (has_phase_ && !tr.last.empty()) {
823 if (out.empty())
return 0.0;
831 void load_schedule(
const lang::Distrib<T>& d) {
832 if (!d.has_schedule())
833 throw InputError(
"SolverLDES (native engine): the time-inhomogeneous process at " +
834 where_ +
" carries no segment schedule");
835 for (
const T& b : d.sched_bp) bp_.push_back(num_traits<T>::to_double(b));
836 if (bp_.size() != d.sched_D0.size() + 1)
837 throw InputError(
"SolverLDES (native engine): the schedule at " + where_ +
838 " has a boundary vector that does not bound its segments");
839 for (std::size_t k = 0; k < d.sched_D0.size(); ++k) {
840 const std::size_t H = d.sched_D0[k].rows();
841 mam::Map<double> seg;
842 seg.D0 = Matrix<double>(H, H, 0.0);
843 seg.D1 = Matrix<double>(H, H, 0.0);
844 for (std::size_t a = 0; a < H; ++a)
845 for (std::size_t b2 = 0; b2 < H; ++b2) {
846 seg.D0(a, b2) = num_traits<T>::to_double(d.sched_D0[k](a, b2));
847 seg.D1(a, b2) = num_traits<T>::to_double(d.sched_D1[k](a, b2));
849 segs_.push_back(seg);
854 if (d.has_marked_schedule()) {
855 const std::size_t C = d.sched_Dmark.size();
856 for (std::size_t k = 0; k < d.sched_D0.size(); ++k) {
857 const std::size_t H = d.sched_D0[k].rows();
858 std::vector<Matrix<double>> per_mark;
859 for (std::size_t c = 0; c < C; ++c) {
860 Matrix<double> m(H, H, 0.0);
861 for (std::size_t a = 0; a < H; ++a)
862 for (std::size_t b2 = 0; b2 < H; ++b2)
863 m(a, b2) = num_traits<T>::to_double(d.sched_Dmark[c][k](a, b2));
864 per_mark.push_back(m);
866 seg_mark_.push_back(per_mark);
875 if (d.has_batch_schedule()) {
876 const std::size_t C = d.sched_Dbatch.size();
877 const std::size_t B = d.sched_Dbatch[0].size();
878 for (std::size_t k = 0; k < d.sched_D0.size(); ++k) {
879 const std::size_t H = d.sched_D0[k].rows();
880 std::vector<std::vector<Matrix<double>>> per_mark;
881 for (std::size_t c = 0; c < C; ++c) {
882 std::vector<Matrix<double>> per_batch;
883 for (std::size_t b = 0; b < B; ++b) {
884 Matrix<double> m(H, H, 0.0);
885 for (std::size_t a = 0; a < H; ++a)
886 for (std::size_t b2 = 0; b2 < H; ++b2)
887 m(a, b2) = num_traits<T>::to_double(d.sched_Dbatch[c][b][k](a, b2));
888 per_batch.push_back(m);
890 per_mark.push_back(per_batch);
892 seg_batch_.push_back(per_mark);
895 cyclic_ = d.sched_cyclic;
896 has_schedule_ =
true;
898 if (!(mean_ > 0.0)) mean_ = num_traits<T>::to_double(d.mean);
903 double period()
const {
return bp_.back() - bp_.front(); }
913 double offset_at(
double t)
const {
914 double offset = t - bp_.front();
915 const double per = period();
917 offset = std::fmod(offset, per);
918 if (offset < 0.0) offset += per;
919 }
else if (offset < 0.0 || offset >= per) {
926 int segment_of(
double offset)
const {
927 const double pos = bp_.front() + offset;
928 for (std::size_t k = 0; k + 1 < bp_.size(); ++k)
929 if (pos < bp_[k + 1])
return static_cast<int>(k);
930 return static_cast<int>(segs_.size()) - 1;
934 int segment_at(
double t)
const {
935 const double offset = offset_at(t);
936 return (offset < 0.0) ? -1 : segment_of(offset);
950 double schedule_sample(Rng& g,
double from) {
951 const std::size_t H = segs_[0].order();
952 double offset = offset_at(from);
953 if (offset < 0.0)
return 0.0;
954 std::size_t idx =
static_cast<std::size_t
>(segment_of(offset));
955 double elapsed = 0.0;
956 for (
int guard = 0; guard < 1000000; ++guard) {
957 const double to_boundary = (bp_[idx + 1] - bp_.front()) - offset;
958 const mam::Map<double>& seg = segs_[idx];
959 const double total = -seg.D0(phase_, phase_);
961 const double holding = (total > 0.0) ? -std::log(
uniform01(g)) / total
962 : std::numeric_limits<double>::infinity();
963 if (holding >= to_boundary) {
965 if (idx >= segs_.size()) {
966 if (!cyclic_)
return 0.0;
969 elapsed += to_boundary;
977 offset = bp_[idx] - bp_.front();
993 if (!seg_mark_.empty()) {
994 const std::vector<Matrix<double>>& marks = seg_mark_[idx];
999 const bool batched_here = !seg_batch_.empty();
1000 const std::size_t B = batched_here ? seg_batch_[idx][0].size() : std::size_t(1);
1001 for (std::size_t j = 0; j < H; ++j) {
1002 for (std::size_t c = 0; c < marks.size(); ++c) {
1003 if (!batched_here) {
1004 cum += marks[c](phase_, j);
1006 last_mark_ =
static_cast<int>(c) + 1;
1013 for (std::size_t b = 0; b < B; ++b) {
1014 cum += seg_batch_[idx][c][b](phase_, j);
1016 last_mark_ =
static_cast<int>(c) + 1;
1017 last_batch_ =
static_cast<int>(b) + 1;
1024 for (std::size_t j = 0; j < H; ++j) {
1025 if (j == phase_)
continue;
1026 cum += seg.D0(phase_, j);
1028 chosen =
static_cast<int>(H + j);
1035 for (std::size_t j = H; j-- > 0;)
1036 for (std::size_t c = marks.size(); c-- > 0;) {
1037 if (!batched_here) {
1038 if (marks[c](phase_, j) > 0.0) {
1039 last_mark_ =
static_cast<int>(c) + 1;
1046 for (std::size_t b = B; b-- > 0;)
1047 if (seg_batch_[idx][c][b](phase_, j) > 0.0) {
1048 last_mark_ =
static_cast<int>(c) + 1;
1049 last_batch_ =
static_cast<int>(b) + 1;
1058 phase_ =
static_cast<std::size_t
>(chosen) - H;
1061 for (std::size_t j = 0; j < 2 * H; ++j) {
1062 const double w = (j < H) ? seg.D1(phase_, j)
1063 : ((j - H == phase_) ? 0.0 : seg.D0(phase_, j - H));
1066 chosen =
static_cast<int>(j);
1071 for (std::size_t j = 2 * H; j-- > 0;) {
1072 const double w = (j < H) ? seg.D1(phase_, j)
1073 : ((j - H == phase_) ? 0.0 : seg.D0(phase_, j - H));
1075 chosen =
static_cast<int>(j);
1079 if (chosen <
static_cast<int>(H)) {
1080 phase_ =
static_cast<std::size_t
>(chosen);
1083 phase_ =
static_cast<std::size_t
>(chosen) - H;
1090 double mean_ = 0.0, scv_ = 1.0, rate_ = 0.0;
1091 double a_ = 0.0, b_ = 0.0;
1093 double erlang_rate_ = 0.0;
1094 std::vector<double> trace_;
1095 std::size_t trace_idx_ = 0;
1096 mam::Map<double> map_;
1097 std::vector<double> entry_;
1098 std::shared_ptr<mam::MeSampler<double>> me_;
1100 std::vector<std::vector<Matrix<double>>> seg_mark_;
1102 std::vector<Matrix<double>> mark_;
1105 std::vector<Matrix<double>> batch_;
1107 std::vector<std::vector<std::vector<Matrix<double>>>> seg_batch_;
1111 int last_batch_ = 0;
1112 bool has_phase_ =
false, phase_known_ =
false;
1115 bool has_schedule_ =
false, cyclic_ =
false;
1116 std::vector<double> bp_;
1117 std::vector<mam::Map<double>> segs_;
1118 std::size_t phase_ = 0;