5#ifndef LINE_SOLVERS_FLUID_FLUID_QSYS_H
6#define LINE_SOLVERS_FLUID_FLUID_QSYS_H
69inline bool fluid_qsys_handles(
const std::string& m) {
70 return m ==
"ggisgi" || m ==
"ggingi" ||
71 m ==
"tvms" || m ==
"mtginf" || m ==
"mol";
75inline std::string fluid_qsys_canonical(
const std::string& m) {
return m; }
90inline std::string fluid_qsys_horizon_reason(
const FluidOptions& opt) {
91 const double t1 = opt.timespan_end;
92 if (!std::isfinite(t1) || t1 <= 0.0)
93 return "solver_fluid_qsys: a time-varying fluid method needs a finite horizon; set "
94 "options.timespan_end";
110void fluid_qsys_horizon(
const qn::NetworkStruct<T>&,
const FluidOptions& opt,
double& t0,
112 const std::string reason = fluid_qsys_horizon_reason(opt);
115 t1 = opt.timespan_end;
129 return m ==
"tvms" || m ==
"mtginf" || m ==
"mol";
148 const std::string m = (method.size() > 4 && method.compare(0, 4,
"fld.") == 0)
152 const std::string reason = detail::fluid_qsys_horizon_reason(
opt);
153 if (reason.empty())
return std::string();
154 return "the '" + method +
"' method reports a trajectory. " + reason;
166 std::vector<FluidTranPoint>* traj =
nullptr) {
169 "solver_fluid_qsys: the single-station fluid limits integrate and bisect, so they need "
170 "transcendental arithmetic; rerun with --arith double or --arith real");
172 const std::size_t M =
sn.nstations;
173 const std::size_t K =
sn.nclasses;
179 out.
CN.assign(K, 0.0);
180 out.
XN.assign(K, 0.0);
185 bool haveSrc =
false;
187 for (std::size_t i = 0; i <
sn.nof_nodes(); ++i) {
188 if (
sn.nodes[i].nodetype == qn::NodeType::Source) {
189 src =
sn.nodes[i].station - 1;
191 }
else if (
sn.nodes[i].nodetype == qn::NodeType::Queue ||
192 sn.nodes[i].nodetype == qn::NodeType::Delay) {
193 qi =
sn.nodes[i].station - 1;
202 if (!haveSrc || !haveQ)
204 "solver_fluid_qsys: the single-station fluid limits need a Source and a queueing "
206 if (K != 1 ||
sn.nclosedjobs() > 0)
208 "' method is a single-station limit: it needs one open class "
209 "through one Source and one queueing station");
211 const std::size_t qstateful =
sn.stateful_of_station(qi + 1);
212 const T Vq =
sn.visits[0](qstateful - 1, 0);
213 const T lambda = T(
sn.rates(src, 0) * Vq);
214 const T mu =
sn.rates(qi, 0);
215 const double nserv =
sn.stations[qi].nservers;
216 const T scvS =
sn.scv(qi, 0);
229 std::function<T(
const T&)> serviceCcdf;
233 serviceCcdf = [sm, one](
const T& x) {
234 std::vector<T> pts(1, x);
238 serviceCcdf = [mu](
const T& x) {
return qsys::detail::num_exp(T(-mu * x)); };
245 const std::string m = detail::fluid_qsys_canonical(
opt.method);
252 auto stationary = [&](
double Lsys,
double Tq,
double Uq) {
253 const double R = Tq > 0 ? Lsys / Tq : 0.0;
255 out.
QN(qi, 0) = Lsys;
258 out.
TN(src, 0) = lamD / VqD;
263 auto transient = [&](
const std::vector<T>& t,
const std::vector<T>& Lt,
264 const std::vector<T>& Ut,
const std::vector<T>& Tt,
265 const std::vector<T>& arrival) {
266 const std::size_t n = t.size();
267 std::vector<double> td(n), Ld(n), Ud(n), Td(n), Ad(n);
268 for (std::size_t i = 0; i < n; ++i) {
275 auto trapz = [&](
const std::vector<double>& y) {
277 for (std::size_t i = 1; i < n; ++i) s += 0.5 * (y[i] + y[i - 1]) * (td[i] - td[i - 1]);
280 const double span = td[n - 1] - td[0];
281 const double Lbar = span > 0 ? trapz(Ld) / span : Ld[0];
282 const double Ubar = span > 0 ? trapz(Ud) / span : Ud[0];
283 const double Tbar = span > 0 ? trapz(Td) / span : Td[0];
284 const double Abar = span > 0 ? trapz(Ad) / span : Ad[0];
285 out.
QN(qi, 0) = Lbar;
286 out.
UN(qi, 0) = Ubar;
287 out.
TN(qi, 0) = Tbar;
288 out.
TN(src, 0) = Abar / VqD;
289 out.
RN(qi, 0) = Tbar > 0 ? Lbar / Tbar : 0.0;
291 out.
CN[0] = out.
RN(qi, 0) * VqD;
292 if (traj !=
nullptr) {
295 for (std::size_t i = 0; i < n; ++i) {
304 p.
TN(src, 0) = Ad[i] / VqD;
310 auto requirePatience = [&]() {
313 "' method needs a reneging patience law on the queue "
314 "(Queue.setPatience)");
316 auto requireFiniteServers = [&]() {
317 if (!std::isfinite(nserv) || nserv < 1)
319 "' method needs a finite number of servers");
321 auto linspaceT = [](
double a,
double b, std::size_t n) {
323 for (std::size_t i = 0; i < n; ++i)
325 static_cast<double>(n - 1));
332 lambda, mu,
static_cast<unsigned>(std::llround(nserv)), h.
ccdf);
335 }
else if (m ==
"ggingi") {
337 requireFiniteServers();
339 lambda, mu,
static_cast<unsigned>(std::llround(nserv)), ca, cs, h.
ccdf, h.
pdf,
344 }
else if (m ==
"tvms") {
346 requireFiniteServers();
348 double t0 = 0, t1 = 0;
349 detail::fluid_qsys_horizon(
sn,
opt, t0, t1);
359 rf.
lambda, [sT](
const T&) { return sT; }, [mu](
const T&) { return mu; }, h.
ccdf,
361 std::vector<T> times = r.
times;
362 for (std::size_t i = 0; i < times.size(); ++i)
364 std::vector<T> served(r.
B.size());
365 for (std::size_t i = 0; i < r.
B.size(); ++i) served[i] = T(mu * r.
B[i]);
367 }
else if (m ==
"mtginf") {
369 double t0 = 0, t1 = 0;
370 detail::fluid_qsys_horizon(
sn,
opt, t0, t1);
372 rf.
lambda, serviceCcdf, ES, linspaceT(t0, t1, 200),
373 -std::numeric_limits<double>::infinity(), ES2);
378 }
else if (m ==
"mol") {
379 requireFiniteServers();
381 double t0 = 0, t1 = 0;
382 detail::fluid_qsys_horizon(
sn,
opt, t0, t1);
383 const double cap =
sn.cap[qi];
386 const bool useDelay = std::isfinite(cap) && cap > nserv;
388 rf.
lambda, serviceCcdf, ES,
static_cast<unsigned>(std::llround(nserv)),
389 linspaceT(t0, t1, 200), -std::numeric_limits<double>::infinity(), useDelay);
393 for (std::size_t i = 0; i < r.
meanBusyMOL.size(); ++i) {
400 "' method is not a single-station fluid limit");
UnsupportedError(const std::string &what)
A network plus its refreshed NetworkStruct.
Cumulative distribution of the inter-arrival time of a MAP.
PatienceHandles< T > sn_patience_handles(const qn::NetworkStruct< T > &sn, std::size_t ist, std::size_t r)
Build the patience handles of station ist (0-based), class r.
std::string sn_patience_refusal(const qn::NetworkStruct< T > &sn, std::size_t ist, std::size_t r)
Port of sn_patience_refusal.m: the by-name refusal of a reneging patience that is not a Markovian law...
ArrivalRateFun< T > sn_arrival_rate_fun(const qn::NetworkStruct< T > &sn, std::size_t ist, std::size_t r)
Build lambda(t) for station ist (0-based), class r.
std::string fluid_qsys_horizon_supports(const std::string &method, const FluidOptions &opt)
The horizon rule the time-varying limits impose, as a public predicate a REPORT can ask: empty when m...
bool fluid_is_time_varying_limit(const std::string &m)
The three single-station limits that report a TRAJECTORY rather than a stationary point,...
FluidSolution solver_fluid_qsys(const qn::NetworkStruct< T > &sn, const FluidOptions &opt, std::vector< FluidTranPoint > *traj=nullptr)
Solve a single-station model with one of the closed-form fluid limits.
mam::Map< T > dist_to_map(const Distrib< T > &d)
The (D0,D1) pair that reaches sn.proc.
std::vector< T > map_cdf(const Map< T > &m, const std::vector< T > &points)
Cumulative distribution of the inter-arrival time at the given points.
QsysTvFluidResult< Tv > qsys_gtmtst_fluid(const std::function< Tv(const Tv &)> &lambdaFun, const std::function< Tv(const Tv &)> &sFun, const std::function< Tv(const Tv &)> &muFun, const std::function< Tv(const Tv &)> &patienceCcdf, const Tv &T, const TvFluidOptions< Tv > &opts=TvFluidOptions< Tv >())
The Gt/Mt/st+GI many-server fluid queue, and the network of them.
QsysFluidAbandonResult< T > qsys_ggisgi_fluid(const T &lambda, const T &mu, unsigned s, const std::function< T(const T &)> &patienceCcdf, const std::function< T(const T &)> &servingCcdf=std::function< T(const T &)>(), const std::vector< T > &agePoints=std::vector< T >(), double tol=1e-12, double maxTime=std::numeric_limits< double >::quiet_NaN())
Steady state of the G/GI/s+GI fluid model.
QsysMtginfResult< T > qsys_mtginf(const std::function< T(const T &)> &lambdaFun, const std::function< T(const T &)> &serviceCcdf, const T &ES, const std::vector< T > &tvals, double startTime=-std::numeric_limits< double >::infinity(), double ES2=std::numeric_limits< double >::quiet_NaN(), const std::function< T(const T &)> &servicePdf=std::function< T(const T &)>(), double tol=1e-12, std::size_t panels=4000, double maxAge=1e12)
Exact time-varying analysis of the Mt/G/infinity queue.
QsysMolResult< T > qsys_mtgs0_mol(const std::function< T(const T &)> &lambdaFun, const std::function< T(const T &)> &serviceCcdf, const T &ES, unsigned s, const std::vector< T > &tvals, double startTime=-std::numeric_limits< double >::infinity(), bool delay=false)
Modified-offered-load and pointwise-stationary approximations for a time-varying multiserver system.
QsysTgaResult< T > qsys_ggingi_tga(const T &lambda, const T &mu, unsigned n, const T &ca, const T &cs, const std::function< T(const T &)> &patienceCcdf, const std::function< T(const T &)> &patiencePdf=std::function< T(const T &)>(), const std::function< T(const T &)> &serviceCcdf=std::function< T(const T &)>())
Truncated Gaussian approximation (TGA-G) for the G/GI/n+GI queue.
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.
Truncated Gaussian approximation (TGA-G) for the G/GI/n+GI queue.
Steady state of the G/GI/s+GI fluid model.
The Gt/Mt/st+GI many-server fluid queue, and the network of them.
Exact time-varying analysis of the Mt/G/infinity queue.
Modified-offered-load and pointwise-stationary approximations for a time-varying multiserver system.
Port of matlab/src/api/sn/sn_arrival_rate_fun.m.
Port of matlab/src/api/sn/sn_patience_handles.m.
SolverFluid: the closing method, a port of solver_fluid.m, solver_fluid_iteration....
The <kind> part of a LINE:<category>:<kind> identifier (see _kb/17-error-vocabulary....
lambda(t), with whether it actually varies and the cycle length.
std::function< T(const T &)> lambda
the rate as a function of time
The patience law of one station-class pair, in the forms the solvers consume.
std::function< T(const T &)> pdf
The patience density.
std::function< T(const T &)> ccdf
F^c(t) = P(patience > t).
bool present
Whether the pair declares reneging at all; everything below is unset when false.
Controls, defaulting to SolverOptions('Fluid') in the reference.
What the analyzer returns, in the same shape as the MVA solver's result.
One point of a transient trajectory: the metrics at time t.
bool has_map() const
True when the type carries a (D0,D1) pair of its own.
A MAP as the pair of matrices (D0, D1).
Steady state of the G/GI/s+GI fluid model.
T throughput
min(lambda, s mu)
MOL and PSA measures of a time-varying multiserver system.
std::vector< T > times
the evaluation times
std::vector< T > meanBusyMOL
carried load m(t)(1-B), or min(m,s) for the delay model
std::vector< T > arrivalRate
lambda(t)
Time-varying measures of the Mt/G/infinity queue.
std::vector< T > meanNumber
m(t), the Poisson mean
std::vector< T > times
the evaluation times
std::vector< T > arrivalRate
lambda(t)
Steady-state measures of the G/GI/n+GI truncated Gaussian approximation.
T meanNumberInService
E[B].
T meanNumber
E[X] = E[B] + E[Q].
T probAbandon
P(patience < wait).
Trajectory of the Gt/Mt/st+GI fluid queue; every vector is on the time grid.
std::vector< T > utilization
B/s.
std::vector< T > arrivalRate
lambda on the grid
std::vector< T > B
fluid in service
std::vector< T > times
the time grid
Options of qsys_gtmtst_fluid, all with the MATLAB defaults.
std::function< T(const T &)> pdf
patience density; differenced when empty