5#ifndef LINE_API_MAPQN_MAPQN_QR_BOUNDS_RSRD_H
6#define LINE_API_MAPQN_MAPQN_QR_BOUNDS_RSRD_H
73 std::vector<Matrix<T>>
mu;
74 std::vector<Matrix<T>>
v;
76 std::vector<std::vector<T> >
alpha;
79 if (
M <= 0)
throw InputError(
"qrf_rsrd: M must be positive");
80 if (
N < 1)
throw InputError(
"qrf_rsrd: N must be at least 1");
81 if (
static_cast<int>(
F.size()) !=
M)
throw InputError(
"qrf_rsrd: F has the wrong length");
82 if (
static_cast<int>(
K.size()) !=
M)
throw InputError(
"qrf_rsrd: K has the wrong length");
83 if (
static_cast<int>(
mu.size()) !=
M ||
static_cast<int>(
v.size()) !=
M)
84 throw InputError(
"qrf_rsrd: mu and v must have one entry per queue");
85 for (
int i = 0; i <
M; ++i) {
86 if (
K[i] <= 0)
throw InputError(
"qrf_rsrd: every queue needs at least one phase");
87 if (
F[i] < 1 ||
F[i] >
N)
throw InputError(
"qrf_rsrd: F(i) must lie in 1..N");
88 const std::size_t k =
static_cast<std::size_t
>(
K[i]);
89 if (
mu[i].rows() != k ||
mu[i].cols() != k)
90 throw InputError(
"qrf_rsrd: mu{i} must be K(i) x K(i)");
91 if (
v[i].rows() != k ||
v[i].cols() != k)
92 throw InputError(
"qrf_rsrd: v{i} must be K(i) x K(i)");
94 if (
r.
rows() !=
static_cast<std::size_t
>(
M) ||
r.
cols() !=
static_cast<std::size_t
>(
M))
96 if (!
alpha.empty() &&
static_cast<int>(
alpha.size()) !=
M)
97 throw InputError(
"qrf_rsrd: alpha must have M rows when given");
129 QrRsrdIndex(
int m,
int n,
const std::vector<int>& k,
const std::vector<int>& f)
130 :
M(m),
N(n),
K(k),
F(f) {
131 base.assign(
static_cast<std::size_t
>(
M) + 1, 0);
132 cumU.assign(
static_cast<std::size_t
>(
M) + 1, 0);
133 for (
int i = 0; i <
M; ++i) {
137 B =
static_cast<std::size_t
>(
base[
M]);
144 std::size_t
half(
int i,
int ni,
int h)
const {
145 return static_cast<std::size_t
>(
base[i]) +
146 static_cast<std::size_t
>(ni) *
static_cast<std::size_t
>(
K[i]) +
147 static_cast<std::size_t
>(h);
149 std::size_t
p2(
int j,
int nj,
int kj,
int i,
int ni,
int hi)
const {
150 return half(j, nj, kj) *
B +
half(i, ni, hi);
153 std::size_t
U(
int i,
int k,
int n)
const {
154 return off_U +
static_cast<std::size_t
>(
cumU[i]) +
155 static_cast<std::size_t
>(k) *
static_cast<std::size_t
>(
F[i]) +
156 static_cast<std::size_t
>(n - 1);
158 std::size_t
Ueff(
int i,
int k,
int n)
const {
160 static_cast<std::size_t
>(k) *
static_cast<std::size_t
>(
F[i]) +
161 static_cast<std::size_t
>(n - 1);
163 std::size_t
pb(
int i)
const {
return off_pb +
static_cast<std::size_t
>(i); }
171T rsrd_rate(
const QrRsrdParams<T>& p,
int i,
int j,
int k,
int h,
int n) {
172 const std::size_t ki =
static_cast<std::size_t
>(k), hi =
static_cast<std::size_t
>(h);
173 const std::size_t ii =
static_cast<std::size_t
>(i), ji =
static_cast<std::size_t
>(j);
175 if (!p.alpha.empty() && n >= 0 &&
176 static_cast<std::size_t
>(n) < p.alpha[
static_cast<std::size_t
>(i)].size())
177 a = p.alpha[
static_cast<std::size_t
>(i)][
static_cast<std::size_t
>(n)];
178 if (j != i)
return T(a * p.r(ii, ji) * p.mu[i](ki, hi));
179 return T(a * (p.v[i](ki, hi) + p.r(ii, ii) * p.mu[i](ki, hi)));
184void rsrd_bounds(
const QrRsrdParams<T>& p,
const QrRsrdIndex& x, lp::LpModel<T>& m) {
185 const T one = num_traits<T>::from_int(1);
186 for (std::size_t j = 0; j < x.num_vars(); ++j) m.set_bounds(j, T(), one);
191void rsrd_one(
const QrRsrdParams<T>& p,
const QrRsrdIndex& x, lp::LpModel<T>& m) {
192 for (
int j = 0; j < p.M; ++j) {
193 for (
int nj = 0; nj <= p.F[j]; ++nj)
194 for (
int kj = 0; kj < p.K[j]; ++kj) m.row_add_int(x.p2(j, nj, kj, j, nj, kj), 1);
207void rsrd_zero(
const QrRsrdParams<T>& p,
const QrRsrdIndex& x, lp::LpModel<T>& m) {
209 for (
int i = 0; i < p.M; ++i) totF += p.F[i];
210 for (
int j = 0; j < p.M; ++j) {
211 for (
int nj = 0; nj <= p.F[j]; ++nj) {
212 for (
int kj = 0; kj < p.K[j]; ++kj) {
213 for (
int i = 0; i < p.M; ++i) {
214 for (
int ni = 0; ni <= p.F[i]; ++ni) {
215 for (
int hi = 0; hi < p.K[i]; ++hi) {
217 if (i == j && nj == ni && hi != kj) z =
true;
218 if (i == j && nj != ni) z =
true;
219 if (i != j && nj + ni > p.N) z =
true;
220 if (i != j && p.N - nj - ni > totF - p.F[i] - p.F[j])
222 if (z) m.fix(x.p2(j, nj, kj, i, ni, hi), T());
228 for (
int nj = 0; nj <= p.F[j]; ++nj)
229 for (
int kj = 0; kj < p.K[j]; ++kj)
230 if (p.N - nj > totF - p.F[j]) m.fix(x.p2(j, nj, kj, j, nj, kj), T());
236void rsrd_symmetry(
const QrRsrdParams<T>& p,
const QrRsrdIndex& x, lp::LpModel<T>& m) {
237 for (
int j = 0; j < p.M; ++j)
238 for (
int nj = 0; nj <= p.F[j]; ++nj)
239 for (
int kj = 0; kj < p.K[j]; ++kj)
240 for (
int i = j + 1; i < p.M; ++i)
241 for (
int ni = 0; ni <= p.F[i]; ++ni)
242 for (
int hi = 0; hi < p.K[i]; ++hi) {
243 const std::size_t a = x.p2(j, nj, kj, i, ni, hi);
244 const std::size_t b = x.p2(i, ni, hi, j, nj, kj);
245 if (a == b)
continue;
247 m.row_add_int(b, -1);
254void rsrd_marginals(
const QrRsrdParams<T>& p,
const QrRsrdIndex& x, lp::LpModel<T>& m) {
255 for (
int j = 0; j < p.M; ++j)
256 for (
int kj = 0; kj < p.K[j]; ++kj)
257 for (
int nj = 0; nj <= p.F[j]; ++nj)
258 for (
int i = 0; i < p.M; ++i) {
259 if (i == j)
continue;
260 m.row_add_int(x.p2(j, nj, kj, j, nj, kj), 1);
261 for (
int ni = 0; ni <= p.F[i]; ++ni)
262 for (
int hi = 0; hi < p.K[i]; ++hi)
263 m.row_add_int(x.p2(j, nj, kj, i, ni, hi), -1);
270void rsrd_uclassic(
const QrRsrdParams<T>& p,
const QrRsrdIndex& x, lp::LpModel<T>& m) {
271 for (
int i = 0; i < p.M; ++i)
272 for (
int ki = 0; ki < p.K[i]; ++ki)
273 for (
int ni = 1; ni <= p.F[i]; ++ni) {
274 m.row_add_int(x.U(i, ki, ni), 1);
275 m.row_add_int(x.p2(i, ni, ki, i, ni, ki), -1);
285void rsrd_ueffs(
const QrRsrdParams<T>& p,
const QrRsrdIndex& x, lp::LpModel<T>& m) {
286 for (
int i = 0; i < p.M; ++i)
287 for (
int ki = 0; ki < p.K[i]; ++ki)
288 for (
int ni = 1; ni <= p.F[i]; ++ni) {
289 m.row_add_int(x.Ueff(i, ki, ni), 1);
290 m.row_add_int(x.p2(i, ni, ki, i, ni, ki), -1);
291 for (
int j = 0; j < p.M; ++j) {
292 if (j == i)
continue;
293 if (!(p.r(
static_cast<std::size_t
>(i),
static_cast<std::size_t
>(j)) > T()))
295 for (
int hj = 0; hj < p.K[j]; ++hj)
296 m.row_add(x.p2(i, ni, ki, j, p.F[j], hj),
297 p.r(
static_cast<std::size_t
>(i),
static_cast<std::size_t
>(j)));
305void rsrd_pblock(
const QrRsrdParams<T>& p,
const QrRsrdIndex& x, lp::LpModel<T>& m) {
306 for (
int i = 0; i < p.M; ++i) {
307 m.row_add_int(x.pb(i), 1);
308 for (
int ki = 0; ki < p.K[i]; ++ki)
309 for (
int ni = 1; ni <= p.F[i]; ++ni) {
310 m.row_add_int(x.U(i, ki, ni), -1);
311 m.row_add_int(x.Ueff(i, ki, ni), 1);
319void rsrd_pbb(
const QrRsrdParams<T>& p,
const QrRsrdIndex& x, lp::LpModel<T>& m) {
320 for (
int i = 0; i < p.M; ++i) {
321 m.row_add_int(x.pb(i), 1);
322 for (
int j = 0; j < p.M; ++j) {
323 if (j == i)
continue;
324 if (!(p.r(
static_cast<std::size_t
>(i),
static_cast<std::size_t
>(j)) > T()))
continue;
325 for (
int hj = 0; hj < p.K[j]; ++hj)
326 m.row_add_int(x.p2(j, p.F[j], hj, j, p.F[j], hj), -1);
339void rsrd_thm2(
const QrRsrdParams<T>& p,
const QrRsrdIndex& x, lp::LpModel<T>& m) {
340 for (
int i = 0; i < p.M; ++i) {
341 for (
int ki = 0; ki < p.K[i]; ++ki) {
342 for (
int ni = 1; ni <= p.F[i]; ++ni) {
343 for (
int j = 0; j < p.M; ++j) {
344 if (j == i)
continue;
345 for (
int hi = 0; hi < p.K[i]; ++hi) {
346 if (hi == ki)
continue;
347 m.row_add(x.Ueff(i, ki, ni), rsrd_rate(p, i, j, ki, hi, ni));
350 for (
int hi = 0; hi < p.K[i]; ++hi) {
351 if (hi == ki)
continue;
352 m.row_add(x.p2(i, ni, ki, i, ni, ki), rsrd_rate(p, i, i, ki, hi, ni));
355 for (
int ni = 1; ni <= p.F[i]; ++ni) {
356 for (
int j = 0; j < p.M; ++j) {
357 if (j == i)
continue;
358 for (
int hi = 0; hi < p.K[i]; ++hi) {
359 if (hi == ki)
continue;
360 m.row_add(x.Ueff(i, hi, ni), T(-rsrd_rate(p, i, j, hi, ki, ni)));
363 for (
int hi = 0; hi < p.K[i]; ++hi) {
364 if (hi == ki)
continue;
365 m.row_add(x.p2(i, ni, hi, i, ni, hi), T(-rsrd_rate(p, i, i, hi, ki, ni)));
380void rsrd_thm1(
const QrRsrdParams<T>& p,
const QrRsrdIndex& x, lp::LpModel<T>& m) {
381 for (
int j = 0; j < p.M; ++j) {
382 for (
int kj = 0; kj < p.K[j]; ++kj) {
383 for (
int nj = 1; nj <= p.F[j]; ++nj) {
384 m.row_add_int(x.p2(j, nj, kj, j, nj, kj), -p.N);
385 for (
int i = 0; i < p.M; ++i)
386 for (
int ni = 1; ni <= p.F[i]; ++ni)
387 for (
int hi = 0; hi < p.K[i]; ++hi)
388 m.row_add_int(x.p2(j, nj, kj, i, ni, hi), ni);
397void rsrd_thm1c(
const QrRsrdParams<T>& p,
const QrRsrdIndex& x, lp::LpModel<T>& m) {
398 for (
int j = 0; j < p.M; ++j) {
399 for (
int kj = 0; kj < p.K[j]; ++kj) {
400 m.row_add_int(x.p2(j, 0, kj, j, 0, kj), -p.N);
401 for (
int i = 0; i < p.M; ++i) {
402 if (i == j)
continue;
403 for (
int ni = 1; ni <= p.F[i]; ++ni)
404 for (
int hi = 0; hi < p.K[i]; ++hi)
405 m.row_add_int(x.p2(j, 0, kj, i, ni, hi), ni);
414void rsrd_thm3a(
const QrRsrdParams<T>& p,
const QrRsrdIndex& x, lp::LpModel<T>& m) {
415 for (
int i = 0; i < p.M; ++i) {
416 for (
int ni = 1; ni <= p.F[i] - 1; ++ni) {
417 for (
int j = 0; j < p.M; ++j) {
418 if (j == i)
continue;
419 for (
int kj = 0; kj < p.K[j]; ++kj)
420 for (
int hj = 0; hj < p.K[j]; ++hj)
421 for (
int ui = 0; ui < p.K[i]; ++ui)
422 for (
int nj = 1; nj <= p.F[j]; ++nj)
423 m.row_add(x.p2(j, nj, kj, i, ni, ui),
424 rsrd_rate(p, j, i, kj, hj, nj));
426 for (
int j = 0; j < p.M; ++j) {
427 if (j == i)
continue;
428 for (
int ki = 0; ki < p.K[i]; ++ki)
429 for (
int hi = 0; hi < p.K[i]; ++hi)
430 for (
int uj = 0; uj < p.K[j]; ++uj)
431 for (
int nj = 0; nj <= p.F[j] - 1; ++nj)
432 m.row_add(x.p2(i, ni + 1, ki, j, nj, uj),
433 T(-rsrd_rate(p, i, j, ki, hi, ni + 1)));
442void rsrd_thm3b(
const QrRsrdParams<T>& p,
const QrRsrdIndex& x, lp::LpModel<T>& m) {
443 for (
int i = 0; i < p.M; ++i) {
444 for (
int ui = 0; ui < p.K[i]; ++ui) {
445 for (
int j = 0; j < p.M; ++j) {
446 if (j == i)
continue;
447 for (
int kj = 0; kj < p.K[j]; ++kj)
448 for (
int hj = 0; hj < p.K[j]; ++hj)
449 for (
int nj = 1; nj <= p.F[j]; ++nj)
450 m.row_add(x.p2(j, nj, kj, i, 0, ui), rsrd_rate(p, j, i, kj, hj, nj));
452 for (
int j = 0; j < p.M; ++j) {
453 if (j == i)
continue;
454 for (
int ki = 0; ki < p.K[i]; ++ki)
455 for (
int nj = 0; nj <= p.F[j] - 1; ++nj)
456 for (
int hj = 0; hj < p.K[j]; ++hj)
457 m.row_add(x.p2(i, 1, ki, j, nj, hj),
458 T(-rsrd_rate(p, i, j, ki, ui, 1)));
467void rsrd_qbal(
const QrRsrdParams<T>& p,
const QrRsrdIndex& x, lp::LpModel<T>& m) {
468 for (
int i = 0; i < p.M; ++i) {
469 for (
int ki = 0; ki < p.K[i]; ++ki) {
470 for (
int hi = 0; hi < p.K[i]; ++hi) {
471 if (hi == ki)
continue;
472 for (
int j = 0; j < p.M; ++j) {
473 if (j == i)
continue;
474 for (
int ni = 1; ni <= p.F[i]; ++ni)
475 for (
int uj = 0; uj < p.K[j]; ++uj)
476 for (
int nj = 0; nj <= p.F[j] - 1; ++nj)
477 m.row_add(x.p2(i, ni, ki, j, nj, uj),
478 T(rsrd_rate(p, i, j, ki, hi, ni) *
479 num_traits<T>::from_int(ni)));
482 for (
int hi = 0; hi < p.K[i]; ++hi) {
483 if (hi == ki)
continue;
484 for (
int ni = 1; ni <= p.F[i]; ++ni)
485 m.row_add(x.p2(i, ni, ki, i, ni, ki),
486 T(rsrd_rate(p, i, i, ki, hi, ni) * num_traits<T>::from_int(ni)));
488 for (
int j = 0; j < p.M; ++j) {
489 if (j == i)
continue;
490 for (
int hi = 0; hi < p.K[i]; ++hi)
491 for (
int ni = 1; ni <= p.F[i]; ++ni)
492 for (
int uj = 0; uj < p.K[j]; ++uj) {
494 (p.F[j] - 1) < (p.N - ni) ? (p.F[j] - 1) : (p.N - ni);
495 for (
int nj = 0; nj <= cap; ++nj)
496 m.row_add(x.p2(i, ni, hi, j, nj, uj),
497 rsrd_rate(p, i, j, hi, ki, ni));
500 for (
int j = 0; j < p.M; ++j) {
501 if (j == i)
continue;
502 for (
int hj = 0; hj < p.K[j]; ++hj)
503 for (
int ni = 0; ni <= p.F[i] - 1; ++ni)
504 for (
int uj = 0; uj < p.K[j]; ++uj)
505 for (
int nj = 1; nj <= p.F[j]; ++nj)
506 m.row_add(x.p2(i, ni, ki, j, nj, hj),
507 T(-rsrd_rate(p, j, i, hj, uj, nj)));
509 for (
int hi = 0; hi < p.K[i]; ++hi) {
510 if (hi == ki)
continue;
511 for (
int ni = 1; ni <= p.F[i]; ++ni)
512 m.row_add(x.p2(i, ni, hi, i, ni, hi),
513 T(-(rsrd_rate(p, i, i, hi, ki, ni) * num_traits<T>::from_int(ni))));
515 for (
int hi = 0; hi < p.K[i]; ++hi) {
516 if (hi == ki)
continue;
517 for (
int j = 0; j < p.M; ++j) {
518 if (j == i)
continue;
519 for (
int ni = 1; ni <= p.F[i]; ++ni)
520 for (
int uj = 0; uj < p.K[j]; ++uj)
521 for (
int nj = 0; nj <= p.F[j] - 1; ++nj)
522 m.row_add(x.p2(i, ni, hi, j, nj, uj),
523 T(-(rsrd_rate(p, i, j, hi, ki, ni) *
524 num_traits<T>::from_int(ni))));
538void rsrd_thm4(
const QrRsrdParams<T>& p,
const QrRsrdIndex& x, lp::LpModel<T>& m) {
539 for (
int j = 0; j < p.M; ++j)
540 for (
int kj = 0; kj < p.K[j]; ++kj)
541 for (
int i = 0; i < p.M; ++i) {
542 for (
int t = 0; t < p.M; ++t)
543 for (
int ht = 0; ht < p.K[t]; ++ht)
544 for (
int nj = 0; nj <= p.F[j]; ++nj)
545 for (
int nt = 1; nt <= p.F[t]; ++nt)
546 m.row_add_int(x.p2(j, nj, kj, t, nt, ht), -nt);
547 for (
int hi = 0; hi < p.K[i]; ++hi)
548 for (
int nj = 0; nj <= p.F[j]; ++nj)
549 for (
int ni = 1; ni <= p.F[i]; ++ni)
550 m.row_add_int(x.p2(j, nj, kj, i, ni, hi), p.N);
568 if (objective_queue < 0 || objective_queue >= p.
M)
569 throw InputError(
"qrf_rsrd: objective_queue out of range");
573 detail::rsrd_bounds(p, x, m);
575 detail::rsrd_one(p, x, m);
576 detail::rsrd_zero(p, x, m);
577 detail::rsrd_symmetry(p, x, m);
578 detail::rsrd_marginals(p, x, m);
579 detail::rsrd_uclassic(p, x, m);
580 detail::rsrd_ueffs(p, x, m);
581 detail::rsrd_pblock(p, x, m);
582 detail::rsrd_pbb(p, x, m);
583 detail::rsrd_thm2(p, x, m);
584 detail::rsrd_thm1(p, x, m);
585 detail::rsrd_thm1c(p, x, m);
586 detail::rsrd_thm3a(p, x, m);
587 detail::rsrd_thm3b(p, x, m);
588 detail::rsrd_qbal(p, x, m);
589 detail::rsrd_thm4(p, x, m);
592 for (
int ki = 0; ki < p.
K[objective_queue]; ++ki)
593 for (
int ni = 1; ni <= p.
F[objective_queue]; ++ni)
594 m.
set_cost(x.
p2(objective_queue, ni, ki, objective_queue, ni, ki), one);
610 if (!out.
ok)
return out;
612 out.
U.assign(
static_cast<std::size_t
>(p.
M), T());
613 out.
Ueff.assign(
static_cast<std::size_t
>(p.
M), T());
614 out.
pb.assign(
static_cast<std::size_t
>(p.
M), T());
615 for (
int i = 0; i < p.
M; ++i) {
616 for (
int ki = 0; ki < p.
K[i]; ++ki) {
617 for (
int ni = 1; ni <= p.
F[i]; ++ni) {
618 out.
U[
static_cast<std::size_t
>(i)] += sol.
x[x.
U(i, ki, ni)];
619 out.
Ueff[
static_cast<std::size_t
>(i)] += sol.
x[x.
Ueff(i, ki, ni)];
622 out.
pb[
static_cast<std::size_t
>(i)] = sol.
x[x.
pb(i)];
Sparse LP in the natural form, with per-variable bounds.
void set_maximize(bool m)
true to maximize c'x (the default), false to minimize.
std::size_t num_rows() const
void set_cost(std::size_t j, const T &v)
std::size_t num_vars() const
The exception types the port throws.
A sparse LP backend for line::lp::LpModel, on HiGHS (MIT).
Model parameters and variable indexing shared by the mapqn QR bounds.
Dense matrix and non-owning view.
LpSolution< T > lp_solve(const LpModel< T > &model, std::size_t dense_max_cols=512)
Solve, choosing the backend by arithmetic and size.
const char * lp_status_name(LpStatus s)
MapqnSense
Which direction the bound is taken in.
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.
Number-type abstraction for the templated API port.
Templated primal simplex with Bland's rule.
T objective
c'x, in the sense requested (max or min)
std::vector< T > x
primal solution in the ORIGINAL variable space
Variable layout: p2(j,nj,kj,i,ni,hi), then U(i,k,n) and Ueff(i,k,n) for n >= 1, then pb(i).
std::size_t U(int i, int k, int n) const
n is 1-based here: U is only defined for a busy queue.
QrRsrdIndex(int m, int n, const std::vector< int > &k, const std::vector< int > &f)
std::size_t num_vars() const
std::size_t half(int i, int ni, int h) const
std::size_t pb(int i) const
std::size_t p2(int j, int nj, int kj, int i, int ni, int hi) const
std::size_t Ueff(int i, int k, int n) const
Parameters of the RS-RD bound, mirroring the reference's params.
std::vector< int > K
(M) number of phases of each queue
std::vector< Matrix< T > > mu
mu[i] is K(i) x K(i), completion rates
std::vector< Matrix< T > > v
v[i] is K(i) x K(i), background rates
std::vector< int > F
(M) capacity of each queue
Matrix< T > r
(M x M) routing probabilities
std::vector< std::vector< T > > alpha
optional (M) x (N+1) load scalings; empty means 1
Result of an RS-RD bound solve.
T objective
the bound on the utilization of the target queue
std::vector< T > pb
(M) blocking probability of each queue
std::vector< T > Ueff
(M) effective utilization of each queue
std::vector< T > U
(M) utilization of each queue