5#ifndef LINE_SOLVERS_BA_SOLVER_BA_QRF_ANALYZER_H
6#define LINE_SOLVERS_BA_SOLVER_BA_QRF_ANALYZER_H
56inline bool is_qrf_noblo_method(
const std::string& m) {
57 return m ==
"qrf.mmi" || m ==
"qrf.mem" || m ==
"qrf.bethe" || m ==
"qrf.mmi.ld" ||
58 m ==
"qrf.mmi.linear";
62inline bool is_qrf_lp_method(
const std::string& m) {
return m ==
"qrf.bas" || m ==
"qrf.rsrd"; }
65inline bool is_qrf_bas_nlp_method(
const std::string& m) {
66 return m ==
"qrf.bas.mem" || m ==
"qrf.bas.bethe" || m ==
"qrf.bas.mmi";
71void qrf_blocks_from_maps(
const std::vector<std::pair<Matrix<T>, Matrix<T> > >& MAPs,
72 const std::vector<int>& K, std::vector<Matrix<T> >* mu,
73 std::vector<Matrix<T> >* v) {
74 const T zero = num_traits<T>::from_int(0);
75 const std::size_t M = MAPs.size();
76 mu->assign(M, Matrix<T>());
77 v->assign(M, Matrix<T>());
78 for (std::size_t i = 0; i < M; ++i) {
79 const std::size_t k =
static_cast<std::size_t
>(K[i]);
82 for (std::size_t h = 0; h < k; ++h)
83 for (std::size_t j = 0; j < k; ++j) {
84 (*mu)[i](h, j) = MAPs[i].second(h, j);
87 (*v)[i](h, j) = (h == j) ? zero : MAPs[i].first(h, j);
94mapqn::QrBasParams<T> qrf_bas_params(
95 const qn::NetworkStruct<T>& L,
const BaOptions& opt,
96 const std::vector<std::pair<Matrix<T>, Matrix<T> > >& MAPs,
const std::vector<int>& K,
97 const Matrix<T>& rt, std::size_t N,
bool require_capacity) {
98 const std::size_t M = L.nstations;
99 (void)require_capacity;
106 BaOptions::QrfParams derived;
107 if (!opt.qrf_params.supplied) {
109 for (std::size_t i = 0; i < K.size(); ++i) Ktot += std::max(1, K[i]);
111 if (!blk.msg.
empty())
113 "' method cannot be applied to this model: " + blk.msg +
114 " Supply options.config.qrf_params explicitly to override the "
116 derived.supplied =
true;
121 derived.MM1 = blk.MM1;
125 const BaOptions::QrfParams& qp = opt.qrf_params.supplied ? opt.qrf_params : derived;
127 std::vector<int> F = qp.F;
133 if (!cap.msg.empty())
135 "' method cannot be applied: " + cap.msg);
138 std::vector<Matrix<T> > mu, v;
139 qrf_blocks_from_maps(MAPs, K, &mu, &v);
141 mapqn::QrBasParams<T> bp;
142 bp.M =
static_cast<int>(M);
143 bp.N =
static_cast<int>(N);
155 bp.MM.assign(qp.MM.size(), std::vector<int>());
156 for (std::size_t m = 0; m < qp.MM.size(); ++m)
157 for (std::size_t c = 0; c < qp.MM[m].size(); ++c) bp.MM[m].push_back(qp.MM[m][c] - 1);
158 bp.MM1.assign(qp.MM1.size(), std::vector<int>());
159 for (std::size_t m = 0; m < qp.MM1.size(); ++m)
160 for (std::size_t j = 0; j < qp.MM1[m].size(); ++j) bp.MM1[m].push_back(qp.MM1[m][j] - 1);
162 for (std::size_t m = 0; m < bp.ZZ.size(); ++m) bp.ZM = std::max(bp.ZM, bp.ZZ[m]);
168std::vector<T> qrf_lp_utilizations(
const qn::NetworkStruct<T>& L,
const BaOptions& opt,
169 const std::vector<std::pair<Matrix<T>, Matrix<T> > >& MAPs,
170 const std::vector<int>& K,
const Matrix<T>& rt,
171 const Matrix<T>& alpha, std::size_t N) {
172 const std::size_t M = L.nstations;
173 if (opt.method ==
"qrf.rsrd") {
179 std::vector<int> F = opt.qrf_params.F;
182 if (!cap.msg.empty())
183 throw UnsupportedError(
"solver_ba_qrf_analyzer: the 'qrf.rsrd' method cannot be "
184 "applied: " + cap.msg);
187 std::vector<Matrix<T> > mu, v;
188 qrf_blocks_from_maps(MAPs, K, &mu, &v);
189 mapqn::QrRsrdParams<T> rp;
190 rp.M =
static_cast<int>(M);
191 rp.N =
static_cast<int>(N);
197 if (alpha.rows() == M && alpha.cols() > 0) {
198 rp.alpha.assign(M, std::vector<T>());
199 for (std::size_t i = 0; i < M; ++i)
200 for (std::size_t n = 0; n < alpha.cols(); ++n) rp.alpha[i].push_back(alpha(i, n));
204 throw NumericError(
"solver_ba_qrf_analyzer: the 'qrf.rsrd' linear program did not "
205 "solve (" + res.status +
")");
209 const mapqn::QrBasParams<T> bp = qrf_bas_params(L, opt, MAPs, K, rt, N,
false);
212 throw NumericError(
"solver_ba_qrf_analyzer: the 'qrf.bas' linear program did not solve (" +
224std::vector<T> qrf_qn_from_bounds(
const qn::NetworkStruct<T>& L,
const std::vector<T>& UN,
225 const std::vector<T>& V,
const std::vector<T>& stimes,
227 const T zero = num_traits<T>::from_int(0);
228 const T one = num_traits<T>::from_int(1);
229 const std::size_t M = L.nstations;
231 for (std::size_t i = 0; i < M; ++i) {
232 const T c = num_traits<T>::from_double(L.stations[i].nservers);
233 if (stimes[i] > zero && V[i] > zero && UN[i] > zero) {
234 X = T(UN[i] * c / T(V[i] * stimes[i]));
238 std::vector<T>
QN(M, zero);
239 for (std::size_t i = 0; i < M; ++i) {
240 if (!(stimes[i] > zero))
continue;
241 const T Ti = T(X * V[i]);
242 QN[i] = (
UN[i] < one) ? T(T(Ti * stimes[i]) / T(one - UN[i]))
243 : num_traits<T>::from_int(
static_cast<long>(N));
260 const std::string& method =
opt.method;
264 throw UnsupportedError(
"solver_ba_qrf_analyzer: QRF methods support single-class networks "
266 for (
double n : L.
njobs())
268 throw UnsupportedError(
"solver_ba_qrf_analyzer: QRF methods support closed networks "
270 const std::size_t N =
static_cast<std::size_t
>(L.
nclosedjobs());
272 throw UnsupportedError(
"solver_ba_qrf_analyzer: QRF methods support closed networks only");
288 const bool method_is_ld = (method ==
"qrf.mmi.ld" || method ==
"qrf.mmi.linear");
289 if (alpha_sn.
ld && !method_is_ld)
291 "solver_ba_qrf_analyzer: the '" + method +
292 "' method models every station as a single server: its transition rates carry no "
293 "population index, so it has nowhere to put the rate of a delay, a multiserver or a "
294 "load-dependent station. Use 'qrf.mmi.ld' or 'qrf.mmi.linear', which do");
295 if (!alpha_sn.
msg.empty())
297 "' method cannot be applied: " + alpha_sn.
msg);
301 std::vector<std::pair<Matrix<T>,
Matrix<T>>> MAPs(M);
302 std::vector<int> K_phases(M, 1);
303 for (std::size_t i = 0; i < M; ++i) {
305 if (m.
D0.rows() == 0) {
307 MAPs[i] = std::make_pair(D0, D1);
310 MAPs[i] = std::make_pair(m.
D0, m.
D1);
311 K_phases[i] =
static_cast<int>(m.
D0.rows());
317 for (std::size_t i = 0; i < M; ++i)
318 for (std::size_t j = 0; j < M; ++j) rt(i, j) = L.
rt(i, j);
327 if (
opt.qrf_alpha.rows() > 0) {
328 if (
opt.qrf_alpha.rows() != M ||
opt.qrf_alpha.cols() != N)
329 throw InputError(
"solver_ba_qrf_analyzer: qrf_alpha must be (nstations x N)");
330 for (std::size_t i = 0; i < M; ++i)
331 for (std::size_t n = 0; n < N; ++n)
334 for (std::size_t i = 0; i < M; ++i)
335 for (std::size_t n = 0; n < N; ++n)
340 if (detail::is_qrf_lp_method(method)) {
341 r.
UN = detail::qrf_lp_utilizations(L,
opt, MAPs, K_phases, rt, alpha, N);
344 "solver_ba_qrf_analyzer: the QRF objective is the MEM entropy, the mutual "
345 "information or the tree-reweighted free entropy, all of which take a log, and "
346 "exact arithmetic has no representation for it; use the double or real backend");
348 if (method ==
"qrf.mmi")
350 else if (method ==
"qrf.mem")
352 else if (method ==
"qrf.bethe")
358 else if (method ==
"qrf.mmi.ld")
360 else if (method ==
"qrf.mmi.linear")
362 else if (method ==
"qrf.bas.mmi")
364 detail::qrf_bas_params(L,
opt, MAPs, K_phases, rt, N,
true));
365 else if (method ==
"qrf.bas.bethe")
369 detail::qrf_bas_params(L,
opt, MAPs, K_phases, rt, N,
true));
370 else if (detail::is_qrf_bas_nlp_method(method))
372 detail::qrf_bas_params(L,
opt, MAPs, K_phases, rt, N,
true));
374 throw UnsupportedError(
"solver_ba_qrf_analyzer: unknown QRF method '" + method +
"'");
378 std::vector<T> V(M, zero);
379 for (std::size_t c = 0; c < L.
nchains; ++c)
380 for (std::size_t i = 0; i < M; ++i)
383 std::vector<T> stimes(M, zero);
384 for (std::size_t i = 0; i < M; ++i) {
386 m.
D0 = MAPs[i].first;
387 m.
D1 = MAPs[i].second;
393 if (r.
QN.empty()) r.
QN = detail::qrf_qn_from_bounds(L, r.
UN, V, stimes, N);
397 for (
const T& q : r.
QN) qsum += q;
398 std::vector<T> QN = r.
QN;
406 if (r.
BN.empty()) r.
BN = r.
UN;
417 for (std::size_t i = 0; i < M; ++i) {
418 if (stimes[i] > zero && V[i] > zero && r.
BN[i] > zero) {
419 X = T(r.
BN[i] / T(V[i] * stimes[i]));
424 const std::size_t rs = L.
classes[0].refstat;
425 if (rs >= 1 && rs <= M && stimes[rs - 1] > zero && V[rs - 1] > zero)
426 X = T(QN[rs - 1] / T(V[rs - 1] * stimes[rs - 1]));
434 for (std::size_t i = 0; i < M; ++i) {
436 s.
Tp(i, 0) = T(X * V[i]);
437 if (std::isinf(alpha_sn.
peak[i]))
447 if (s.
Tp(i, 0) > zero) s.
R(i, 0) = T(s.
Q(i, 0) / s.
Tp(i, 0));
451 s.
lG = std::numeric_limits<double>::quiet_NaN();
NumericError(const std::string &what)
UnsupportedError(const std::string &what)
A network plus its refreshed NetworkStruct.
std::size_t stateful_of_station(std::size_t st) const
std::vector< std::vector< Distrib< T > > > service
service[i][r], 0-based station and class; a disabled entry marks a pair never visited.
Matrix< T > rt
sn.rt and sn.rtnodes: the class-expanded routing.
std::vector< JobClass > classes
std::vector< double > njobs() const
sn.njobs: the population of each class, infinite for an open one.
std::vector< Matrix< T > > visits
(nchains) each (nstateful x nclasses)
double nclosedjobs() const
sn.nclosedjobs: the total population of the closed classes.
Markovian arrival process descriptors: stationary vectors, rate, moments, autocorrelation and the ind...
Quadratic-reduction bound on the utilization of one queue of a closed MAP queueing network with a FIN...
Quadratic-reduction bound on the utilization of one queue of a closed MAP queueing network under RS-R...
qrf_bas_mmi, qrf_bas_mem and qrf_bas_bethe: the nonlinear bounds on the BAS-BLOCKING polytope.
The QRF no-blocking nonlinear bounds: qrf_noblo_mmi, qrf_noblo_mem and the load-dependent qrf_noblo_m...
BaSolution< T > solver_ba_qrf_analyzer(const qn::NetworkStruct< T > &L, const BaOptions &opt)
Port of solver_ba_qrf_analyzer.
mam::Map< T > dist_to_map(const Distrib< T > &d)
T map_mean(const Map< T > &m)
Mean inter-arrival time, 1/lambda.
QrfMetrics< T > mapqn_qrf_bas_mmi(const QrBasParams< T > &p, unsigned max_iter=200)
Minimum-mutual-information bound on the BAS-blocking polytope.
QrfMetrics< T > qrf_noblo_mem(const std::vector< std::pair< Matrix< T >, Matrix< T > > > &MAPs, std::size_t N, const Matrix< T > &rt)
qrf_noblo_mem: the same polytope under maximum entropy.
QrfMetrics< T > qrf_noblo_mmi_ld(std::size_t M, const std::vector< int > &K, std::size_t N, const Matrix< T > &mu, const Matrix< T > &v, const Matrix< T > &rt, const Matrix< T > &alpha)
qrf_noblo_mmi_ld: MMI on the LOAD-DEPENDENT polytope.
QrfMetrics< T > mapqn_qrf_bas_bethe(const QrBasParams< T > &p, unsigned max_iter=200)
Tree-reweighted (Bethe) free entropy bound on the BAS-blocking polytope.
QrfMetrics< T > qrf_noblo_mmi(std::size_t M, const std::vector< int > &K, std::size_t N, const Matrix< T > &mu, const Matrix< T > &v, const Matrix< T > &rt)
qrf_noblo_mmi: the no-blocking bound under mutual-information minimization.
QrfMetrics< T > mapqn_qrf_bas_mem(const QrBasParams< T > &p, unsigned max_iter=200)
Maximum-entropy bound on the BAS-blocking polytope.
QrfMetrics< T > qrf_noblo_mmi_linear(const std::vector< std::pair< Matrix< T >, Matrix< T > > > &MAPs, std::size_t N, const Matrix< T > &rt, const Matrix< T > &alpha)
qrf_noblo_mmi_linear: the load-dependent no-blocking bound, under MMI.
QrRsrdResult< T > mapqn_qr_bounds_rsrd(const QrRsrdParams< T > &p, int objective_queue, MapqnSense sense=MapqnSense::Min)
Bound the utilization of one queue over the RS-RD polytope.
QrfMetrics< T > qrf_noblo_bethe(std::size_t M, const std::vector< int > &K, std::size_t N, const Matrix< T > &mu, const Matrix< T > &v, const Matrix< T > &rt)
qrf_noblo_bethe: the same polytope under the tree-reweighted free entropy.
QrBasResult< T > mapqn_qr_bounds_bas(const QrBasParams< T > &p, int objective_queue, MapqnSense sense=MapqnSense::Min)
Bound the utilization of one queue over the BAS polytope.
void qrf_extract_mu_v(const std::vector< std::pair< Matrix< T >, Matrix< T > > > &MAPs, std::size_t M, const std::vector< int > &K, Matrix< T > *mu, Matrix< T > *v)
extract_mu_v_from_maps: the completion and background rates of each MAP.
QrfBlocking sn_to_qrf_blocking(const qn::NetworkStruct< T > &sn, int Ktot, double max_vars=kQrfDefaultMaxVars)
The QRF BAS blocking tables (f, MR, BB, MM, ZZ, MM1), derived from an sn.
QrfCapacity sn_to_qrf_capacity(const qn::NetworkStruct< T > &sn)
F is an OCCUPANCY BOUND, not a declared capacity: the station's buffer where that buffer BINDS,...
QrfAlpha sn_to_qrf_alpha(const qn::NetworkStruct< T > &L)
ld stays TRUE through a refusal: the model IS load dependent, and the caller has to tell "no arm serv...
A queueing network and its refreshed NetworkStruct.
The QRF load-dependent rate scaling alpha(i,n), derived from an sn.
The QRF BAS blocking tables (f, MR, BB, MM, ZZ, MM1), derived from an sn.
Port of matlab/src/solvers/BA/solver_ba_analyzer.m, the bound-analysis handler behind SolverBA.
The options SolverBA reads.
Class-level results, the [Q,U,R,T,C,X] of solver_ba_analyzer.
double lG
-N log X, the reference's approximate normalizing constant.
A MAP as the pair of matrices (D0, D1).
The utilizations and queue lengths read off an optimal pair tensor.
std::vector< T > BN
The ALPHA-WEIGHTED diagonal marginal mean: the mean number of jobs actually in service,...
The scaling, the utilization normalizer, and why they may not exist.
bool ld
alpha is not identically 1
std::string msg
empty on success
std::vector< double > peak
(M) utilization normalizer; inf at a delay
std::vector< std::vector< double > > alpha
(M x N) scaling at population n = 1..N