5#ifndef LINE_SOLVERS_CTMC_SOLVER_CTMC_CDF_H
6#define LINE_SOLVERS_CTMC_SOLVER_CTMC_CDF_H
80 bool empty()
const {
return t.empty(); }
86constexpr std::size_t respt_intervals = 100000;
87constexpr std::size_t sysrespt_intervals = 10000;
93 std::vector<qn::Sync<T>> sync;
109std::size_t class_to_tag(
const NetworkStruct<T>& sn, std::size_t chain) {
110 const std::vector<std::size_t>& ic = sn.inchain[chain - 1];
111 for (std::size_t a = 0; a < ic.size(); ++a)
112 if (sn.classes[ic[a] - 1].population > 0.0)
return ic[a];
113 throw InputError(
"SolverCTMC: chain " + std::to_string(chain) +
114 " holds no jobs, so it has no job to tag");
119TaggedCtmc<T> tagged_ctmc(
const NetworkStruct<T>& sn, std::size_t chain,
const CtmcOptions& opt) {
124 o.keep_filtration =
true;
138 if (out.sol.chain.filt.size() != out.sync.size())
140 "SolverCTMC: the event filtration does not match the synchronization list; the "
141 "generator was built without keep_filtration");
157std::vector<std::size_t> completing_tagged(
const qn::TaggedChain<T>& tag) {
158 std::vector<std::size_t> out;
159 for (std::size_t a = 0; a < tag.tagged.size(); ++a)
160 if (tag.V.classes[tag.tagged[a] - 1].completes) out.push_back(tag.tagged[a]);
163 "SolverCTMC: no class of the tagged chain has JobClass::completes set, so the response "
164 "time has no completion event to end at. `completes` now defaults to true here as it "
165 "does in the other three codebases, so reaching this means a caller cleared it; set "
166 "classes of the chain before asking for a response-time CDF");
181Matrix<T> filtration_sum(
const CtmcSolution<T>& sol,
const std::vector<qn::Sync<T>>& sync,
183 const std::vector<std::pair<std::size_t, std::size_t>>& sel) {
184 const std::size_t n = sol.chain.Q.rows();
185 Matrix<T> S(n, n, num_traits<T>::from_int(0));
186 for (std::size_t v = 0; v < sync.size(); ++v) {
187 const qn::SyncEvent<T>& half = on_passive ? sync[v].passive : sync[v].active;
188 if (half.event != ev)
continue;
190 for (std::size_t k = 0; k < sel.size(); ++k)
191 if (half.cls == sel[k].first && half.node == sel[k].second) hit =
true;
193 for (std::size_t i = 0; i < n; ++i)
194 for (std::size_t j = 0; j < n; ++j) S(i, j) += sol.chain.filt[v](i, j);
201bool any_rate(
const Matrix<T>& S) {
202 for (std::size_t i = 0; i < S.rows(); ++i)
203 for (std::size_t j = 0; j < S.cols(); ++j)
204 if (num_traits<T>::to_double(S(i, j)) != 0)
return true;
217T grid_step(
const Matrix<T>& Q, std::size_t intervals) {
218 double lo = std::numeric_limits<double>::infinity();
219 for (std::size_t i = 0; i < Q.rows(); ++i)
220 for (std::size_t j = 0; j < Q.cols(); ++j) {
221 const double a = std::fabs(num_traits<T>::to_double(Q(i, j)));
224 if (!std::isfinite(lo))
225 throw NumericError(
"SolverCTMC: the generator of the tagged model carries no rate above "
226 "the tolerance, so no time horizon can be chosen");
227 const double horizon = 100.0 / lo;
228 return num_traits<T>::from_double(horizon /
static_cast<double>(intervals));
238CdfCurve<T> absorption_cdf(
const Matrix<T>& D0,
const std::vector<T>& pie,
const T& dt,
239 std::size_t intervals,
double tol) {
240 static_assert(num_traits<T>::has_transcendental,
241 "the response-time CDF needs a matrix exponential and is not available in exact "
242 "rational arithmetic");
243 const T one = num_traits<T>::from_int(1);
244 const Matrix<T> E =
expm(D0, dt);
245 std::vector<T> v = pie;
247 for (std::size_t k = 0; k <= intervals; ++k) {
248 T mass = num_traits<T>::from_int(0);
249 for (std::size_t i = 0; i < v.size(); ++i) mass += v[i];
250 const T F = T(one - mass);
251 out.t.push_back(T(dt * num_traits<T>::from_int(
static_cast<long>(k))));
255 if (num_traits<T>::to_double(F) > 1.0 - tol)
break;
277 "getCdfRespT needs a matrix exponential and is not available in exact rational "
279 const std::size_t M =
sn.nstations, K =
sn.nclasses;
280 const std::vector<double> N =
sn.njobs();
281 for (std::size_t k = 0; k < K; ++k)
282 if (!std::isfinite(N[k]))
284 "SolverCTMC: getCdfRespT is presently supported only for closed models; class '" +
285 sn.classes[k].name +
"' is open");
287 std::vector<std::vector<CdfCurve<T>>> RD(M, std::vector<
CdfCurve<T>>(K));
289 for (std::size_t c = 1; c <=
sn.nchains; ++c) {
290 const cdf_detail::TaggedCtmc<T> tc = cdf_detail::tagged_ctmc(
sn, c,
opt);
291 const std::vector<std::size_t> tagged = cdf_detail::completing_tagged(tc.tag);
293 const T dt = cdf_detail::grid_step(Q, cdf_detail::respt_intervals);
295 for (std::size_t ist = 1; ist <= M; ++ist) {
296 const std::size_t ind = tc.tag.V.node_of_station(ist);
297 std::vector<std::pair<std::size_t, std::size_t>> sel;
298 for (std::size_t a = 0; a < tagged.size(); ++a) sel.push_back(std::make_pair(tagged[a], ind));
301 cdf_detail::filtration_sum(tc.sol, tc.sync,
true, EventType::ARV, sel);
305 if (!cdf_detail::any_rate(A1))
continue;
307 cdf_detail::filtration_sum(tc.sol, tc.sync,
false, EventType::DEP, sel);
308 if (!cdf_detail::any_rate(D1))
continue;
313 for (std::size_t i = 0; i < A.
D0.rows(); ++i)
314 for (std::size_t j = 0; j < A.
D0.cols(); ++j) A.
D0(i, j) -= A1(i, j);
320 for (std::size_t i = 0; i < D.
D0.rows(); ++i)
321 for (std::size_t j = 0; j < D.
D0.cols(); ++j) D.
D0(i, j) -= D1(i, j);
324 const CdfCurve<T> curve = cdf_detail::absorption_cdf(
326 for (std::size_t a = 0; a <
sn.inchain[c - 1].size(); ++a)
327 RD[ist - 1][
sn.inchain[c - 1][a] - 1] = curve;
349 "getCdfSysRespT needs a matrix exponential and is not available in exact "
350 "rational arithmetic");
351 std::vector<CdfCurve<T>> RD(
sn.nchains);
353 for (std::size_t c = 1; c <=
sn.nchains; ++c) {
354 const cdf_detail::TaggedCtmc<T> tc = cdf_detail::tagged_ctmc(
sn, c,
opt);
355 const std::vector<std::size_t> tagged = cdf_detail::completing_tagged(tc.tag);
361 std::vector<std::pair<std::size_t, std::size_t>> sel;
362 for (std::size_t a = 0; a < tagged.size(); ++a) {
363 const std::size_t refstat = tc.tag.V.classes[tagged[a] - 1].refstat;
364 sel.push_back(std::make_pair(tagged[a], tc.tag.V.node_of_station(refstat)));
367 const Matrix<T> D1 = cdf_detail::filtration_sum(tc.sol, tc.sync,
true, EventType::ARV, sel);
368 if (!cdf_detail::any_rate(D1))
370 "SolverCTMC: the tagged job never arrives at its reference station, so the system "
371 "response time of chain " + std::to_string(c) +
" has no cycle to measure");
376 for (std::size_t i = 0; i < D.
D0.rows(); ++i)
377 for (std::size_t j = 0; j < D.
D0.cols(); ++j) D.
D0(i, j) -= D1(i, j);
381 const T dt = cdf_detail::grid_step(Q, cdf_detail::sysrespt_intervals);
382 RD[c - 1] = cdf_detail::absorption_cdf(Dn.
D0, pie_arv, dt, cdf_detail::sysrespt_intervals,
NumericError(const std::string &what)
UnsupportedError(const std::string &what)
A network plus its refreshed NetworkStruct.
The exception types the port throws.
Matrix exponential by scaling and squaring with a diagonal Pade approximant.
Markovian arrival process descriptors: stationary vectors, rate, moments, autocorrelation and the ind...
Dense matrix and non-owning view.
std::vector< CdfCurve< T > > solver_ctmc_cdf_sys_respt(const NetworkStruct< T > &sn, const CtmcOptions &opt)
Port of @@SolverCTMC/getCdfSysRespT.m: the per-chain SYSTEM response-time CDF, indexed by chain.
std::vector< std::vector< CdfCurve< T > > > solver_ctmc_cdf_respt(const NetworkStruct< T > &sn, const CtmcOptions &opt)
Port of @@SolverCTMC/getCdfRespT.m: the per-(station, class) response-time CDF, indexed [ist-1][r-1].
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....
EventType
The events a state can undergo, with the values of MATLAB EventType.
std::vector< T > map_pie(const Map< T > &m)
Phase distribution seen by an arriving job, pie = pi D1 / (pi D1 e).
Map< T > map_normalize(const Map< T > &in)
Clamp negative off-diagonal entries of D0 and negative entries of D1 to zero, then rebuild the diagon...
TaggedChain< T > tag_chain(const NetworkStruct< T > &sn, std::size_t chain, std::size_t jobclass, const std::string &suffix=".tagged")
Tag one class of one chain.
std::vector< Sync< T > > refresh_sync(const NetworkStruct< T > &sn, const std::vector< std::vector< bool > > &impatience_classes=std::vector< std::vector< bool > >(), const std::vector< std::size_t > &breakdown_nodes=std::vector< std::size_t >())
Port of MNetwork.refreshSync: the synchronization list.
std::vector< T > vecmul(const std::vector< T > &v, const Matrix< T > &A)
Row vector times matrix, v A.
Matrix< T > expm(const Matrix< T > &A)
Matrix exponential exp(A).
A queueing network and its refreshed NetworkStruct.
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...
Port of the event half of MATLAB's +State package: the successor states an event produces at one node...
A CDF as the reference returns it: the value at each point of the time grid.
The SolverCTMC knobs this port honours.
static constexpr double FineTol
static constexpr double CoarseTol
A MAP as the pair of matrices (D0, D1).
The tagged model and the class bookkeeping a caller needs to read it back.
Port of matlab/src/io/@ModelAdapter/tagChain.m: the model-to-model transform that isolates ONE job of...