5#ifndef LINE_SOLVERS_CTMC_SOLVER_CTMC_GETTERS_H
6#define LINE_SOLVERS_CTMC_SOLVER_CTMC_GETTERS_H
67 std::vector<Matrix<T>>
filt;
166 return d.
avg.PreemptN;
169namespace getters_detail {
173std::vector<std::size_t> node_widths(
const std::vector<NetState<T>>& space) {
174 std::vector<std::size_t> w;
175 if (space.empty())
return w;
176 for (std::size_t f = 0; f < space[0].local.size(); ++f) w.push_back(space[0].local[f].size());
182Matrix<T> flatten(
const std::vector<NetState<T>>& space) {
183 const std::vector<std::size_t> w = node_widths(space);
184 std::size_t total = 0;
185 for (std::size_t f = 0; f < w.size(); ++f) total += w[f];
186 Matrix<T> out(space.size(), total, num_traits<T>::from_int(0));
187 for (std::size_t s = 0; s < space.size(); ++s) {
189 for (std::size_t f = 0; f < space[s].local.size(); ++f)
190 for (std::size_t j = 0; j < space[s].local[f].size(); ++j) out(s, c++) = space[s].local[f][j];
203std::vector<Matrix<T>> local_spaces(
const std::vector<NetState<T>>& space) {
204 std::vector<Matrix<T>> out;
205 if (space.empty())
return out;
206 const std::size_t NF = space[0].local.size();
207 for (std::size_t f = 0; f < NF; ++f) {
208 std::vector<std::vector<T>> rows;
209 std::set<std::vector<double>> seen;
210 for (std::size_t s = 0; s < space.size(); ++s) {
211 if (space[s].local.size() <= f)
continue;
212 const std::vector<T>& r = space[s].local[f];
213 std::vector<double> key(r.size());
214 for (std::size_t j = 0; j < r.size(); ++j) key[j] = num_traits<T>::to_double(r[j]);
215 if (!seen.insert(key).second)
continue;
218 const std::size_t w = rows.empty() ? 0 : rows[0].size();
219 Matrix<T> m(rows.size(), w, num_traits<T>::from_int(0));
220 for (std::size_t i = 0; i < rows.size(); ++i)
221 for (std::size_t j = 0; j < w && j < rows[i].size(); ++j) m(i, j) = rows[i][j];
235std::size_t stateful_or_throw(
const NetworkStruct<T>& sn, std::size_t ind,
const char* what) {
236 if (ind < 1 || ind > sn.nodes.size())
237 throw InputError(std::string(what) +
": the node index is out of range");
238 const std::size_t isf = sn.stateful_index(ind);
241 ": node " + std::to_string(ind) +
242 " is stateless and holds no block of the network state");
254void check_timespan(
const T& t0,
const T& t1,
const char* what) {
255 const double a = num_traits<T>::to_double(t0), b = num_traits<T>::to_double(t1);
256 if (!std::isfinite(a) || !std::isfinite(b) || !(b > a))
258 " requires a finite timespan [t0, t1] with t1 > t0; for the limit as t "
259 "grows use the stationary family (getProb, getProbAggr, getProbSys, "
275 if (d.
chain.filt.empty())
277 "ctmc_get_generator: the solution carries no event filtration, which cannot be "
278 "recovered from Q because its entries have already summed every synchronization's "
279 "contribution; re-solve with CtmcOptions::keep_filtration = true");
286 g.
sync = refresh_sync(
sn);
329 s.
flat = getters_detail::flatten(d.
chain.space);
331 s.
local = getters_detail::local_spaces(d.
chain.space);
344 std::vector<double>
t;
345 std::vector<double>
F;
346 std::vector<double>
f;
351namespace getters_detail {
362 std::set<std::size_t> idx;
363 if (S.
rows() == 0 || S.
cols() == 0)
return std::vector<std::size_t>();
364 const std::size_t n = flat.
rows();
365 bool is_index_vector = (S.
rows() == 1 || S.
cols() == 1);
366 if (is_index_vector) {
367 for (std::size_t i = 0; i < S.
rows() && is_index_vector; ++i)
368 for (std::size_t j = 0; j < S.
cols(); ++j) {
369 const double v = S(i, j);
370 if (v != std::floor(v) || v < 1 || v >
static_cast<double>(n)) {
371 is_index_vector =
false;
376 if (is_index_vector) {
377 for (std::size_t i = 0; i < S.
rows(); ++i)
378 for (std::size_t j = 0; j < S.
cols(); ++j)
379 idx.insert(
static_cast<std::size_t
>(S(i, j)) - 1);
382 throw InputError(std::string(
"getCdfFirstPassT: a state row in set ") + name +
383 " has " + std::to_string(S.
cols()) +
" columns where the state "
384 "space has " + std::to_string(flat.
cols()));
385 for (std::size_t i = 0; i < S.
rows(); ++i) {
387 for (std::size_t r = 0; r < n && !found; ++r) {
389 for (std::size_t j = 0; j < S.
cols() && eq; ++j)
397 throw InputError(std::string(
"A state given in set ") + name +
398 " is not in the state space.");
401 return std::vector<std::size_t>(idx.begin(), idx.end());
424 const std::string& method =
"expm") {
426 "getCdfFirstPassT takes a matrix exponential and therefore requires an "
427 "arithmetic with transcendental functions");
429 const std::size_t n = Q.
rows();
433 out.
target = getters_detail::resolve_state_set(B, flat,
"B");
436 "The target state set B is empty: a first passage time into no state is undefined.");
437 out.
source = getters_detail::resolve_state_set(A, flat,
"A");
440 if (!out.
source.empty()) {
443 static_cast<long>(out.
source.size()));
444 for (std::size_t idx : out.
source) pi0[idx] = w;
449 double min_rate = std::numeric_limits<double>::infinity();
450 for (std::size_t i = 0; i < n; ++i)
451 for (std::size_t j = 0; j < n; ++j) {
455 const double thor = std::abs(100.0 / min_rate);
456 std::vector<double> tset(1000);
457 for (std::size_t i = 0; i < tset.size(); ++i)
458 tset[i] = thor *
static_cast<double>(i) /
static_cast<double>(tset.size() - 1);
471 const std::string& method =
"expm") {
503 std::size_t nmax = 3) {
505 "getFirstPassTMoments marks an unreachable target with an infinity and "
506 "therefore requires an arithmetic that has one");
508 const std::size_t n = Q.
rows();
512 out.
target = getters_detail::resolve_state_set(B, flat,
"B");
515 "The target state set B is empty: a first passage time into no state is undefined.");
516 out.
source = getters_detail::resolve_state_set(A, flat,
"A");
519 if (!out.
source.empty()) {
522 static_cast<long>(out.
source.size()));
523 for (std::size_t idx : out.
source) pi0[idx] = w;
538 std::size_t nmax = 3) {
562namespace getters_detail {
580Matrix<T> node_marginal_labels(
const NetworkStruct<T>&
sn, std::size_t ind, std::size_t isf,
581 const std::vector<NetState<T>>& space) {
582 const std::size_t K =
sn.nclasses;
585 const std::size_t ist =
sn.nodes[ind - 1].station;
586 if (ist != 0 &&
sn.stations[ist - 1].nodetype == NodeType::Source)
return out;
587 for (std::size_t s = 0; s < space.size(); ++s) {
588 const std::vector<T> m = prob_detail::marginal_of(
sn, ind, space[s].local[isf - 1]);
589 for (std::size_t k = 0; k < K && k < m.size(); ++k) out(s, k) = m[k];
604void check_pair(std::size_t isf,
const std::vector<NetState<T>>& space,
const char* what) {
605 if (!space.empty() && isf > space[0].local.size())
607 ": the transient solution has fewer stateful nodes than the model it "
608 "was queried with, so it was not integrated from that model");
613Matrix<T> node_labels(std::size_t isf,
const std::vector<NetState<T>>& space) {
614 const std::size_t w = space.empty() ? 0 : space[0].local[isf - 1].size();
615 Matrix<T> out(space.size(), w, num_traits<T>::from_int(0));
616 for (std::size_t s = 0; s < space.size(); ++s)
617 for (std::size_t j = 0; j < w; ++j) out(s, j) = space[s].local[isf - 1][j];
623CtmcTranProb<T> tran_common(
const CtmcTransient<T>& tr) {
650 const std::size_t isf = getters_detail::stateful_or_throw(
sn, ind,
"getTranProb");
651 getters_detail::check_pair(isf,
tr.chain.chain.space,
"getTranProb");
653 p.
labels = getters_detail::node_labels(isf,
tr.chain.chain.space);
660 std::size_t ind,
const T& t0,
const T& t1) {
662 "getTranProb integrates the forward equation, whose adaptive step controller "
663 "is transcendental; use --arith double or real");
665 getters_detail::check_timespan(t0, t1,
"getTranProb");
690 const std::size_t isf = getters_detail::stateful_or_throw(
sn, ind,
"getTranProbAggr");
691 getters_detail::check_pair(isf,
tr.chain.chain.space,
"getTranProbAggr");
693 p.
labels = getters_detail::node_marginal_labels(
sn, ind, isf,
tr.chain.chain.space);
700 std::size_t ind,
const T& t0,
const T& t1) {
702 "getTranProbAggr integrates the forward equation, whose adaptive step "
703 "controller is transcendental; use --arith double or real");
705 getters_detail::check_timespan(t0, t1,
"getTranProbAggr");
717 p.
labels = getters_detail::flatten(
tr.chain.chain.space);
724 const T& t0,
const T& t1) {
726 "getTranProbSys integrates the forward equation, whose adaptive step "
727 "controller is transcendental; use --arith double or real");
729 getters_detail::check_timespan(t0, t1,
"getTranProbSys");
753 const T& t0,
const T& t1) {
755 "getTranProbSysAggr integrates the forward equation, whose adaptive step "
756 "controller is transcendental; use --arith double or real");
758 getters_detail::check_timespan(t0, t1,
"getTranProbSysAggr");
803 const std::function<T(
const NetState<T>&)>& reward) {
806 f.reserve(g.
space.size());
807 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.
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,...
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...
CtmcTransient< T > solver_ctmc_transient_analyzer(const NetworkStruct< T > &sn, const CtmcOptions &opt, const T &t0, const T &t1, const std::vector< T > &grid=std::vector< T >())
Port of solver_ctmc_transient_analyzer.m.
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.
CtmcFirstPassage ctmc_cdf_firstpasst(const NetworkStruct< T > &, const CtmcSolution< T > &d, const Matrix< double > &A, const Matrix< double > &B, const std::string &method="expm")
Port of @@SolverCTMC/getCdfFirstPassT.m: the distribution of the FIRST PASSAGE TIME from state set A ...
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.
CtmcFirstPassageMoments< T > ctmc_firstpasst_moments(const NetworkStruct< T > &, const CtmcSolution< T > &d, const Matrix< double > &A, const Matrix< double > &B, std::size_t nmax=3)
Port of @@SolverCTMC/getFirstPassTMoments.m: moments of order 1..nmax of the first passage time from ...
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...
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,...
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.
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< 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].
std::vector< double > t
the grid, 1000 points to the horizon
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
[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.
[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.
Per-source and pi0-weighted passage moments.
Matrix< T > mall
(nstates x nmax), zero on the target, inf where unreachable
std::vector< T > m
the pi0-weighted moment vector
One network state: the per-stateful-node local rows it is composed of.
Second-order description of a steady-state estimator.