5#ifndef LINE_SOLVERS_CTMC_SOLVER_CTMC_TRANSIENT_H
6#define LINE_SOLVERS_CTMC_SOLVER_CTMC_TRANSIENT_H
60mc::TransientResult<T> ctmc_fau_transient(
const Matrix<T>& Q,
const std::vector<T>& pi0,
61 const T& t0,
const T& t1,
const CtmcOptions& opt,
62 const std::vector<T>& grid) {
63 const double t0d = num_traits<T>::to_double(t0);
64 const double t1d = num_traits<T>::to_double(t1);
65 if (!std::isfinite(t1d))
67 "solver_ctmc_transient_analyzer: transient_method 'fau' needs a finite horizon");
72 }
else if (opt.timestep > 0.0) {
73 const std::size_t nstep =
74 static_cast<std::size_t
>(std::floor((t1d - t0d) / opt.timestep));
75 for (std::size_t i = 0; i <= nstep; ++i)
76 ts.push_back(num_traits<T>::from_double(t0d + i * opt.timestep));
77 if (num_traits<T>::to_double(ts.back()) < t1d) ts.push_back(t1);
79 const std::size_t ngrid = (opt.fau_ngrid > 1) ? opt.fau_ngrid : 100;
80 for (std::size_t i = 0; i < ngrid; ++i)
81 ts.push_back(num_traits<T>::from_double(
82 t0d + (t1d - t0d) *
static_cast<double>(i) /
static_cast<double>(ngrid - 1)));
84 const std::size_t nt = ts.size();
85 const double eps = (opt.fau_epsilon > 0.0) ? opt.fau_epsilon : 1e-6;
86 const double epsStep = eps /
static_cast<double>((nt > 1) ? (nt - 1) : 1);
88 mc::TransientResult<T> out;
90 out.pi =
Matrix<T>(nt, pi0.size(), num_traits<T>::from_int(0));
91 for (std::size_t j = 0; j < pi0.size(); ++j) out.pi(0, j) = pi0[j];
92 std::vector<T> cur = pi0;
93 for (std::size_t k = 1; k < nt; ++k) {
94 const T dt = ts[k] - ts[k - 1];
95 const mc::FauResult<T> r =
mc::ctmc_fau(cur, Q, dt, epsStep, opt.fau_delta, -1);
97 for (std::size_t j = 0; j < cur.size(); ++j) out.pi(k, j) = cur[j];
132 const std::vector<T>& grid = std::vector<T>()) {
134 "solver_ctmc_transient_analyzer integrates the forward equation with an "
135 "adaptive Runge-Kutta step controller, whose error norm is transcendental; "
136 "use --arith double or real");
145 "SolverCTMC: transient analysis of a fork-join model is not supported. The chain is "
146 "the tag-augmented one, and folding the sibling classes back onto the original ones "
147 "is a steady-state aggregate; use the stationary solve, or SolverLDES for transients");
151 const std::size_t n = out.
chain.chain.space.size();
152 const std::size_t M =
sn.stations.size(), K =
sn.nclasses;
160 if (!analyzer_detail::init_state_distribution(
sn, out.
chain.chain.space, pi0))
162 "solver_ctmc_transient_analyzer: the initial state is not contained in the state "
163 "space, so there is no distribution to start the integration from");
166 if (
opt.transient_method ==
"fau") {
167 tr = detail::ctmc_fau_transient(out.
chain.chain.Q, pi0, t0, t1,
opt, grid);
168 }
else if (
opt.transient_method ==
"ode") {
177 else if (
opt.timestep > 0.0)
181 throw InputError(
"solver_ctmc_transient_analyzer: unknown transient_method '" +
182 opt.transient_method +
"'; use 'ode' or 'fau'");
186 const std::size_t nt = out.
t.size();
190 for (std::size_t i = 0; i < nt; ++i)
191 for (std::size_t s = 0; s < n; ++s)
197 out.
QNt.assign(M, std::vector<std::vector<T>>(K, std::vector<T>(nt, zero)));
198 out.
UNt.assign(M, std::vector<std::vector<T>>(K, std::vector<T>(nt, zero)));
199 out.
TNt.assign(M, std::vector<std::vector<T>>(K, std::vector<T>(nt, zero)));
201 for (std::size_t ist = 1; ist <= M; ++ist) {
202 const std::size_t isf =
sn.stateful_of_station(ist);
203 if (isf == 0)
continue;
204 const bool is_source =
sn.stations[ist - 1].nodetype == NodeType::Source;
205 const double S =
sn.stations[ist - 1].nservers;
208 for (std::size_t k = 1; k <= K; ++k)
209 for (std::size_t i = 0; i < nt; ++i) {
211 for (std::size_t s = 0; s < n; ++s)
212 acc += T(out.
pit(i, s) * out.
chain.chain.dep_rates[s][isf - 1][k - 1]);
213 out.
TNt[ist - 1][k - 1][i] = acc;
217 if (is_source)
continue;
219 for (std::size_t k = 1; k <= K; ++k)
220 for (std::size_t i = 0; i < nt; ++i) {
222 for (std::size_t s = 0; s < n; ++s) q += T(out.
pit(i, s) * A(s, (ist - 1) * K + k - 1));
223 out.
QNt[ist - 1][k - 1][i] = q;
226 if (sched == SchedStrategy::INF) {
227 for (std::size_t k = 0; k < K; ++k) out.
UNt[ist - 1][k] = out.
QNt[ist - 1][k];
230 if (sched == SchedStrategy::PS) {
233 for (std::size_t k = 1; k <= K; ++k)
234 for (std::size_t i = 0; i < nt; ++i) {
236 for (std::size_t s = 0; s < n; ++s) {
238 for (std::size_t j = 0; j < K; ++j)
240 if (tot <= 0)
continue;
242 u += T(out.
pit(i, s) *
245 out.
UNt[ist - 1][k - 1][i] = u;
249 if (sched == SchedStrategy::DPS) {
250 const std::vector<T>& w =
sn.stations[ist - 1].schedparam;
251 for (std::size_t k = 1; k <= K; ++k)
252 for (std::size_t i = 0; i < nt; ++i) {
254 for (std::size_t s = 0; s < n; ++s) {
256 for (std::size_t j = 0; j < K; ++j)
259 if (wtot <= 0)
continue;
265 out.
UNt[ist - 1][k - 1][i] = u;
271 for (std::size_t k = 1; k <= K; ++k) {
274 for (std::size_t i = 0; i < nt; ++i) {
276 for (std::size_t s = 0; s < n; ++s) {
280 out.
UNt[ist - 1][k - 1][i] = u;
UnsupportedError(const std::string &what)
A network plus its refreshed NetworkStruct.
Transient distribution of a CTMC by fast adaptive uniformization.
Transient distribution of a CTMC over a time interval, by integrating the forward equations d pi/dt =...
The exception types the port throws.
Dense matrix and non-owning view.
void check_method(const std::string &method)
Port of runAnalyzerChecks' method gate.
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....
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.
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...
SchedStrategy
Scheduling disciplines, with the values of MATLAB SchedStrategy.
TransientResult< T > ctmc_transient_on_grid(const Matrix< T > &Q, const TransientResult< T > &r, const std::vector< T > &grid)
Resample an adaptive transient onto the uniform grid t0 : dt : t1.
TransientResult< T > ctmc_transient(const Matrix< T > &Q, const std::vector< T > &pi0, const T &t0, const T &t1, double rtol=1e-3, double atol=1e-6)
Transient distribution of a CTMC over a time interval, by integrating the forward equations d pi/dt =...
FauResult< T > ctmc_fau(const std::vector< T > &pi0, const Matrix< T > &Q, const T &t, double epsilon=1e-6, double delta=1e-12, long maxsteps=-1)
Transient distribution of a CTMC by fast adaptive uniformization.
bool has_fork_join(const qn::NetworkStruct< T > &sn)
Whether the model needs the tag augmentation at all.
A queueing network and its refreshed NetworkStruct.
Port of solver_ctmc_analyzer.m and the parts of @@SolverCTMC/runAnalyzer.m that surround one solve: t...
The SolverCTMC knobs this port honours.
Everything one CTMC solve produces.
What one transient CTMC solve produces.
std::vector< T > t
the time grid the solver chose
std::vector< std::vector< std::vector< T > > > QNt
Matrix< T > pit
(ntimes x nstates) occupancy
CtmcSolution< T > chain
the generator and its state space
std::vector< std::vector< std::vector< T > > > UNt
std::vector< std::vector< std::vector< T > > > TNt
[station][class][time]
static constexpr double Zero
Matrix< T > D0
The (D0,D1) pair when the type carries one directly.