5#ifndef LINE_SOLVERS_FLUID_FLUID_QSYS_H
6#define LINE_SOLVERS_FLUID_FLUID_QSYS_H
72inline bool fluid_qsys_handles(
const std::string& m) {
73 return m ==
"ggisgi.fluid" || m ==
"ggisgi" || m ==
"ggingi.tga" || m ==
"tga" ||
74 m ==
"tvms" || m ==
"mtginf" || m ==
"mol";
78inline std::string fluid_qsys_canonical(
const std::string& m) {
79 if (m ==
"ggisgi")
return "ggisgi.fluid";
80 if (m ==
"tga")
return "ggingi.tga";
97inline std::string fluid_qsys_horizon_reason(
const FluidOptions& opt) {
98 const double t1 = opt.timespan_end;
99 if (!std::isfinite(t1) || t1 <= 0.0)
100 return "solver_fluid_qsys: a time-varying fluid method needs a finite horizon; set "
101 "options.timespan_end";
102 return std::string();
117void fluid_qsys_horizon(
const qn::NetworkStruct<T>&,
const FluidOptions& opt,
double& t0,
119 const std::string reason = fluid_qsys_horizon_reason(opt);
122 t1 = opt.timespan_end;
136 return m ==
"tvms" || m ==
"mtginf" || m ==
"mol";
155 const std::string m = (method.size() > 6 && method.compare(0, 6,
"fluid.") == 0)
159 const std::string reason = detail::fluid_qsys_horizon_reason(
opt);
160 if (reason.empty())
return std::string();
161 return "the '" + method +
"' method reports a trajectory. " + reason;
173 std::vector<FluidTranPoint>* traj =
nullptr) {
176 "solver_fluid_qsys: the single-station fluid limits integrate and bisect, so they need "
177 "transcendental arithmetic; rerun with --arith double or --arith real");
179 const std::size_t M =
sn.nstations;
180 const std::size_t K =
sn.nclasses;
186 out.
CN.assign(K, 0.0);
187 out.
XN.assign(K, 0.0);
192 bool haveSrc =
false;
194 for (std::size_t i = 0; i <
sn.nof_nodes(); ++i) {
195 if (
sn.nodes[i].nodetype == qn::NodeType::Source) {
196 src =
sn.nodes[i].station - 1;
198 }
else if (
sn.nodes[i].nodetype == qn::NodeType::Queue ||
199 sn.nodes[i].nodetype == qn::NodeType::Delay) {
200 qi =
sn.nodes[i].station - 1;
209 if (!haveSrc || !haveQ)
211 "solver_fluid_qsys: the single-station fluid limits need a Source and a queueing "
213 if (K != 1 ||
sn.nclosedjobs() > 0)
215 "' method is a single-station limit: it needs one open class "
216 "through one Source and one queueing station");
218 const std::size_t qstateful =
sn.stateful_of_station(qi + 1);
219 const T Vq =
sn.visits[0](qstateful - 1, 0);
220 const T lambda = T(
sn.rates(src, 0) * Vq);
221 const T mu =
sn.rates(qi, 0);
222 const double nserv =
sn.stations[qi].nservers;
223 const T scvS =
sn.scv(qi, 0);
232 std::function<T(
const T&)> serviceCcdf;
236 serviceCcdf = [sm, one](
const T& x) {
237 std::vector<T> pts(1, x);
241 serviceCcdf = [mu](
const T& x) {
return qsys::detail::num_exp(T(-mu * x)); };
248 const std::string m = detail::fluid_qsys_canonical(
opt.method);
255 auto stationary = [&](
double Lsys,
double Tq,
double Uq) {
256 const double R = Tq > 0 ? Lsys / Tq : 0.0;
258 out.
QN(qi, 0) = Lsys;
261 out.
TN(src, 0) = lamD / VqD;
266 auto transient = [&](
const std::vector<T>& t,
const std::vector<T>& Lt,
267 const std::vector<T>& Ut,
const std::vector<T>& Tt,
268 const std::vector<T>& arrival) {
269 const std::size_t n = t.size();
270 std::vector<double> td(n), Ld(n), Ud(n), Td(n), Ad(n);
271 for (std::size_t i = 0; i < n; ++i) {
278 auto trapz = [&](
const std::vector<double>& y) {
280 for (std::size_t i = 1; i < n; ++i) s += 0.5 * (y[i] + y[i - 1]) * (td[i] - td[i - 1]);
283 const double span = td[n - 1] - td[0];
284 const double Lbar = span > 0 ? trapz(Ld) / span : Ld[0];
285 const double Ubar = span > 0 ? trapz(Ud) / span : Ud[0];
286 const double Tbar = span > 0 ? trapz(Td) / span : Td[0];
287 const double Abar = span > 0 ? trapz(Ad) / span : Ad[0];
288 out.
QN(qi, 0) = Lbar;
289 out.
UN(qi, 0) = Ubar;
290 out.
TN(qi, 0) = Tbar;
291 out.
TN(src, 0) = Abar / VqD;
292 out.
RN(qi, 0) = Tbar > 0 ? Lbar / Tbar : 0.0;
294 out.
CN[0] = out.
RN(qi, 0) * VqD;
295 if (traj !=
nullptr) {
298 for (std::size_t i = 0; i < n; ++i) {
307 p.
TN(src, 0) = Ad[i] / VqD;
313 auto requirePatience = [&]() {
316 "' method needs a reneging patience law on the queue "
317 "(Queue.setPatience)");
319 auto requireFiniteServers = [&]() {
320 if (!std::isfinite(nserv) || nserv < 1)
322 "' method needs a finite number of servers");
324 auto linspaceT = [](
double a,
double b, std::size_t n) {
326 for (std::size_t i = 0; i < n; ++i)
328 static_cast<double>(n - 1));
332 if (m ==
"ggisgi.fluid") {
335 lambda, mu,
static_cast<unsigned>(std::llround(nserv)), h.
ccdf);
338 }
else if (m ==
"ggingi.tga") {
340 requireFiniteServers();
342 lambda, mu,
static_cast<unsigned>(std::llround(nserv)), ca, cs, h.
ccdf, h.
pdf,
347 }
else if (m ==
"tvms") {
349 requireFiniteServers();
351 double t0 = 0, t1 = 0;
352 detail::fluid_qsys_horizon(
sn,
opt, t0, t1);
362 rf.
lambda, [sT](
const T&) { return sT; }, [mu](
const T&) { return mu; }, h.
ccdf,
364 std::vector<T> times = r.
times;
365 for (std::size_t i = 0; i < times.size(); ++i)
367 std::vector<T> served(r.
B.size());
368 for (std::size_t i = 0; i < r.
B.size(); ++i) served[i] = T(mu * r.
B[i]);
370 }
else if (m ==
"mtginf") {
372 double t0 = 0, t1 = 0;
373 detail::fluid_qsys_horizon(
sn,
opt, t0, t1);
375 rf.
lambda, serviceCcdf, ES, linspaceT(t0, t1, 200),
376 -std::numeric_limits<double>::infinity(), ES2);
381 }
else if (m ==
"mol") {
382 requireFiniteServers();
384 double t0 = 0, t1 = 0;
385 detail::fluid_qsys_horizon(
sn,
opt, t0, t1);
386 const double cap =
sn.cap[qi];
389 const bool useDelay = std::isfinite(cap) && cap > nserv;
391 rf.
lambda, serviceCcdf, ES,
static_cast<unsigned>(std::llround(nserv)),
392 linspaceT(t0, t1, 200), -std::numeric_limits<double>::infinity(), useDelay);
396 for (std::size_t i = 0; i < r.
meanBusyMOL.size(); ++i) {
403 "' 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.
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