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);
225 std::function<T(
const T&)> serviceCcdf;
229 serviceCcdf = [sm, one](
const T& x) {
230 std::vector<T> pts(1, x);
234 serviceCcdf = [mu](
const T& x) {
return qsys::detail::num_exp(T(-mu * x)); };
241 const std::string m = detail::fluid_qsys_canonical(
opt.method);
248 auto stationary = [&](
double Lsys,
double Tq,
double Uq) {
249 const double R = Tq > 0 ? Lsys / Tq : 0.0;
251 out.
QN(qi, 0) = Lsys;
254 out.
TN(src, 0) = lamD / VqD;
259 auto transient = [&](
const std::vector<T>& t,
const std::vector<T>& Lt,
260 const std::vector<T>& Ut,
const std::vector<T>& Tt,
261 const std::vector<T>& arrival) {
262 const std::size_t n = t.size();
263 std::vector<double> td(n), Ld(n), Ud(n), Td(n), Ad(n);
264 for (std::size_t i = 0; i < n; ++i) {
271 auto trapz = [&](
const std::vector<double>& y) {
273 for (std::size_t i = 1; i < n; ++i) s += 0.5 * (y[i] + y[i - 1]) * (td[i] - td[i - 1]);
276 const double span = td[n - 1] - td[0];
277 const double Lbar = span > 0 ? trapz(Ld) / span : Ld[0];
278 const double Ubar = span > 0 ? trapz(Ud) / span : Ud[0];
279 const double Tbar = span > 0 ? trapz(Td) / span : Td[0];
280 const double Abar = span > 0 ? trapz(Ad) / span : Ad[0];
281 out.
QN(qi, 0) = Lbar;
282 out.
UN(qi, 0) = Ubar;
283 out.
TN(qi, 0) = Tbar;
284 out.
TN(src, 0) = Abar / VqD;
285 out.
RN(qi, 0) = Tbar > 0 ? Lbar / Tbar : 0.0;
287 out.
CN[0] = out.
RN(qi, 0) * VqD;
288 if (traj !=
nullptr) {
291 for (std::size_t i = 0; i < n; ++i) {
300 p.
TN(src, 0) = Ad[i] / VqD;
306 auto requirePatience = [&]() {
309 "' method needs a reneging patience law on the queue "
310 "(Queue.setPatience)");
312 auto requireFiniteServers = [&]() {
313 if (!std::isfinite(nserv) || nserv < 1)
315 "' method needs a finite number of servers");
317 auto linspaceT = [](
double a,
double b, std::size_t n) {
319 for (std::size_t i = 0; i < n; ++i)
321 static_cast<double>(n - 1));
328 lambda, mu,
static_cast<unsigned>(std::llround(nserv)), h.
ccdf);
331 }
else if (m ==
"ggingi") {
333 requireFiniteServers();
335 lambda, mu,
static_cast<unsigned>(std::llround(nserv)), ca, cs, h.
ccdf, h.
pdf,
340 }
else if (m ==
"tvms") {
342 requireFiniteServers();
344 double t0 = 0, t1 = 0;
345 detail::fluid_qsys_horizon(
sn,
opt, t0, t1);
355 rf.
lambda, [sT](
const T&) { return sT; }, [mu](
const T&) { return mu; }, h.
ccdf,
357 std::vector<T> times = r.
times;
358 for (std::size_t i = 0; i < times.size(); ++i)
360 std::vector<T> served(r.
B.size());
361 for (std::size_t i = 0; i < r.
B.size(); ++i) served[i] = T(mu * r.
B[i]);
363 }
else if (m ==
"mtginf") {
365 double t0 = 0, t1 = 0;
366 detail::fluid_qsys_horizon(
sn,
opt, t0, t1);
368 rf.
lambda, serviceCcdf, ES, linspaceT(t0, t1, 200),
369 -std::numeric_limits<double>::infinity(), ES2);
374 }
else if (m ==
"mol") {
375 requireFiniteServers();
377 double t0 = 0, t1 = 0;
378 detail::fluid_qsys_horizon(
sn,
opt, t0, t1);
379 const double cap =
sn.cap[qi];
382 const bool useDelay = std::isfinite(cap) && cap > nserv;
384 rf.
lambda, serviceCcdf, ES,
static_cast<unsigned>(std::llround(nserv)),
385 linspaceT(t0, t1, 200), -std::numeric_limits<double>::infinity(), useDelay);
389 for (std::size_t i = 0; i < r.
meanBusyMOL.size(); ++i) {
396 "' 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.
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)
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....
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