163 std::size_t data_needed) {
164 const std::size_t K = data.size();
165 if (K == 0)
throw InputError(
"gibbs_analyse_data: no classes");
175 for (std::size_t k = 0; k < K; ++k) {
176 const std::size_t n = data[k].arrival_ms.size();
177 if (data[k].respt_s.size() != n)
178 throw InputError(
"gibbs_analyse_data: a class has mismatched sample counts");
179 for (std::size_t i = 0; i < n; ++i) {
181 a.t = data[k].arrival_ms[i];
186 for (std::size_t i = 0; i < n; ++i) {
188 d.t = T(data[k].arrival_ms[i] + data[k].respt_s[i] * thousand);
194 const std::size_t total = ev.size();
195 if (total == 0)
throw InputError(
"gibbs_analyse_data: empty traces");
198 std::stable_sort(ev.begin(), ev.end(),
199 [](
const Ev& a,
const Ev& b) { return a.t < b.t; });
203 for (std::size_t i = 0; i + 1 < total; ++i) {
204 for (std::size_t c = 0; c < K *
GIBBS_NNODES; ++c) count(i + 1, c) = count(i, c);
205 const std::size_t k = ev[i].cls;
206 const std::size_t from =
static_cast<std::size_t
>(ev[i].logger) - 1;
208 count(i + 1, from * K + k) -= 1;
209 count(i + 1, to * K + k) += 1;
214 for (std::size_t k = 0; k < K; ++k) {
216 for (std::size_t i = 0; i < total; ++i)
218 if (count(i, nd * K + k) > m) m = count(i, nd * K + k);
221 for (std::size_t i = 0; i < total; ++i)
222 for (std::size_t k = 0; k < K; ++k) count(i, k) += out.
N[k];
225 std::size_t burnin = 0;
226 if (data_needed != 0) {
227 if (total == data_needed)
229 "gibbs_analyse_data: the record is exactly data_needed events long, which MATLAB "
230 "indexes from zero");
231 if (total > data_needed) burnin = total - data_needed - 1;
236 std::map<std::vector<long>, T> acc;
237 for (std::size_t i = burnin; i < total; ++i) {
239 for (std::size_t c = 0; c < K *
GIBBS_NNODES; ++c) key[c] = count(i, c);
240 const T dt = i == 0 ? zero : T(ev[i].t - ev[i - 1].t);
241 typename std::map<std::vector<long>, T>::iterator it = acc.find(key);
243 acc.insert(std::make_pair(key, dt));
248 const T obs_length = ev[total - 1].t - ev[burnin].t;
249 if (obs_length <= zero)
throw NumericError(
"gibbs_analyse_data: the record has no duration");
252 out.
prob.assign(acc.size(), zero);
254 for (
typename std::map<std::vector<long>, T>::const_iterator it = acc.begin();
255 it != acc.end(); ++it, ++r) {
257 out.
prob[r] = it->second / obs_length;
260 out.
N0.assign(K, zero);
261 for (std::size_t k = 0; k < K; ++k) {
263 for (std::size_t i = 0; i < out.
prob.size(); ++i)
286 const std::vector<T>& N,
const T& logG_init,
double interval,
287 const T& range_size) {
289 "gibbs_slice requires transcendental arithmetic: it integrates "
290 "d log G / d theta along a grid in logarithms");
294 const std::size_t K = theta.size();
295 if (think_time.size() != K)
throw InputError(
"gibbs_slice: think_time has the wrong length");
296 if (N.size() != K)
throw InputError(
"gibbs_slice: N has the wrong length");
297 if (index >= K)
throw InputError(
"gibbs_slice: coordinate out of range");
299 throw InputError(
"gibbs_slice: testset has the wrong width");
303 const T eps = detail::gibbs_eps<T>();
307 const std::size_t n =
309 if (n == 0)
throw NumericError(
"gibbs_slice: the candidate grid collapsed to nothing");
310 out.
grid.assign(n, zero);
311 for (std::size_t i = 0; i < n; ++i)
313 out.
logG.assign(n, zero);
318 for (std::size_t i = 0; i < n && !found; ++i)
319 if (out.
grid[i] == theta[index]) {
326 for (std::size_t j = 0; j < K; ++j) L(0, j) = theta[j];
327 out.
logG[ip] = logG_init;
330 pfqn::pfqn_bs(L, N, think_time, std::vector<pfqn::AmvaSched>());
332 for (std::size_t i = ip; i-- > 0;) {
333 L(0, index) = out.
grid[i + 1];
334 res =
pfqn::pfqn_bs(L, N, think_time, std::vector<pfqn::AmvaSched>(), interval, 1000,
337 const T d = one - QN(0, index) / (out.
grid[i + 1] + eps) * step;
338 out.
logG[i] = d < zero ? out.
logG[i + 1] : T(out.
logG[i + 1] + log(d));
341 L(0, index) = theta[index];
342 res =
pfqn::pfqn_bs(L, N, think_time, std::vector<pfqn::AmvaSched>());
344 for (std::size_t i = ip + 1; i < n; ++i) {
345 L(0, index) = out.
grid[i - 1];
346 res =
pfqn::pfqn_bs(L, N, think_time, std::vector<pfqn::AmvaSched>(), interval, 1000,
349 const T d = one + QN(0, index) / (out.
grid[i - 1] + eps) * step;
350 out.
logG[i] = d < zero ? out.
logG[i - 1] : T(out.
logG[i - 1] + log(d));
357 for (std::size_t i = 0; i < testset.
rows(); ++i)
361 "gibbs_slice: no sampled state has a job of this class at the queue, so the slice "
362 "density is 0 log 0 at the first grid point and carries no information");
365 std::vector<T>
lp(n, zero);
366 for (std::size_t i = 0; i < n; ++i)
lp[i] = coeff * log(out.
grid[i]) - out.
logG[i] * nt;
368 for (std::size_t i = 1; i < n; ++i)
369 if (
lp[i] > mx) mx =
lp[i];
370 out.
prob.assign(n, zero);
372 for (std::size_t i = 0; i < n; ++i) {
373 out.
prob[i] = exp(T(
lp[i] - mx));
376 if (!(tot > zero))
throw NumericError(
"gibbs_slice: the slice has no mass");
377 for (std::size_t i = 0; i < n; ++i) out.
prob[i] = out.
prob[i] / tot;
383 for (std::size_t i = 0; i < n; ++i) {
406 "infer_gibbs requires transcendental arithmetic: it samples a slice of a "
407 "log density built from an iteratively integrated normalizing constant");
410 const std::size_t K = data.size();
411 if (K == 0)
throw InputError(
"infer_gibbs: no classes");
412 if (opts.
block == 0)
throw InputError(
"infer_gibbs: the convergence block must be positive");
414 if (!(opts.
tol > 0.0))
throw InputError(
"infer_gibbs: the tolerance must be positive");
420 const std::size_t ns = st.
prob.size();
424 for (std::size_t i = 0; i < ns; ++i) {
426 for (std::size_t k = 0; k < K; ++k) q += num_traits<T>::from_int(st.
states(i, K + k));
427 used += (q > nbCores ? nbCores : q) * st.
prob[i];
429 const T denom = one - st.
prob[ns - 1];
430 if (denom == zero)
throw NumericError(
"infer_gibbs: the record holds a single state");
433 std::vector<T> Nt(K, zero), think_time(K, zero);
434 for (std::size_t k = 0; k < K; ++k) {
436 if (data[k].think_obs.empty())
437 throw InputError(
"infer_gibbs: a class has no think-time observations");
439 for (std::size_t i = 0; i < data[k].think_obs.size(); ++i) s += data[k].think_obs[i];
441 if (m == zero)
throw NumericError(
"infer_gibbs: a class has a zero think-time mean");
442 think_time[k] = (Nt[k] - st.
N0[k]) / m;
443 if (!(think_time[k] > zero))
444 throw NumericError(
"infer_gibbs: a class has a non-positive think time");
448 std::vector<T> cum(ns, zero);
450 for (std::size_t i = 0; i < ns; ++i) {
457 std::size_t pick = ns;
458 for (std::size_t i = 0; i < ns; ++i)
464 throw NumericError(
"infer_gibbs: the empirical distribution does not sum to one");
465 for (std::size_t j = 0; j < K *
GIBBS_NNODES; ++j) testset(s, j) = st.
states(pick, j);
470 for (std::size_t k = 0; k < K; ++k) {
471 logG += Nt[k] * log(think_time[k]);
475 std::vector<T> range_size(K, one);
476 std::vector<T> theta(K, zero);
478 std::vector<T> demand_old(K, zero);
479 const std::size_t nblocks =
static_cast<std::size_t
>(
480 std::floor(
static_cast<double>(opts.
nsamples) /
static_cast<double>(opts.
block) + 0.5));
483 for (std::size_t b = 1; b <= nblocks; ++b) {
484 for (std::size_t s = 0; s < opts.
block && si < opts.
nsamples; ++s) {
485 for (std::size_t h = 0; h < K; ++h) {
488 for (std::size_t j = 0; j < h; ++j) theta[j] = smpl(si, j);
489 for (std::size_t j = h; j < K; ++j)
490 theta[j] = si == 0 ? zero : smpl(si - 1, j);
493 gibbs_slice(think_time, theta, testset, h, Nt, logG, opts.
tol, range_size[h]);
497 std::size_t pick = sl.
grid.size();
498 for (std::size_t i = 0; i < sl.
grid.size(); ++i) {
505 if (pick == sl.
grid.size()) {
508 smpl(si, h) = theta[h];
510 smpl(si, h) = sl.
grid[pick];
511 logG = sl.
logG[pick];
520 for (std::size_t k = 0; k < K; ++k) {
522 for (std::size_t i = opts.
block; i < si; ++i) s += smpl(i, k);
526 const std::size_t lo = (b - 1) * opts.
block;
527 std::vector<T> demand_now(K, zero);
531 for (std::size_t k = 0; k < K; ++k) {
533 for (std::size_t i = lo; i < si; ++i) s += smpl(i, k);
535 demand_now[k] = m / bp1 + demand_old[k] / bp1 * bb;
539 for (std::size_t k = 0; k < K; ++k) {
540 if (demand_old[k] == zero) {
544 rel +=
num_abs(T((demand_now[k] - demand_old[k]) / demand_old[k]));
548 demand_old = demand_now;
553 const std::size_t nb = si == 0 ? 0 : si - 1;
554 const std::size_t lo =
static_cast<std::size_t
>(
555 std::floor(
static_cast<double>(nb) / 2.0 + 0.5));
556 if (nb == 0 || lo >= nb)
throw NumericError(
"infer_gibbs: the chain produced no usable tail");
557 std::vector<T> demand(K, zero);
558 for (std::size_t k = 0; k < K; ++k) {
560 for (std::size_t i = lo; i < nb; ++i) s += smpl(i, k) * used;
GibbsSlice< T > gibbs_slice(const std::vector< T > &think_time, const std::vector< T > &theta, const Matrix< long > &testset, std::size_t index, const std::vector< T > &N, const T &logG_init, double interval, const T &range_size)
The deterministic half of one coordinate update: the log normalizing constant along the grid and the ...
AmvaResult< T > pfqn_bs(const Matrix< T > &L, const std::vector< T > &N, const std::vector< T > &Z, const std::vector< AmvaSched > &type, double tol=1e-6, std::size_t maxiter=1000, const Matrix< T > &QN0=Matrix< T >())
Bard-Schweitzer approximate MVA.