150 throw InputError(
"SolverLDES (native engine): the Replayer at " + where_ +
151 " carries no samples");
155 const double half = mean_ * std::sqrt(3.0 * scv_);
158 if (!(a_ >= 0.0) || !(b_ > a_))
159 throw InputError(
"SolverLDES (native engine): the Uniform at " + where_ +
160 " implies a support reaching below zero; a non-negative "
161 "uniform requires an SCV of at most 1/3");
171 const double c = std::sqrt(scv_);
172 a_ = std::pow(c, -1.086);
173 b_ = mean_ / std::tgamma(1.0 + 1.0 / a_);
174 if (!(a_ > 0.0) || !(b_ > 0.0))
175 throw InputError(
"SolverLDES (native engine): the Weibull at " + where_ +
176 " has unusable moments");
181 const double c2p1 = scv_ + 1.0;
182 a_ = std::log(mean_ / std::sqrt(c2p1));
183 b_ = std::sqrt(std::log(c2p1));
185 throw InputError(
"SolverLDES (native engine): the Lognormal at " + where_ +
186 " has a zero log-variance");
193 a_ = std::sqrt(1.0 + 1.0 / scv_) + 1.0;
194 b_ = mean_ * (a_ - 1.0) / a_;
202 if (!(a_ > 0.0) || a_ > 1.0)
203 throw InputError(
"SolverLDES (native engine): the Geometric at " + where_ +
204 " has a success probability outside (0,1]");
215 const double var = scv_ * mean_ * mean_;
216 b_ = std::floor(std::sqrt(12.0 * var + 1.0) + 0.5);
217 a_ = mean_ - (b_ - 1.0) / 2.0;
219 throw InputError(
"SolverLDES (native engine): the DiscreteUniform at " +
220 where_ +
" has moments no (min,max) pair realises");
222 throw InputError(
"SolverLDES (native engine): the DiscreteUniform at " +
223 where_ +
" reaches below zero");
230 if (!(mean_ >= 0.0) || !(mean_ <= 1.0))
231 throw InputError(
"SolverLDES (native engine): the Bernoulli at " + where_ +
232 " has a mean outside [0,1]");
236 const double p = 1.0 - scv_ * mean_;
237 if (!(p > 0.0) || p > 1.0)
238 throw InputError(
"SolverLDES (native engine): the Binomial at " + where_ +
239 " has moments no (n,p) pair realises");
241 b_ = std::floor(mean_ / p + 0.5);
269 throw UnsupportedError(
"SolverLDES (native engine): the process at " + where_ +
270 " is of a family this engine does not sample");
276 double mean()
const {
return mean_; }
288 if (!has_schedule_)
return next(g);
289 return schedule_sample(g, from);
318 if (v != 0.0)
return v;
331 double draw(
Rng& g) {
342 const double v = trace_[trace_idx_];
343 trace_idx_ = (trace_idx_ + 1) % trace_.size();
346 return (v <= 0.0) ? 1e-9 : v;
365 return std::ceil(std::log(1.0 -
uniform01(g)) / std::log(1.0 - a_));
382 if (erlang_k_ <= 0)
return next_markovian(g);
384 for (
int i = 0; i < erlang_k_; ++i)
389 return next_markovian(g);
399 int phase()
const {
return has_phase_ ?
static_cast<int>(phase_) : -1; }
413 int last_batch()
const {
return last_batch_ > 0 ? last_batch_ : 1; }
414 bool marked()
const {
return !mark_.empty() || !seg_mark_.empty(); }
416 bool batched()
const {
return !batch_.empty() || !seg_batch_.empty(); }
418 if (has_phase_ && p >= 0 &&
static_cast<std::size_t
>(p) < map_.order()) {
419 phase_ =
static_cast<std::size_t
>(p);
425 void require_mean()
const {
426 if (!(mean_ > 0.0) || !std::isfinite(mean_))
427 throw InputError(
"SolverLDES (native engine): the process at " + where_ +
428 " has a mean that is neither finite nor positive");
430 void require_moments()
const {
432 if (!(scv_ > 0.0) || !std::isfinite(scv_))
433 throw InputError(
"SolverLDES (native engine): the process at " + where_ +
434 " has an SCV that is neither finite nor positive");
439 if (d.
D0.rows() == 0 || d.
D0.rows() != d.
D1.rows())
440 throw InputError(
"SolverLDES (native engine): the process at " + where_ +
441 " declares no (D0,D1) representation to sample");
442 const std::size_t K = d.
D0.rows();
445 for (std::size_t i = 0; i < K; ++i)
446 for (std::size_t j = 0; j < K; ++j) {
454 if (!(mean_ > 0.0)) {
457 throw InputError(
"SolverLDES (native engine): the process at " + where_ +
458 " has a non-positive mean under its (D0,D1) representation");
467 for (
const Matrix<T>& Dk : d.
Dmark) {
468 Matrix<double> m(K, K, 0.0);
469 for (std::size_t i = 0; i < K; ++i)
470 for (std::size_t j = 0; j < K; ++j)
471 m(i, j) = num_traits<T>::to_double(Dk(i, j));
483 for (
const Matrix<T>& Db : d.
Dmark) {
484 Matrix<double> m(K, K, 0.0);
485 for (std::size_t i = 0; i < K; ++i)
486 for (std::size_t j = 0; j < K; ++j)
487 m(i, j) = num_traits<T>::to_double(Db(i, j));
504 me_.reset(
new mam::MeSampler<double>(map_));
518 void recover_erlang() {
520 const std::size_t n = map_.order();
522 const double lambda = -map_.D0(0, 0);
523 if (!(lambda > 0.0))
return;
524 const double tol = 1e-12 * lambda;
525 for (std::size_t i = 0; i < n; ++i) {
526 if (std::fabs(-map_.D0(i, i) - lambda) > tol)
return;
527 for (std::size_t j = 0; j < n; ++j) {
528 if (j == i)
continue;
529 const double want = (j == i + 1) ? lambda : 0.0;
530 if (std::fabs(map_.D0(i, j) - want) > tol)
return;
533 for (std::size_t j = 0; j < n; ++j) {
534 const double want = (i + 1 == n && j == 0) ? lambda : 0.0;
535 if (std::fabs(map_.D1(i, j) - want) > tol)
return;
538 erlang_k_ =
static_cast<int>(n);
539 erlang_rate_ = lambda;
560 double next_map_java(Rng& g) {
561 const std::size_t n = map_.order();
565 const double lambda = map_.D1(0, 0);
566 return -std::log(g.aux.next_double()) / lambda;
571 const double r = g.aux.next_double();
573 for (std::size_t i = 0; i < n; ++i) {
583 std::vector<double> row(2 * n, 0.0);
586 const double rate = -map_.D0(phase_, phase_);
587 sample += -std::log(g.aux.next_double()) / rate;
588 for (std::size_t k = 0; k < n; ++k) {
589 row[k] = map_.D0(phase_, k);
590 row[n + k] = map_.D1(phase_, k);
593 std::size_t next_state = 2 * n - 1;
595 const double r = g.aux.next_double();
596 for (std::size_t j = 0; j < 2 * n; ++j) {
597 sum += row[j] / rate;
609 if (next_state >= 2 * n - 1 && go) {
615 phase_ = (next_state < n) ? next_state : next_state - n;
626 int sample_mark(std::size_t i, std::size_t j, Rng& g) {
627 const std::size_t C = mark_.size();
628 if (C == 0)
return 1;
630 for (std::size_t c = 0; c < C; ++c) total += std::max(0.0, mark_[c](i, j));
631 if (!(total > 0.0))
return 1;
632 const double r = g.aux.next_double() * total;
634 for (std::size_t c = 0; c < C; ++c) {
635 sum += std::max(0.0, mark_[c](i, j));
636 if (r < sum)
return static_cast<int>(c) + 1;
638 return static_cast<int>(C);
653 double next_mmap_java(Rng& g) {
654 const std::size_t n = map_.order();
656 const double lambda = map_.D1(0, 0);
657 const double time = -std::log(g.aux.next_double()) / lambda;
658 last_mark_ = sample_mark(0, 0, g);
664 const double r = g.aux.next_double();
666 for (std::size_t i = 0; i < n; ++i) {
676 std::vector<double> row(2 * n, 0.0);
678 const double rate = -map_.D0(phase_, phase_);
679 sample += -std::log(g.aux.next_double()) / rate;
680 for (std::size_t k = 0; k < n; ++k) {
681 row[k] = map_.D0(phase_, k);
682 row[n + k] = map_.D1(phase_, k);
685 std::size_t next_state = 2 * n - 1;
687 const double r = g.aux.next_double();
688 for (std::size_t j = 0; j < 2 * n; ++j) {
689 sum += row[j] / rate;
695 if (next_state >= n) {
696 const std::size_t dest = next_state - n;
697 last_mark_ = sample_mark(phase_, dest, g);
717 double next_bmap_java(Rng& g) {
718 const std::size_t n = map_.order();
719 const std::size_t B = batch_.size();
722 const double lambda = map_.D1(0, 0);
723 const double time = -std::log(g.aux.next_double()) / lambda;
725 for (std::size_t b = 0; b < B; ++b) total += batch_[b](0, 0);
727 const double r = g.aux.next_double() * total;
729 for (std::size_t b = 0; b < B; ++b) {
730 cum += batch_[b](0, 0);
732 last_batch_ =
static_cast<int>(b) + 1;
742 const double r = g.aux.next_double();
744 for (std::size_t i = 0; i < n; ++i) {
753 const std::size_t cols = n + B * n;
754 std::vector<double> row(cols, 0.0);
757 const double rate = -map_.D0(phase_, phase_);
758 sample += -std::log(g.aux.next_double()) / rate;
759 for (std::size_t k = 0; k < n; ++k) row[k] = map_.D0(phase_, k);
761 for (std::size_t b = 0; b < B; ++b)
762 for (std::size_t k = 0; k < n; ++k) row[n + b * n + k] = batch_[b](phase_, k);
763 std::size_t next_state = phase_;
766 const double r = g.aux.next_double();
767 for (std::size_t j = 0; j < cols; ++j) {
768 sum += row[j] / rate;
773 const std::size_t idx = j - n;
774 last_batch_ =
static_cast<int>(idx / n) + 1;
775 next_state = idx % n;
782 if (fired)
return sample;
786 double next_markovian(Rng& g) {
787 std::vector<double> out;
792 return next_map_java(g);
795 return next_mmap_java(g);
798 return next_bmap_java(g);
806 return me_->next(g.mc);
812 std::vector<double> a_next;
817 std::vector<double> start;
818 if (has_phase_ && phase_known_) {
819 start.assign(map_.order(), 0.0);
823 if (has_phase_ && !tr.last.empty()) {
828 if (out.empty())
return 0.0;
836 void load_schedule(
const lang::Distrib<T>& d) {
837 if (!d.has_schedule())
838 throw InputError(
"SolverLDES (native engine): the time-inhomogeneous process at " +
839 where_ +
" carries no segment schedule");
840 for (
const T& b : d.sched_bp) bp_.push_back(num_traits<T>::to_double(b));
841 if (bp_.size() != d.sched_D0.size() + 1)
842 throw InputError(
"SolverLDES (native engine): the schedule at " + where_ +
843 " has a boundary vector that does not bound its segments");
844 for (std::size_t k = 0; k < d.sched_D0.size(); ++k) {
845 const std::size_t H = d.sched_D0[k].rows();
846 mam::Map<double> seg;
847 seg.D0 = Matrix<double>(H, H, 0.0);
848 seg.D1 = Matrix<double>(H, H, 0.0);
849 for (std::size_t a = 0; a < H; ++a)
850 for (std::size_t b2 = 0; b2 < H; ++b2) {
851 seg.D0(a, b2) = num_traits<T>::to_double(d.sched_D0[k](a, b2));
852 seg.D1(a, b2) = num_traits<T>::to_double(d.sched_D1[k](a, b2));
854 segs_.push_back(seg);
859 if (d.has_marked_schedule()) {
860 const std::size_t C = d.sched_Dmark.size();
861 for (std::size_t k = 0; k < d.sched_D0.size(); ++k) {
862 const std::size_t H = d.sched_D0[k].rows();
863 std::vector<Matrix<double>> per_mark;
864 for (std::size_t c = 0; c < C; ++c) {
865 Matrix<double> m(H, H, 0.0);
866 for (std::size_t a = 0; a < H; ++a)
867 for (std::size_t b2 = 0; b2 < H; ++b2)
868 m(a, b2) = num_traits<T>::to_double(d.sched_Dmark[c][k](a, b2));
869 per_mark.push_back(m);
871 seg_mark_.push_back(per_mark);
880 if (d.has_batch_schedule()) {
881 const std::size_t C = d.sched_Dbatch.size();
882 const std::size_t B = d.sched_Dbatch[0].size();
883 for (std::size_t k = 0; k < d.sched_D0.size(); ++k) {
884 const std::size_t H = d.sched_D0[k].rows();
885 std::vector<std::vector<Matrix<double>>> per_mark;
886 for (std::size_t c = 0; c < C; ++c) {
887 std::vector<Matrix<double>> per_batch;
888 for (std::size_t b = 0; b < B; ++b) {
889 Matrix<double> m(H, H, 0.0);
890 for (std::size_t a = 0; a < H; ++a)
891 for (std::size_t b2 = 0; b2 < H; ++b2)
892 m(a, b2) = num_traits<T>::to_double(d.sched_Dbatch[c][b][k](a, b2));
893 per_batch.push_back(m);
895 per_mark.push_back(per_batch);
897 seg_batch_.push_back(per_mark);
900 cyclic_ = d.sched_cyclic;
901 has_schedule_ =
true;
903 if (!(mean_ > 0.0)) mean_ = num_traits<T>::to_double(d.mean);
908 double period()
const {
return bp_.back() - bp_.front(); }
918 double offset_at(
double t)
const {
919 double offset = t - bp_.front();
920 const double per = period();
922 offset = std::fmod(offset, per);
923 if (offset < 0.0) offset += per;
924 }
else if (offset < 0.0 || offset >= per) {
931 int segment_of(
double offset)
const {
932 const double pos = bp_.front() + offset;
933 for (std::size_t k = 0; k + 1 < bp_.size(); ++k)
934 if (pos < bp_[k + 1])
return static_cast<int>(k);
935 return static_cast<int>(segs_.size()) - 1;
939 int segment_at(
double t)
const {
940 const double offset = offset_at(t);
941 return (offset < 0.0) ? -1 : segment_of(offset);
955 double schedule_sample(Rng& g,
double from) {
956 const std::size_t H = segs_[0].order();
957 double offset = offset_at(from);
958 if (offset < 0.0)
return 0.0;
959 std::size_t idx =
static_cast<std::size_t
>(segment_of(offset));
960 double elapsed = 0.0;
961 for (
int guard = 0; guard < 1000000; ++guard) {
962 const double to_boundary = (bp_[idx + 1] - bp_.front()) - offset;
963 const mam::Map<double>& seg = segs_[idx];
964 const double total = -seg.D0(phase_, phase_);
966 const double holding = (total > 0.0) ? -std::log(
uniform01(g)) / total
967 : std::numeric_limits<double>::infinity();
968 if (holding >= to_boundary) {
970 if (idx >= segs_.size()) {
971 if (!cyclic_)
return 0.0;
974 elapsed += to_boundary;
982 offset = bp_[idx] - bp_.front();
998 if (!seg_mark_.empty()) {
999 const std::vector<Matrix<double>>& marks = seg_mark_[idx];
1004 const bool batched_here = !seg_batch_.empty();
1005 const std::size_t B = batched_here ? seg_batch_[idx][0].size() : std::size_t(1);
1006 for (std::size_t j = 0; j < H; ++j) {
1007 for (std::size_t c = 0; c < marks.size(); ++c) {
1008 if (!batched_here) {
1009 cum += marks[c](phase_, j);
1011 last_mark_ =
static_cast<int>(c) + 1;
1018 for (std::size_t b = 0; b < B; ++b) {
1019 cum += seg_batch_[idx][c][b](phase_, j);
1021 last_mark_ =
static_cast<int>(c) + 1;
1022 last_batch_ =
static_cast<int>(b) + 1;
1029 for (std::size_t j = 0; j < H; ++j) {
1030 if (j == phase_)
continue;
1031 cum += seg.D0(phase_, j);
1033 chosen =
static_cast<int>(H + j);
1040 for (std::size_t j = H; j-- > 0;)
1041 for (std::size_t c = marks.size(); c-- > 0;) {
1042 if (!batched_here) {
1043 if (marks[c](phase_, j) > 0.0) {
1044 last_mark_ =
static_cast<int>(c) + 1;
1051 for (std::size_t b = B; b-- > 0;)
1052 if (seg_batch_[idx][c][b](phase_, j) > 0.0) {
1053 last_mark_ =
static_cast<int>(c) + 1;
1054 last_batch_ =
static_cast<int>(b) + 1;
1063 phase_ =
static_cast<std::size_t
>(chosen) - H;
1066 for (std::size_t j = 0; j < 2 * H; ++j) {
1067 const double w = (j < H) ? seg.D1(phase_, j)
1068 : ((j - H == phase_) ? 0.0 : seg.D0(phase_, j - H));
1071 chosen =
static_cast<int>(j);
1076 for (std::size_t j = 2 * H; j-- > 0;) {
1077 const double w = (j < H) ? seg.D1(phase_, j)
1078 : ((j - H == phase_) ? 0.0 : seg.D0(phase_, j - H));
1080 chosen =
static_cast<int>(j);
1084 if (chosen <
static_cast<int>(H)) {
1085 phase_ =
static_cast<std::size_t
>(chosen);
1088 phase_ =
static_cast<std::size_t
>(chosen) - H;
1095 double mean_ = 0.0, scv_ = 1.0, rate_ = 0.0;
1096 double a_ = 0.0, b_ = 0.0;
1098 double erlang_rate_ = 0.0;
1099 std::vector<double> trace_;
1100 std::size_t trace_idx_ = 0;
1101 mam::Map<double> map_;
1102 std::vector<double> entry_;
1103 std::shared_ptr<mam::MeSampler<double>> me_;
1105 std::vector<std::vector<Matrix<double>>> seg_mark_;
1107 std::vector<Matrix<double>> mark_;
1110 std::vector<Matrix<double>> batch_;
1112 std::vector<std::vector<std::vector<Matrix<double>>>> seg_batch_;
1116 int last_batch_ = 0;
1117 bool has_phase_ =
false, phase_known_ =
false;
1120 bool has_schedule_ =
false, cyclic_ =
false;
1121 std::vector<double> bp_;
1122 std::vector<mam::Map<double>> segs_;
1123 std::size_t phase_ = 0;