5#ifndef LINE_SOLVERS_ENV_SOLVER_ENV_MEANFIELD_H
6#define LINE_SOLVERS_ENV_SOLVER_ENV_MEANFIELD_H
110 std::string
da =
"courtois";
140namespace meanfield_detail {
143inline void refuse_inexact(
const std::string&
da) {
145 "SolverENV compression: the '" +
da +
146 "' decomposition needs transcendental arithmetic, because every one of ctmc_courtois, "
147 "ctmc_kms, ctmc_takahashi and ctmc_multi reports epsMAX, a subdominant eigenvalue "
148 "modulus with no rational closed form; rerun with --arith double or real");
152inline void check_partition(
const MacroPartition& MS, std::size_t n) {
153 std::vector<bool> seen(n,
false);
154 std::size_t total = 0;
155 for (
const std::vector<std::size_t>& blk : MS) {
156 if (blk.
empty())
throw InputError(
"SolverENV compression: a macro-state is empty");
157 for (std::size_t s : blk) {
159 throw InputError(
"SolverENV compression: a macro-state names stage " +
160 std::to_string(s + 1) +
", which does not exist");
162 throw InputError(
"SolverENV compression: stage " + std::to_string(s + 1) +
163 " appears in more than one macro-state");
170 "SolverENV compression: the macro-states must cover every stage; the partition "
172 std::to_string(total) +
" of " + std::to_string(n));
178 for (std::size_t i = 0; i < E; ++i) MS[i] = std::vector<std::size_t>{i};
185 out.reserve(ms.size() - 1);
186 for (std::size_t k = 0; k < ms.size(); ++k) {
188 std::vector<std::size_t> m = ms[i];
189 m.insert(m.end(), ms[j].begin(), ms[j].end());
192 out.push_back(ms[k]);
211 meanfield_detail::check_partition(MS, Q.
rows());
214 meanfield_detail::refuse_inexact(
opt.da);
219 for (std::size_t i = 0; i < Q.
rows(); ++i)
220 for (std::size_t j = 0; j < Q.
cols(); ++j) {
221 const T a =
num_abs(T(Q(i, j)));
222 if (a > qmax) qmax = a;
226 if (
opt.da ==
"courtois") {
232 }
else if (
opt.da ==
"kms") {
238 }
else if (
opt.da ==
"takahashi") {
244 }
else if (
opt.da ==
"multi") {
250 for (std::size_t i = 0; i < MS.size(); ++i) MSS[i] = std::vector<std::size_t>{i};
258 "SolverENV compression: unknown decomposition '" +
opt.da +
259 "'; options.config.da is one of courtois, kms, takahashi, multi");
277 const std::size_t E = e.
nstages();
279 for (std::size_t a = 0; a < E; ++a)
280 for (std::size_t b = 0; b < E; ++b)
281 if (e.
arc(a, b).enabled) E0(a, b) = e.
arc(a, b).dist.rate();
298 const std::size_t E = Eutil.
rows();
302 if (std::isnan(best_eps))
return best;
304 for (std::size_t i = 0; i < E; ++i)
305 for (std::size_t j = i + 1; j < E; ++j) {
307 meanfield_detail::merge_blocks(meanfield_detail::singletons(E), i, j);
310 if (!std::isnan(te) && te < best_eps) {
334 const std::size_t E = Eutil.
rows();
335 std::vector<MacroPartition> beam{meanfield_detail::singletons(E)};
339 for (std::size_t depth = 1; depth < E; ++depth) {
340 std::vector<std::pair<double, MacroPartition>> cand;
342 for (std::size_t i = 0; i < ms.size(); ++i)
343 for (std::size_t j = i + 1; j < ms.size(); ++j) {
344 const MacroPartition trial = meanfield_detail::merge_blocks(ms, i, j);
347 if (std::isnan(te) || !(te > 0.0))
continue;
349 opt.env_alpha *
static_cast<double>(depth);
350 cand.push_back(std::make_pair(cost, trial));
351 if (cost < best_cost) {
357 if (cand.empty())
break;
360 std::stable_sort(cand.begin(), cand.end(),
361 [](
const std::pair<double, MacroPartition>& a,
362 const std::pair<double, MacroPartition>& b) { return a.first < b.first; });
364 for (std::size_t i = 0; i <
opt.beam_width && i < cand.size(); ++i)
365 beam.push_back(cand[i].second);
381 std::shared_ptr<Environment<T>>
env;
407 const std::size_t E = e0.
nstages();
415 "SolverENV compression",
416 "a macro-state is built as one stage network carrying the pmicro-weighted average of "
417 "its members' station rates, and a layered model has no such rate table -- only the "
418 "layers SolverLN derives from it");
424 for (std::size_t a = 0; a < E; ++a)
425 for (std::size_t b = 0; b < E; ++b) {
426 if (!e0.
arc(a, b).enabled)
continue;
429 "SolverENV compression: the transition from stage " + std::to_string(a + 1) +
430 " to " + std::to_string(b + 1) +
431 " is not exponential, and the NCD decomposition reads the environment as a "
432 "CTMC through E0 = getRate(); aggregating it would silently replace the "
433 "transition by an exponential of the same mean, so it is refused instead");
440 if (!
opt.partition.empty()) {
441 meanfield_detail::check_partition(
opt.partition, E);
442 c.
MS =
opt.partition;
443 }
else if (E <=
opt.beam_above_stages) {
448 const std::size_t Ec = c.
MS.size();
460 c.
pmacro.assign(Ec, zero);
461 for (std::size_t i = 0; i < Ec; ++i)
462 for (std::size_t s : c.
MS[i]) c.
pmacro[i] += c.
p[s];
464 for (std::size_t i = 0; i < Ec; ++i) {
472 for (std::size_t i = 0; i < Ec; ++i)
473 for (std::size_t j = 0; j < Ec; ++j)
474 for (std::size_t mi : c.
MS[i])
479 for (std::size_t x = 0; x < Ec; ++x) {
481 for (std::size_t h = 0; h < Ec; ++h)
485 if (!(tot > 0.0))
continue;
486 for (std::size_t k = 0; k < Ec; ++k) {
487 if (k == x)
continue;
495 c.
env = std::make_shared<Environment<T>>(e0.
name() +
"-compressed", Ec);
496 for (std::size_t i = 0; i < Ec; ++i) {
497 const std::size_t first = c.
MS[i][0];
499 const std::size_t M =
sn.nstations, K =
sn.nclasses;
500 for (std::size_t s : c.
MS[i])
501 if (e0.
stage(s).model.nstations != M || e0.
stage(s).model.nclasses != K)
503 "SolverENV compression: macro-state " + std::to_string(i + 1) +
504 " merges stages with different stations or classes, whose rates cannot be "
505 "averaged entrywise");
506 for (std::size_t m = 0; m < M; ++m) {
512 for (std::size_t k = 0; k < K; ++k) {
514 for (std::size_t s : c.
MS[i])
515 acc += T(c.
pmicro[s] * e0.
stage(s).model.rates(m, k));
520 c.
env->set_stage(i, e0.
stage(first).name +
"+", e0.
stage(first).type,
sn);
523 for (std::size_t i = 0; i < Ec; ++i) {
524 bool any_out =
false;
525 for (std::size_t j = 0; j < Ec; ++j) {
526 if (i == j)
continue;
533 const std::size_t fi = c.
MS[i][0],
fj = c.
MS[j][0];
534 const bool want =
static_cast<bool>(e0.
arc(fi,
fj).reset);
535 for (std::size_t a : c.
MS[i])
536 for (std::size_t b : c.
MS[j])
537 if (e0.
arc(a, b).enabled &&
static_cast<bool>(e0.
arc(a, b).reset) != want)
539 "SolverENV compression: the arcs folding into the macro transition " +
540 std::to_string(i + 1) +
" -> " + std::to_string(j + 1) +
541 " do not agree on whether a reset policy applies, and one macro arc "
542 "can carry only one; split the partition so that reset policies are "
543 "uniform within it");
545 e0.
arc(fi,
fj).reset);
550 "SolverENV compression: macro-state " + std::to_string(i + 1) +
551 " has no outgoing transition, so the compressed environment is absorbing; the "
552 "partition merged a whole recurrent class into one block");
577 const std::size_t Ec = c.
MS.size();
580 "SolverENV compression: the macro probabilities do not match the environment they "
581 "are being applied to");
610namespace meanfield_detail {
615 std::vector<std::size_t> out;
616 for (std::size_t ind = 0; ind <
sn.nodes.size(); ++ind)
628std::vector<T> hit_by_list(
const std::vector<T>& xbar,
const Matrix<T>& lam, std::size_t k) {
630 if (xbar.empty() || lam.
rows() == 0 || k >= lam.
rows())
return hbl;
631 const std::size_t nitems = lam.
cols();
632 if (nitems == 0 || xbar.size() % nitems != 0)
return hbl;
633 const std::size_t lists = xbar.size() / nitems;
634 if (lists < 2)
return hbl;
635 const std::size_t h = lists - 1;
636 std::vector<double> wpop(nitems, 0.0);
638 for (std::size_t i = 0; i < nitems; ++i) {
640 wpop[i] = std::isfinite(v) ? v : 0.0;
643 if (!(tot > 0.0))
return hbl;
644 hbl.assign(h, num_traits<T>::from_int(0));
645 for (std::size_t l = 1; l <= h; ++l) {
646 T acc = num_traits<T>::from_int(0);
647 for (std::size_t i = 0; i < nitems; ++i)
648 acc = T(acc + T(num_traits<T>::from_double(wpop[i] / tot) * xbar[i + l * nitems]));
649 double v = num_traits<T>::to_double(acc);
650 v = std::max(0.0, std::min(1.0, v));
651 hbl[l - 1] = num_traits<T>::from_double(v);
680solvers::CacheMetrics<T> aggregate_cache_meanfield(Environment<T>& e,
const EnvOptions& o) {
681 solvers::CacheMetrics<T> out;
682 const std::size_t E = e.nstages();
683 if (E == 0)
return out;
687 if (e.has_lqn_stages())
return out;
688 const qn::NetworkStruct<T>& sn1 = e.stage(0).model;
689 const std::vector<std::size_t> nodes = cache_nodes_of(sn1);
690 if (nodes.empty())
return out;
691 const std::size_t nc = nodes.size(), K = sn1.nclasses;
697 if (o.stage_solver !=
"fluid")
return out;
701 std::vector<double> tend(E, 0.0);
702 for (std::size_t s = 0; s < E; ++s) {
703 double t1 = o.timespan_end;
704 if (!std::isfinite(t1) || !(t1 > 0.0)) t1 = 20.0 *
mam::map_mean(e.hold_time[s].map());
708 std::vector<std::vector<std::vector<T> > > entry(E, std::vector<std::vector<T> >(nc));
709 std::vector<std::vector<fluid::FluidCacheqnTranCache<T> > > tran(E);
710 std::vector<std::vector<std::vector<T> > > exit_occ(E, std::vector<std::vector<T> >(nc));
711 std::vector<T> prev_flat;
712 const int sweeps = o.iter_max > 0 ? o.iter_max : 1;
714 for (
int sweep = 0; sweep < sweeps; ++sweep) {
715 for (std::size_t s = 0; s < E; ++s) {
716 fluid::FluidOptions fo;
721 const auto hm = e.hold_time[s].map();
723 Matrix<T> hD0(hm.D0.rows(), hm.D0.cols(), num_traits<T>::from_int(0));
724 for (std::size_t i = 0; i < hm.D0.rows(); ++i)
725 for (std::size_t j = 0; j < hm.D0.cols(); ++j)
726 hD0(i, j) = num_traits<T>::from_double(hm.D0(i, j));
727 std::vector<T> hpieT(hpie.size());
728 for (std::size_t i = 0; i < hpie.size(); ++i) hpieT[i] = num_traits<T>::from_double(hpie[i]);
731 for (std::size_t c = 0; c < nc; ++c) {
732 exit_occ[s][c].clear();
733 std::size_t idx = tran[s].size();
734 for (std::size_t q = 0; q < tran[s].size(); ++q)
735 if (tran[s][q].node == nodes[c]) idx = q;
736 if (idx == tran[s].size())
continue;
737 const fluid::FluidCacheqnTranCache<T>& tc = tran[s][idx];
738 if (tc.sojourn.empty() || !(num_traits<T>::to_double(tc.sojourn.wtot) > 0.0))
continue;
739 exit_occ[s][c] = tc.sojourn.xbar;
744 std::vector<std::vector<std::vector<T> > > next(E, std::vector<std::vector<T> >(nc));
745 for (std::size_t s = 0; s < E; ++s)
746 for (std::size_t c = 0; c < nc; ++c) {
748 for (std::size_t h = 0; h < E; ++h) {
749 const double po = e.prob_orig(h, s);
750 if (!(po > 0.0) || exit_occ[h][c].empty())
continue;
751 if (acc.empty()) acc.assign(exit_occ[h][c].size(), num_traits<T>::from_int(0));
752 if (acc.size() != exit_occ[h][c].size())
continue;
753 for (std::size_t a = 0; a < acc.size(); ++a)
754 acc[a] = T(acc[a] + T(num_traits<T>::from_double(po) * exit_occ[h][c][a]));
760 for (std::size_t s = 0; s < E; ++s)
761 for (std::size_t c = 0; c < nc; ++c)
762 flat.insert(flat.end(), next[s][c].begin(), next[s][c].end());
764 if (!prev_flat.empty() && prev_flat.size() == flat.size()) {
766 for (std::size_t a = 0; a < flat.size(); ++a)
767 dmax = std::max(dmax, std::fabs(num_traits<T>::to_double(flat[a]) -
768 num_traits<T>::to_double(prev_flat[a])));
770 if (dmax < o.iter_tol)
break;
776 const T nan = num_traits<T>::from_double(std::numeric_limits<double>::quiet_NaN());
777 std::vector<std::vector<T> > hitprob(nc, std::vector<T>(K, nan));
778 std::vector<std::vector<T> > missprob(nc, std::vector<T>(K, nan));
779 std::vector<Matrix<T> > hitproblist(nc);
780 for (std::size_t c = 0; c < nc; ++c) {
781 std::vector<T> hitT(K, num_traits<T>::from_int(0)), missT(K, num_traits<T>::from_int(0));
783 for (std::size_t s = 0; s < E; ++s) {
784 std::size_t idx = tran[s].size();
785 for (std::size_t q = 0; q < tran[s].size(); ++q)
786 if (tran[s][q].node == nodes[c]) idx = q;
787 if (idx == tran[s].size())
continue;
788 const fluid::FluidCacheqnTranCache<T>& tc = tran[s][idx];
789 const double sw = num_traits<T>::to_double(tc.sojourn.wtot);
790 if (tc.sojourn.empty() || !std::isfinite(sw) || !(sw > 0.0))
continue;
791 const T pe = num_traits<T>::from_double(e.prob_env[s]);
794 const std::vector<T>& xbar = tc.sojourn.xbar;
795 for (std::size_t k = 0; k < K && k < tc.arate.size(); ++k) {
796 if (!(num_traits<T>::to_double(tc.arate[k]) > 0.0))
continue;
798 const T hbar = tc.hitprob_bar[k], mbar = tc.missprob_bar[k];
799 hitT[k] = T(hitT[k] + T(T(pe * tc.arate[k]) * hbar));
800 missT[k] = T(missT[k] + T(T(pe * tc.arate[k]) * mbar));
801 const std::vector<T> hbl = hit_by_list(xbar, tc.lam, k);
802 if (hbl.empty())
continue;
803 if (hitLT.rows() == 0) hitLT =
Matrix<T>(K, hbl.size(), num_traits<T>::from_int(0));
804 for (std::size_t l = 0; l < hbl.size() && l < hitLT.cols(); ++l)
805 hitLT(k, l) = T(hitLT(k, l) + T(T(pe * tc.arate[k]) * hbl[l]));
808 if (hitLT.rows() > 0) hitproblist[c] =
Matrix<T>(K, hitLT.cols(), nan);
809 for (std::size_t k = 0; k < K; ++k) {
810 const T tot = T(hitT[k] + missT[k]);
811 if (num_traits<T>::to_double(tot) > 0.0) {
812 hitprob[c][k] = T(hitT[k] / tot);
813 missprob[c][k] = T(missT[k] / tot);
814 for (std::size_t l = 0; l < hitLT.cols(); ++l)
815 hitproblist[c](k, l) = T(hitLT(k, l) / tot);
820 for (std::size_t k = 0; k < hitproblist[c].rows() && !any; ++k)
821 for (std::size_t l = 0; l < hitproblist[c].cols(); ++l)
822 if (std::isfinite(num_traits<T>::to_double(hitproblist[c](k, l)))) any =
true;
833 std::vector<T>(), Matrix<T>(), Matrix<T>(), std::vector<T>());
834 for (std::size_t c = 0; c < nc && c < out.caches.size(); ++c) {
835 out.caches[c].hitprob = hitprob[c];
836 out.caches[c].missprob = missprob[c];
837 if (hitproblist[c].rows() > 0) out.caches[c].hitproblist = hitproblist[c];
844bool env_has_cache_stage(
const Environment<T>& e) {
845 for (std::size_t s = 0; s < e.nstages(); ++s) {
848 if (e.is_lqn(s))
continue;
849 if (!cache_nodes_of(e.stage(s).model).empty())
return true;
855inline const char* substitute_cache_blend_warning() {
856 return "The mean-field cache fixed point requires fluid stage solvers; blending each stage's "
857 "own cache ratios instead, without the occupancy handoff across environment switches.";
868solvers::CacheMetrics<T> substitute_cache_blend(
const Environment<T>& e,
const EnvOptions& o) {
869 typename SolverEnvLimit<T>::CacheAccum acc;
870 for (std::size_t s = 0; s < e.nstages(); ++s) {
871 if (e.is_lqn(s))
continue;
872 const qn::NetworkStruct<T>& sn = e.stage(s).model;
874 acc.add(sn, st, e.prob_env[s]);
876 const solvers::CacheMetrics<double> c = acc.finish();
877 solvers::CacheMetrics<T> out;
878 for (std::size_t i = 0; i < c.caches.size(); ++i) {
879 const solvers::CacheNodeMetrics<double>& m = c.caches[i];
880 solvers::CacheNodeMetrics<T> w;
883 w.itemcap = m.itemcap;
885 for (std::size_t k = 0; k < m.hitprob.size(); ++k)
886 w.hitprob.push_back(num_traits<T>::from_double(m.hitprob[k]));
887 for (std::size_t k = 0; k < m.missprob.size(); ++k)
888 w.missprob.push_back(num_traits<T>::from_double(m.missprob[k]));
889 for (std::size_t k = 0; k < m.delayedprob.size(); ++k)
890 w.delayedprob.push_back(num_traits<T>::from_double(m.delayedprob[k]));
891 if (m.hitproblist.rows() > 0) {
892 w.hitproblist =
Matrix<T>(m.hitproblist.rows(), m.hitproblist.cols());
893 for (std::size_t r = 0; r < m.hitproblist.rows(); ++r)
894 for (std::size_t l = 0; l < m.hitproblist.cols(); ++l)
895 w.hitproblist(r, l) = num_traits<T>::from_double(m.hitproblist(r, l));
897 out.caches.push_back(w);
907void meanfield_cache(Environment<T>& e,
const EnvOptions& o, EnvMeanfieldSolution<T>& out) {
908 if (o.stage_solver ==
"fluid" || e.has_lqn_stages() || !env_has_cache_stage(e)) {
909 out.cache = aggregate_cache_meanfield(e, o);
912 out.cache_warning = substitute_cache_blend_warning();
913 out.cache = substitute_cache_blend(e, o);
924 meanfield_detail::meanfield_cache(e, o, out);
946 meanfield_detail::meanfield_cache(*out.
compression.env, o, out);
What a solver observed about the Cache nodes of a model.
UnsupportedError(const std::string &what)
const std::string & name() const
const EnvStage< T > & stage(std::size_t e) const
Matrix< double > prob_orig
probOrig(h, e)
std::size_t nstages() const
void reject_lqn_stages(const std::string &who, const std::string &why) const
Refuse an environment carrying a LayeredNetwork stage, by name.
const EnvArc< T > & arc(std::size_t e, std::size_t h) const
std::vector< double > prob_env
probEnv
static EnvStageAvg< T > ctmc_stage_steady(const qn::NetworkStruct< T > &sn, double cutoff)
One stage in steady state under the enumerated CTMC at cutoff, with its cache split,...
A network plus its refreshed NetworkStruct.
Courtois decomposition of a nearly completely decomposable (NCD) CTMC.
Koury-McAllister-Stewart aggregation-disaggregation for a nearly completely decomposable CTMC.
Two-level multigrid aggregation-disaggregation for a nearly completely decomposable CTMC.
Steady-state distribution of a continuous-time Markov chain.
Takahashi's aggregation-disaggregation for a nearly completely decomposable CTMC.
A random environment: a port of matlab/src/lang/Environment.m, restricted to what SolverENV reads out...
The exception types the port throws.
The INTEGRATED caching-queueing network under the fluid solver: ports of solver_fld_cacheqn_analyzer....
Cumulative distribution of the inter-arrival time of a MAP.
Markovian arrival process descriptors: stationary vectors, rate, moments, autocorrelation and the ind...
Dense matrix and non-owning view.
std::vector< std::vector< std::size_t > > MacroPartition
A partition of the stage indices 0..E-1 into macro-states, MATLAB's MS.
EnvDecomp< T > env_ctmc_decompose(const Matrix< T > &Q, const MacroPartition &MS, const EnvCompressOptions &opt)
Port of SolverENV.ctmc_decompose: one NCD decomposition, by whichever kernel options....
MacroPartition env_beam_search_partition(const Matrix< T > &Eutil, const EnvCompressOptions &opt)
Port of beamSearchPartition, the large-environment search: repeatedly merge two blocks,...
MacroPartition env_find_best_partition(const Matrix< T > &Eutil, const EnvCompressOptions &opt)
Port of findBestPartition, the small-environment search.
Matrix< T > env_rate_matrix(const Environment< T > &e)
E0, the environment's rate matrix: E0(e,h) = env{e,h}.getRate().
EnvMeanfieldSolution< T > solver_env_meanfield(Environment< T > &e, const EnvOptions &o)
The mean-field solve on the original stages, with no compression.
EnvCompression< T > env_compress(const Environment< T > &e0, const EnvCompressOptions &opt)
Port of applyCompression: pick a partition, decompose, and build the macro-state environment.
void env_apply_macro_probabilities(Environment< T > &e, const EnvCompression< T > &c)
probEnv = pMacro and probOrig = newEmbweight, the two quantities applyCompression overwrites on the e...
std::vector< FluidCacheqnTranCache< T > > solver_fld_cacheqn_tran(const qn::NetworkStruct< T > &sn, const FluidOptions &opt, double t0, double t1, const std::vector< std::vector< T > > &x0cell=std::vector< std::vector< T > >(), const Matrix< T > &hold_D0=Matrix< T >(), const std::vector< T > &hold_pie=std::vector< T >())
Port of solver_fld_cacheqn_tran.m: the transient counterpart of the analyzer above.
NodeType
Node kinds, with the values of MATLAB NodeType.
T map_mean(const Map< T > &m)
Mean inter-arrival time, 1/lambda.
std::vector< T > map_pie(const Map< T > &m)
Phase distribution seen by an arriving job, pie = pi D1 / (pi D1 e).
Matrix< T > ctmc_makeinfgen(const Matrix< T > &Q)
Set the diagonal so that every row sums to zero (ctmc_makeinfgen).
KmsResult< T > ctmc_kms(const Matrix< T > &Q, const std::vector< std::vector< std::size_t > > &MS, std::size_t numSteps)
Koury-McAllister-Stewart aggregation-disaggregation for a nearly completely decomposable CTMC.
TakahashiResult< T > ctmc_takahashi(const Matrix< T > &Q, const std::vector< std::vector< std::size_t > > &MS, std::size_t numSteps, double massTol=1e-14)
Takahashi's aggregation-disaggregation for a nearly completely decomposable CTMC.
MultiResult< T > ctmc_multi(const Matrix< T > &Q, const std::vector< std::vector< std::size_t > > &MS, const std::vector< std::vector< std::size_t > > &MSS, const T &q)
Two-level multigrid aggregation-disaggregation for a nearly completely decomposable CTMC.
CourtoisResult< T > ctmc_courtois(const Matrix< T > &Q, const std::vector< std::vector< std::size_t > > &MS, const T &q)
Courtois decomposition of a nearly completely decomposable (NCD) CTMC.
CacheMetrics< T > cache_metrics_of(const qn::NetworkStruct< T > &sn, const std::vector< T > &hitprob, const std::vector< T > &missprob, const std::vector< T > &delayedprob, const std::vector< T > &latency, const Matrix< T > &hitproblist, const Matrix< T > &itemprob, const std::vector< T > &listcost)
Assemble CacheMetrics from what a cache analyzer returned.
Conservation laws of a layered queueing network, enumerated from its structure.
A queueing network and its refreshed NetworkStruct.
Number-type abstraction for the templated API port.
SolverENV: a queueing network in a random environment.
The two CLOSED-FORM environment limits: SolverENV.solveEnvLimit, reached by options....
The knobs applyCompression reads out of options.config.
MacroPartition partition
A partition supplied by the caller, which SKIPS the search entirely.
double env_alpha
options.config.env_alpha: the beam search's per-depth merge penalty.
std::size_t beam_above_stages
Stage count above which the reference switches from the pairwise search to the beam search.
std::string da
options.config.da: courtois (the reference's default), kms, takahashi, multi.
std::size_t beam_width
Beam width, the reference's hard-coded B = 3.
std::size_t da_iter
options.config.da_iter: sweeps for the two iterative kernels.
Everything applyCompression computes, plus the compressed environment.
std::vector< T > pmicro
within-macro-state conditional probabilities
std::vector< T > pmacro
pMacro, the macro-state probabilities
bool compressible
eps <= epsMAX: below this the aggregation is meaningful, above it is not.
Matrix< T > macro_rate
computeMacroRate(i,j)
std::vector< T > p
micro stationary vector from the decomposition
Matrix< double > prob_orig
the macro embedding weights newEmbweight
std::shared_ptr< Environment< T > > env
The compressed environment.
What SolverENV.ctmc_decompose returns: [p, eps, epsMax, q].
std::vector< T > p
approximate stationary vector of the environment
A mean-field solve, with the compression that produced it.
std::string cache_warning
The reference's substituteCacheBlend_ warning, verbatim; empty when it did not run.
solvers::CacheMetrics< T > cache
aggregateCacheMeanfield_: environment-blended hit and miss probabilities per Cache node.
EnvCompression< T > compression
bool compressed
false when the solve ran on the original stages
EnvSolution avg
what SolverEnv reported
static Distrib exp_rate(const T &r)
T q
uniformization rate used
T eps
NCD index: largest ROW sum of B, ||B||_inf (MATLAB and the JAR).
std::vector< T > p
approximate stationary vector, ORIGINAL state ordering
T epsMAX
(1 - max subdominant block eigenvalue modulus) / 2
T epsMAX
maximum admissible NCD index
T eps
NCD index, as ctmc_courtois defines it.
std::vector< T > p
estimate after numSteps sweeps, ORIGINAL ordering
std::vector< T > p
approximate stationary vector, ORIGINAL ordering
T eps
NCD index of the fine level.
T epsMAX
maximum admissible NCD index of the fine level
T eps
NCD index, as ctmc_courtois defines it.
T epsMAX
maximum admissible NCD index
std::vector< T > p
estimate after numSteps sweeps
Every Cache node of the model, in node order; empty on a model with none.