5#ifndef LINE_SOLVERS_CTMC_SOLVER_CTMC_GETTERS_H
6#define LINE_SOLVERS_CTMC_SOLVER_CTMC_GETTERS_H
68 std::vector<Matrix<T>>
filt;
167 return d.
avg.PreemptN;
170namespace getters_detail {
174std::vector<std::size_t> node_widths(
const std::vector<NetState<T>>& space) {
175 std::vector<std::size_t> w;
176 if (space.empty())
return w;
177 for (std::size_t f = 0; f < space[0].local.size(); ++f) w.push_back(space[0].local[f].size());
183Matrix<T> flatten(
const std::vector<NetState<T>>& space) {
184 const std::vector<std::size_t> w = node_widths(space);
185 std::size_t total = 0;
186 for (std::size_t f = 0; f < w.size(); ++f) total += w[f];
187 Matrix<T> out(space.size(), total, num_traits<T>::from_int(0));
188 for (std::size_t s = 0; s < space.size(); ++s) {
190 for (std::size_t f = 0; f < space[s].local.size(); ++f)
191 for (std::size_t j = 0; j < space[s].local[f].size(); ++j) out(s, c++) = space[s].local[f][j];
204std::vector<Matrix<T>> local_spaces(
const std::vector<NetState<T>>& space) {
205 std::vector<Matrix<T>> out;
206 if (space.empty())
return out;
207 const std::size_t NF = space[0].local.size();
208 for (std::size_t f = 0; f < NF; ++f) {
209 std::vector<std::vector<T>> rows;
210 std::set<std::vector<double>> seen;
211 for (std::size_t s = 0; s < space.size(); ++s) {
212 if (space[s].local.size() <= f)
continue;
213 const std::vector<T>& r = space[s].local[f];
214 std::vector<double> key(r.size());
215 for (std::size_t j = 0; j < r.size(); ++j) key[j] = num_traits<T>::to_double(r[j]);
216 if (!seen.insert(key).second)
continue;
219 const std::size_t w = rows.empty() ? 0 : rows[0].size();
220 Matrix<T> m(rows.size(), w, num_traits<T>::from_int(0));
221 for (std::size_t i = 0; i < rows.size(); ++i)
222 for (std::size_t j = 0; j < w && j < rows[i].size(); ++j) m(i, j) = rows[i][j];
236std::size_t stateful_or_throw(
const NetworkStruct<T>& sn, std::size_t ind,
const char* what) {
237 if (ind < 1 || ind > sn.nodes.size())
238 throw InputError(std::string(what) +
": the node index is out of range");
239 const std::size_t isf = sn.stateful_index(ind);
242 ": node " + std::to_string(ind) +
243 " is stateless and holds no block of the network state");
255void check_timespan(
const T& t0,
const T& t1,
const char* what) {
256 const double a = num_traits<T>::to_double(t0), b = num_traits<T>::to_double(t1);
257 if (!std::isfinite(a) || !std::isfinite(b) || !(b > a))
259 " requires a finite timespan [t0, t1] with t1 > t0; for the limit as t "
260 "grows use the stationary family (getProb, getProbAggr, getProbSys, "
276 if (d.
chain.filt.empty())
278 "ctmc_get_generator: the solution carries no event filtration, which cannot be "
279 "recovered from Q because its entries have already summed every synchronization's "
280 "contribution; re-solve with CtmcOptions::keep_filtration = true");
330 s.
flat = getters_detail::flatten(d.
chain.space);
332 s.
local = getters_detail::local_spaces(d.
chain.space);
345 std::vector<double>
t;
346 std::vector<double>
F;
347 std::vector<double>
f;
355namespace getters_detail {
366 std::set<std::size_t> idx;
367 if (S.
rows() == 0 || S.
cols() == 0)
return std::vector<std::size_t>();
368 const std::size_t n = flat.
rows();
369 bool is_index_vector = (S.
rows() == 1 || S.
cols() == 1);
370 if (is_index_vector) {
371 for (std::size_t i = 0; i < S.
rows() && is_index_vector; ++i)
372 for (std::size_t j = 0; j < S.
cols(); ++j) {
373 const double v = S(i, j);
374 if (v != std::floor(v) || v < 1 || v >
static_cast<double>(n)) {
375 is_index_vector =
false;
380 if (is_index_vector) {
381 for (std::size_t i = 0; i < S.
rows(); ++i)
382 for (std::size_t j = 0; j < S.
cols(); ++j)
383 idx.insert(
static_cast<std::size_t
>(S(i, j)) - 1);
386 throw InputError(std::string(
"getCdfFirstPassT: a state row in set ") + name +
387 " has " + std::to_string(S.
cols()) +
" columns where the state "
388 "space has " + std::to_string(flat.
cols()));
389 for (std::size_t i = 0; i < S.
rows(); ++i) {
391 for (std::size_t r = 0; r < n && !found; ++r) {
393 for (std::size_t j = 0; j < S.
cols() && eq; ++j)
401 throw InputError(std::string(
"A state given in set ") + name +
402 " is not in the state space.");
405 return std::vector<std::size_t>(idx.begin(), idx.end());
441 const std::string& method =
"expm") {
443 "getCdfFirstPassT takes a matrix exponential and therefore requires an "
444 "arithmetic with transcendental functions");
446 const std::size_t n = Q.
rows();
450 out.
target = getters_detail::resolve_state_set(B, flat,
"B");
453 "The target state set B is empty: a first passage time into no state is undefined.");
454 out.
source = getters_detail::resolve_state_set(A, flat,
"A");
455 const std::vector<std::size_t> Cidx = getters_detail::resolve_state_set(C, flat,
"C");
458 if (!out.
source.empty()) {
461 static_cast<long>(out.
source.size()));
462 for (std::size_t idx : out.
source) pi0[idx] = w;
468 double min_rate = std::numeric_limits<double>::infinity();
469 for (std::size_t i = 0; i < n; ++i)
470 for (std::size_t j = 0; j < n; ++j) {
474 const double thor = std::abs(100.0 / min_rate);
475 tset.assign(1000, 0.0);
476 for (std::size_t i = 0; i < tset.size(); ++i)
477 tset[i] = thor *
static_cast<double>(i) /
static_cast<double>(tset.size() - 1);
482 std::vector<double> tfin, tinf;
483 for (
double v : tset) (std::isinf(v) ? tinf : tfin).push_back(v);
487 out.
F.assign(tset.size(), 0.0);
488 out.
f.assign(tset.size(), 0.0);
489 std::size_t a = 0, b = 0;
490 for (std::size_t i = 0; i < tset.size(); ++i) {
491 if (std::isinf(tset[i])) {
492 out.
F[i] = pt.
F[b++];
494 out.
F[i] = curve.
F[a];
495 out.
f[i] = curve.
f[a++];
516 const std::string& method =
"expm") {
525 const std::string& method =
"expm") {
533 const std::string& method =
"expm") {
577 "getFirstPassTMoments marks an unreachable target with an infinity and "
578 "therefore requires an arithmetic that has one");
580 const std::size_t n = Q.
rows();
584 out.
target = getters_detail::resolve_state_set(B, flat,
"B");
587 "The target state set B is empty: a first passage time into no state is undefined.");
588 out.
source = getters_detail::resolve_state_set(A, flat,
"A");
589 const std::vector<std::size_t> Cidx = getters_detail::resolve_state_set(C, flat,
"C");
592 if (!out.
source.empty()) {
595 static_cast<long>(out.
source.size()));
596 for (std::size_t idx : out.
source) pi0[idx] = w;
611 for (std::size_t c : Cidx)
612 if (!std::binary_search(out.
target.begin(), out.
target.end(), c))
613 out.
taboo.push_back(c);
624 std::size_t nmax = 3) {
645 std::size_t nmax = 3) {
670namespace getters_detail {
688Matrix<T> node_marginal_labels(
const NetworkStruct<T>&
sn, std::size_t ind, std::size_t isf,
689 const std::vector<NetState<T>>& space) {
690 const std::size_t K =
sn.nclasses;
693 const std::size_t ist =
sn.nodes[ind - 1].station;
694 if (ist != 0 &&
sn.stations[ist - 1].nodetype == NodeType::Source)
return out;
695 for (std::size_t s = 0; s < space.size(); ++s) {
696 const std::vector<T> m = prob_detail::marginal_of(
sn, ind, space[s].local[isf - 1]);
697 for (std::size_t k = 0; k < K && k < m.size(); ++k) out(s, k) = m[k];
712void check_pair(std::size_t isf,
const std::vector<NetState<T>>& space,
const char* what) {
713 if (!space.empty() && isf > space[0].local.size())
715 ": the transient solution has fewer stateful nodes than the model it "
716 "was queried with, so it was not integrated from that model");
721Matrix<T> node_labels(std::size_t isf,
const std::vector<NetState<T>>& space) {
722 const std::size_t w = space.empty() ? 0 : space[0].local[isf - 1].size();
723 Matrix<T> out(space.size(), w, num_traits<T>::from_int(0));
724 for (std::size_t s = 0; s < space.size(); ++s)
725 for (std::size_t j = 0; j < w; ++j) out(s, j) = space[s].local[isf - 1][j];
731CtmcTranProb<T> tran_common(
const CtmcTransient<T>& tr) {
758 const std::size_t isf = getters_detail::stateful_or_throw(
sn, ind,
"getTranProb");
759 getters_detail::check_pair(isf,
tr.chain.chain.space,
"getTranProb");
761 p.
labels = getters_detail::node_labels(isf,
tr.chain.chain.space);
768 std::size_t ind,
const T& t0,
const T& t1) {
770 "getTranProb integrates the forward equation, whose adaptive step controller "
771 "is transcendental; use --arith double or real");
773 getters_detail::check_timespan(t0, t1,
"getTranProb");
798 const std::size_t isf = getters_detail::stateful_or_throw(
sn, ind,
"getTranProbAggr");
799 getters_detail::check_pair(isf,
tr.chain.chain.space,
"getTranProbAggr");
801 p.
labels = getters_detail::node_marginal_labels(
sn, ind, isf,
tr.chain.chain.space);
808 std::size_t ind,
const T& t0,
const T& t1) {
810 "getTranProbAggr integrates the forward equation, whose adaptive step "
811 "controller is transcendental; use --arith double or real");
813 getters_detail::check_timespan(t0, t1,
"getTranProbAggr");
825 p.
labels = getters_detail::flatten(
tr.chain.chain.space);
832 const T& t0,
const T& t1) {
834 "getTranProbSys integrates the forward equation, whose adaptive step "
835 "controller is transcendental; use --arith double or real");
837 getters_detail::check_timespan(t0, t1,
"getTranProbSys");
861 const T& t0,
const T& t1) {
863 "getTranProbSysAggr integrates the forward equation, whose adaptive step "
864 "controller is transcendental; use --arith double or real");
866 getters_detail::check_timespan(t0, t1,
"getTranProbSysAggr");
911 const std::function<T(
const NetState<T>&)>& reward) {
914 f.reserve(g.
space.size());
915 for (std::size_t i = 0; i < g.
space.size(); ++i) f.push_back(reward(g.
space[i]));
A network plus its refreshed NetworkStruct.
First passage times into a target STATE SET, for Markov and semi-Markov chains.
The exception types the port throws.
Dense matrix and non-owning view.
void assert_phase_type_states(const NetworkStruct< T > &sn, const std::string &what)
Port of @@SolverCTMC/assertPhaseTypeStates: refuse a query whose answer would be a per-state probabil...
CtmcGenerator< T > ctmc_get_generator(const NetworkStruct< T > &sn, const CtmcSolution< T > &d)
Port of @@SolverCTMC/getGenerator.m: the generator, its event filtration and the synchronization list...
CtmcTranProb< T > ctmc_get_tran_prob_sys(const NetworkStruct< T > &sn, const CtmcTransient< T > &tr)
Port of @@SolverCTMC/getTranProbSys.m: pi(t), labelled by the whole network state with its phases.
CtmcTranProb< T > ctmc_get_tran_prob_sys_aggr(const NetworkStruct< T > &sn, const CtmcTransient< T > &tr)
Port of @@SolverCTMC/getTranProbSysAggr.m: pi(t), labelled by the network's per-(station,...
CtmcGenerator< T > ctmc_get_infgen(const NetworkStruct< T > &sn, const CtmcSolution< T > &d)
@@SolverCTMC/getInfGen.m, a pure alias of getGenerator in the reference.
sim::AsymVarResult< T > ctmc_get_asymptotic_variance(const NetworkStruct< T > &sn, const CtmcOptions &opt, const std::function< T(const NetState< T > &)> &reward)
Port of @@SolverCTMC/getAsymptoticVariance.m: the asymptotic variance of the time-average of a reward...
CtmcStateSpace< T > ctmc_get_state_space(const NetworkStruct< T > &, const CtmcSolution< T > &d)
Port of @@SolverCTMC/getStateSpace.m.
CtmcTransient< T > solver_ctmc_transient_analyzer(const NetworkStruct< T > &sn_arg, const CtmcOptions &opt, const T &t0, const T &t1, const std::vector< T > &grid=std::vector< T >())
Port of solver_ctmc_transient_analyzer.m.
CtmcFirstPassageMoments< T > ctmc_firstpasst_moments(const NetworkStruct< T > &, const CtmcSolution< T > &d, const Matrix< double > &A, const Matrix< double > &B, std::size_t nmax, const Matrix< double > &C)
Port of @@SolverCTMC/getFirstPassTMoments.m: moments of order 1..nmax of the first passage time from ...
Matrix< T > ctmc_get_state_space_aggr(const NetworkStruct< T > &sn, const CtmcOptions &opt)
Port of @@SolverCTMC/getStateSpaceAggr.m: the per-(station, class) job counts of every state,...
CtmcFirstPassage ctmc_cdf_firstpasst(const NetworkStruct< T > &, const CtmcSolution< T > &d, const Matrix< double > &A, const Matrix< double > &B, const Matrix< double > &C, std::vector< double > tset, const std::string &method="expm")
Port of @@SolverCTMC/getCdfFirstPassT.m: the distribution of the FIRST PASSAGE TIME from state set A ...
CtmcSolution< T > solver_ctmc_analyzer(const NetworkStruct< T > &sn_in, const CtmcOptions &opt)
Port of solver_ctmc_analyzer.m plus the fork-join wrapper of @@SolverCTMC/runAnalyzer....
Matrix< T > ctmc_get_preempt_rate(const NetworkStruct< T > &sn, const CtmcOptions &opt)
SolverCTMC.getPreemptRate; see ctmc_get_start_rate.
Matrix< T > ctmc_get_start_rate(const NetworkStruct< T > &sn, const CtmcOptions &opt)
SolverCTMC.getStartRate and getPreemptRate: the DERIVED rates the START/PREEMPT filtration reduces to...
CtmcTranProb< T > ctmc_get_tran_prob(const NetworkStruct< T > &sn, const CtmcTransient< T > &tr, std::size_t ind)
Port of @@SolverCTMC/getTranProb.m: pi(t) over the whole chain, labelled by one node's local state.
Matrix< T > ctmc_state_space_aggr(const NetworkStruct< T > &sn, const std::vector< NetState< T > > &space)
Port of StateSpaceAggr: the per-(station, class) job counts of every state, as an (nstates x nstation...
CtmcTranProb< T > ctmc_get_tran_prob_aggr(const NetworkStruct< T > &sn, const CtmcTransient< T > &tr, std::size_t ind)
Port of @@SolverCTMC/getTranProbAggr.m: pi(t), labelled by one node's per-class job counts.
PassageMoments< T > ctmc_passage_moments(const Matrix< T > &Q, const std::vector< T > &pi0, const std::vector< std::size_t > &target, std::size_t nmax=1)
Moments of order 1..nmax of the first passage time into target.
PassageCurve< T > ctmc_passage_time(const Matrix< T > &Q, const std::vector< T > &pi0, const std::vector< std::size_t > &target, const std::vector< double > &tset, const std::string &method="expm", const std::string <i_method="euler")
CDF and density of the first passage time on the grid tset: F(t) = 1 - alpha exp(St) 1 and f(t) = alp...
PassageTabooMoments< T > ctmc_passage_taboo_moments(const Matrix< T > &Q, const std::vector< T > &pi0, const std::vector< std::size_t > &target, const std::vector< std::size_t > &taboo, std::size_t nmax=1)
Moments of order 1..nmax of the first passage time into target, CONDITIONAL on entering it before tab...
PassageTaboo< T > ctmc_passage_taboo(const Matrix< T > &Q, const std::vector< T > &pi0, const std::vector< std::size_t > &target, const std::vector< std::size_t > &taboo, const std::vector< double > &tset=std::vector< double >(), const std::string &method="expm", const std::string <i_method="euler")
First passage into target under the taboo set taboo, the reference's ctmc_passage_taboo.
AsymVarResult< T > sim_asymvar_ctmc(const Matrix< T > &A, const std::vector< T > &f, const std::vector< T > &pi=std::vector< T >())
Asymptotic variance of a reward on a CTMC: 2 sum_x pi(x)g(x)d(x) with g = f - E_pi[f] and A d = -g,...
Conservation laws of a layered queueing network, enumerated from its structure.
A queueing network and its refreshed NetworkStruct.
Run-length planning for steady-state simulation.
Port of solver_ctmc.m: the infinitesimal generator of a queueing network, assembled from the enumerat...
Port of solver_ctmc_analyzer.m and the parts of @@SolverCTMC/runAnalyzer.m that surround one solve: t...
The SolverCTMC probability family: solver_ctmc_joint, _jointaggr, _marg, _margaggr,...
Port of solver_ctmc_transient_analyzer.m: the time-dependent counterpart of solver_ctmc_analyzer,...
Port of the MATLAB +State package: the encoding that turns a station's state row into marginal job co...
Port of the event half of MATLAB's +State package: the successor states an event produces at one node...
The answer of @@SolverCTMC/getFirstPassTMoments.m.
std::vector< T > p
(nstates) probability of entering B (before C), one row per state
Matrix< T > mall
(nstates x nmax), one row per starting state
std::vector< std::size_t > source
resolved 0-based rows; empty = conditional stationary
std::vector< std::size_t > target
resolved 0-based rows
std::vector< std::size_t > taboo
resolved 0-based rows of C minus B; empty = none
std::vector< T > m
(nmax) moments for a passage started uniformly in A
The answer of @@SolverCTMC/getCdfFirstPassT.m: the [F(t), t] curve with its grid, density and resolve...
std::vector< double > F
CDF at t, clamped to [0, 1]; DEFECTIVE under a taboo set.
std::vector< double > t
the grid: the caller's, else 1000 points to the horizon
double tabooprob
Pr{C entered before B}.
double reachprob
Pr{B entered before C}, the limit of F.
std::vector< std::size_t > target
resolved 0-based rows
std::vector< std::size_t > source
resolved 0-based rows; empty = conditional stationary
std::vector< double > f
density at t
std::vector< std::size_t > taboo
resolved 0-based rows of C minus B; empty = none
[infGen, eventFilt, ev] of @@SolverCTMC/getGenerator.m.
std::vector< std::vector< Matrix< T > > > preempt_filt
std::vector< NetState< T > > space
row i of Q is space[i]
std::vector< Matrix< T > > filt
eventFilt: filt[a] holds only what synchronization sync[a] contributed, so sum_a filt[a] is the off-d...
std::vector< Sync< T > > sync
ev, the reference's sn.sync
std::vector< std::vector< Matrix< T > > > start_filt
The DERIVED START/PREEMPT filtrations, indexed [station-1][class-1].
Matrix< T > Q
the infinitesimal generator
The SolverCTMC knobs this port honours.
bool keep_filtration
Keep the per-synchronization EVENT FILTRATION alongside Q.
Everything one CTMC solve produces.
std::shared_ptr< const NetworkStruct< T > > solved_sn
The struct the chain was built on, when it differs from the caller's in its state LAYOUT: set when he...
[stateSpace, localStateSpace] of @@SolverCTMC/getStateSpace.m.
std::vector< NetState< T > > space
The enumerated states.
std::vector< std::size_t > node_width
column width of each stateful node's block
std::vector< Matrix< T > > local
localStateSpace{f}: one matrix per stateful node, its DISTINCT local rows in first-appearance order.
Matrix< T > flat
the blocks concatenated, as MATLAB returns them
The time-dependent answer of one getTranProb* query.
Matrix< T > pit
(ntimes x nstates) occupancy over the solved chain
std::vector< T > t
The reference returns Pi_t = [t, pi_t], one matrix with time glued on as column 1.
Matrix< T > labels
(nstates x width) the state descriptor the query asked for
What one transient CTMC solve produces.
static constexpr double FineTol
A passage-time law on a grid.
Moments of a first passage time, [Mall, m] of the reference.
Matrix< T > mall
(nstates x nmax), zero on the target, inf where unreachable
std::vector< T > m
the pi0-weighted moment vector
Conditional moments under a taboo set, [mall, m, pB] of ctmc_passage_taboo_moments....
std::vector< T > m
the pi0-weighted conditional moments, NaN if B is never entered first
Matrix< T > mall
(nstates x nmax): zero on B, NaN where B cannot be entered first
std::vector< T > pB
(nstates) probability of entering B before C
First passage into a target set B under a TABOO set C, [F, f, out] of ctmc_passage_taboo....
std::vector< std::size_t > taboo
C minus B, sorted and unique.
T tabooprob
Pr{C entered before B}.
std::vector< double > F
DEFECTIVE CDF Pr{B entered by t, C not before}, clamped to [0, 1].
T reachprob
Pr{B entered before C}, the limit of F.
std::vector< double > f
its density alpha exp(St) sB
One network state: the per-stateful-node local rows it is composed of.
Second-order description of a steady-state estimator.