5#ifndef LINE_SOLVERS_MVA_SOLVER_MVA_PROB_H
6#define LINE_SOLVERS_MVA_SOLVER_MVA_PROB_H
63T num_nchoosekln(
const T& n,
const T& k) {
64 return T(pfqn::detail::num_factln<T>(n) - pfqn::detail::num_factln<T>(k) -
65 pfqn::detail::num_factln<T>(T(n - k)));
79T binom_logterm(
const T& N,
const T& n,
const T& Q) {
88 T
lp = num_nchoosekln<T>(N, n);
90 if (n > zero)
lp += T(n * log(p));
91 if (T(N - n) > zero)
lp += T(T(N - n) * log(T(one - p)));
117 std::size_t ist, std::size_t r,
118 const std::vector<long>& states,
119 const std::string& method =
"default") {
121 "getProbMarg fits a binomial / Poisson / geometric law and needs logarithms");
127 throw InputError(
"getProbMarg: station index exceeds the number of stations in the model");
129 throw InputError(
"getProbMarg: job class index exceeds the number of classes in the model");
133 const double Nr = L.
classes[r - 1].population;
136 if (std::isfinite(Nr)) {
140 if (method ==
"exact")
141 for (std::size_t s = 0; s < L.
nstations; ++s)
144 "getProbMarg: exact marginalized probabilities require single-server "
147 const long n_max =
static_cast<long>(Nr);
148 std::vector<T> all(
static_cast<std::size_t
>(n_max) + 1, zero), alllog(all.size(), zero);
150 for (
long k = 0; k <= n_max; ++k) {
153 alllog[
static_cast<std::size_t
>(k)] =
lp;
154 all[
static_cast<std::size_t
>(k)] = exp(
lp);
156 if (states.empty()) {
161 for (
long s : states) {
162 if (s < 0 || s > n_max)
164 "getProbMarg: the requested state exceeds the maximum population for this "
166 out.
P.push_back(all[
static_cast<std::size_t
>(s)]);
167 out.
logP.push_back(alllog[
static_cast<std::size_t
>(s)]);
178 out.
P.push_back(one);
179 out.
logP.push_back(zero);
183 std::vector<long> sm = states;
185 const T lam = avg.
QN(ist - 1, r - 1);
188 const long nm = std::max<long>(
189 1,
static_cast<long>(std::ceil(lamd + 5.0 * std::sqrt(std::max(lamd, 1.0)))));
190 for (
long n = 0; n <= nm; ++n) sm.push_back(n);
198 lp = (n == 0) ? zero : neg_inf;
201 out.
P.push_back(n == 0 && !(lam > zero) ? one : exp(
lp));
209 const T rho_r = avg.
UN(ist - 1, r - 1);
211 for (std::size_t k = 0; k < L.
nclasses; ++k) {
212 const T u = avg.
UN(ist - 1, k);
216 if (rho_tot > rho_cap) rho_tot = rho_cap;
220 if (rho_r > zero && rho_tot < one) {
221 const T denom = T(one - rho_tot + rho_r);
223 if (ratio > 0.0 && ratio < 1.0)
224 nm = std::max<long>(1,
static_cast<long>(std::ceil(-std::log(1e-10) / -std::log(ratio))));
225 nm = std::min<long>(nm, 1000);
227 for (
long n = 0; n <= nm; ++n) sm.push_back(n);
229 if (!(rho_tot < rho_cap)) {
230 out.
P.assign(sm.size(), zero);
231 out.
logP.assign(sm.size(), neg_inf);
234 const T denom = T(one - rho_tot + rho_r);
239 lp = T(log(T(one - rho_tot)) + nn * log(rho_r) - T(nn + one) * log(denom));
241 lp = T(log(T(one - rho_tot)) - log(denom));
246 out.
P.push_back(exp(
lp));
304 std::size_t ist,
const std::string& method =
"default") {
306 "getProbAggr fits a binomial / product-form law and needs logarithms");
310 throw InputError(
"getProbAggr: station number exceeds the number of stations in the model");
311 const std::size_t i = ist - 1;
313 const Matrix<T> nir = detail::initial_marginal(L);
315 bool all_closed =
true;
316 for (std::size_t r = 0; r < L.
nclasses; ++r)
317 if (!std::isfinite(L.
classes[r].population)) all_closed =
false;
321 if (all_closed && method ==
"exact")
323 "getProbAggr: exact marginal state probabilities are not available yet in SolverMVA");
330 logP = T(logP + term.
logp);
333 for (std::size_t r = 0; r < L.
nclasses; ++r) {
334 if (!std::isfinite(L.
classes[r].population))
continue;
336 logP = T(logP + detail::binom_logterm<T>(N, nir(i, r), avg.
QN(i, r)));
338 return {T(exp(logP)), logP};
351 const std::string& method =
"default") {
353 "getProbSysAggr fits a binomial / product-form law and needs logarithms");
357 const Matrix<T> nir = detail::initial_marginal(L);
359 bool all_closed =
true;
360 for (std::size_t r = 0; r < L.
nclasses; ++r)
361 if (!std::isfinite(L.
classes[r].population)) all_closed =
false;
365 if (all_closed && method ==
"exact")
367 "getProbSysAggr: exact joint state probabilities are not available yet in SolverMVA");
371 for (std::size_t r = 0; r < L.
nclasses; ++r)
374 for (std::size_t i = 0; i < L.
nstations; ++i)
375 for (std::size_t r = 0; r < L.
nclasses; ++r) {
383 if (L.
classes[r].population == 0.0)
continue;
385 logP = T(logP - pfqn::detail::num_factln<T>(nir(i, r)));
386 if (avg.
QN(i, r) > zero)
387 logP = T(logP + nir(i, r) * log(T(avg.
QN(i, r) / N)));
389 return {T(exp(logP)), logP};
393 for (std::size_t r = 0; r < L.
nclasses; ++r)
394 if (std::isfinite(L.
classes[r].population))
397 for (std::size_t i = 0; i < L.
nstations; ++i) {
400 logP = T(logP + term.
logp);
401 for (std::size_t r = 0; r < L.
nclasses; ++r) {
402 if (!std::isfinite(L.
classes[r].population))
continue;
404 if (L.
classes[r].population == 0.0)
continue;
406 logP = T(logP - pfqn::detail::num_factln<T>(nir(i, r)));
407 if (avg.
QN(i, r) > zero) logP = T(logP + nir(i, r) * log(T(avg.
QN(i, r) / N)));
410 return {T(exp(logP)), logP};
UnsupportedError(const std::string &what)
A network plus its refreshed NetworkStruct.
std::vector< JobClass > classes
std::vector< Station< T > > stations
stations[k-1] is the k-th station
Matrix< T > sn_declared_marginal(const qn::NetworkStruct< T > &sn)
The (nstations x nclasses) per-class job counts of the model's OWN state.
OpenProbTerm< T > sn_open_prob_terms(const qn::NetworkStruct< T > &sn, const Matrix< T > &Q, const Matrix< T > &U, const Matrix< T > &nir, std::size_t ist)
Open-class contribution to an aggregate state probability at one station.
SchedStrategy
Scheduling disciplines, with the values of MATLAB SchedStrategy.
AggrResult< T > solver_mva_get_prob_aggr(const qn::NetworkStruct< T > &L, const AvgResult< T > &avg, std::size_t ist, const std::string &method="default")
T solver_mva_get_prob_norm_const_aggr(const qn::NetworkStruct< T > &L, const MvaOptions &opt)
Port of @@SolverMVA/getProbNormConstAggr.m: log G.
MargResult< T > solver_mva_get_prob_marg(const qn::NetworkStruct< T > &L, const AvgResult< T > &avg, std::size_t ist, std::size_t r, const std::vector< long > &states, const std::string &method="default")
Port of @@SolverMVA/getProbMarg.m: P(n jobs of class r at station i) for the states in states (or the...
AggrResult< T > solver_mva_get_prob_sys_aggr(const qn::NetworkStruct< T > &L, const AvgResult< T > &avg, const std::string &method="default")
Port of @@SolverMVA/getProbSysAggr.m: the joint probability of the model's whole state across all sta...
DispatchResult< T > mva_dispatch(const qn::NetworkStruct< T > &L, const MvaOptions &opt, const Matrix< T > &init_sol)
The ladder itself.
A queueing network and its refreshed NetworkStruct.
Shared scalar machinery for the integration / asymptotic members of the pfqn family (pfqn_le,...
Open-class contribution to an aggregate state probability at one station.
Ports of matlab/src/api/sn/sn_get_state_aggr.m and sn_is_state_valid.m.
The SolverMVA class surface: @@SolverMVA/runAnalyzer.m and the gates around it.
The log contribution, and whether the state carries any mass at all.
bool feasible
false when the law gives the state zero probability
T logp
log of the open-class factor at this station
Port of @@SolverMVA/getProbAggr.m: P(n1 jobs of class 1, n2 of class 2, ...) at station ist for the m...
The metrics getAvg returns, after filtering.
Matrix< T > UN
utilization
Matrix< T > QN
queue length
What the dispatch returns: the metrics plus the algorithm that produced them.
static constexpr double FineTol
A marginal distribution and its logarithm, over the states asked for.
The options SolverMVA reads.