LINE Solver (C++)
Templated C++ port of the LINE queueing solver
Loading...
Searching...
No Matches
pfqn_mcub.h
Go to the documentation of this file.
1/*
2 * Copyright (c) 2012-2026, QORE Lab, Imperial College London
3 * All rights reserved.
4 */
5#ifndef LINE_API_PFQN_PFQN_MCUB_H
6#define LINE_API_PFQN_PFQN_MCUB_H
7
8/**
9 * @file
10 * @ingroup api_pfqn
11 * Kerola's multiclass composite bound (Perf. Eval. 6:1-9, eqs. 10-16) on the
12 * per-class throughput of a closed product-form network.
13 *
14 * Templated port of matlab/src/api/pfqn/pfqn_mcub.m. The multiclass Balanced
15 * Job Bound gives the per-class lower bound
16 *
17 * X_r^- = N_r / (sum_k L_kr + Z_r + (Ntot - 1) max_k L_kr)
18 *
19 * and the residual-utilization argument then gives the composite upper bound
20 *
21 * X_r^+ = min_k [1 - sum_{s != r} X_s^- L_ks] / L_kr
22 *
23 * at O(MR). Despite the name it has nothing to do with pfqn_cub, which is the
24 * Grundmann-Moeller cubature normalizing constant.
25 *
26 * ARITHMETIC. Sums, products, maxima and divisions only, so the bound is EXACT
27 * in rational arithmetic and is deliberately left ungated.
28 */
29
30#include <cstddef>
31#include <vector>
32
33#include "line/num/number.h"
34#include "line/util/error.h"
35#include "line/util/matrix.h"
36
37namespace line {
38namespace pfqn {
39
40/** Return value of pfqn_mcub, mirroring [Xub, Xlb]. */
41template <class T>
42struct McubBounds {
43 std::vector<T> Xub;
44 std::vector<T> Xlb;
45};
46
47/**
48 * @brief Kerola's multiclass composite bound (Perf. Eval. 6:1-9, eqs. 10-16)
49 * on the per-class throughput of a closed product-form network.
50 *
51 * @param L (M x R) demands, @param N (R) population, @param Z (R) think times
52 * (empty for zero think time)
53 */
54template <class T>
55McubBounds<T> pfqn_mcub(const Matrix<T>& L, const std::vector<T>& N, const std::vector<T>& Z) {
56 const std::size_t M = L.rows(), R = L.cols();
57 if (N.size() != R) throw InputError("pfqn_mcub: L and N disagree on the class count");
58 if (!Z.empty() && Z.size() != R) throw InputError("pfqn_mcub: Z has the wrong length");
59 const T zero = num_traits<T>::from_int(0), one = num_traits<T>::from_int(1);
60 T Ntot = zero;
61 for (const T& v : N) Ntot += v;
62
64 r.Xlb.assign(R, zero);
65 r.Xub.assign(R, zero);
66 for (std::size_t s = 0; s < R; ++s) {
67 T R0 = zero, Lb = zero;
68 for (std::size_t k = 0; k < M; ++k) {
69 R0 += L(k, s);
70 if (L(k, s) > Lb) Lb = L(k, s);
71 }
72 const T zr = Z.empty() ? zero : Z[s];
73 const T den = T(R0 + zr + T(Ntot - one) * Lb);
74 if (den == zero) throw NumericError("pfqn_mcub: zero cycle time in the balanced job bound");
75 r.Xlb[s] = T(N[s] / den);
76 }
77
78 for (std::size_t s = 0; s < R; ++s) {
79 bool any = false;
80 T best = zero;
81 for (std::size_t k = 0; k < M; ++k) {
82 if (!(L(k, s) > zero)) continue; // MATLAB leaves the device at Inf
83 T Uoth = zero;
84 for (std::size_t t = 0; t < R; ++t)
85 if (t != s) Uoth += r.Xlb[t] * L(k, t);
86 const T dev = T(T(one - Uoth) / L(k, s));
87 if (!any || dev < best) {
88 best = dev;
89 any = true;
90 }
91 }
92 // MATLAB's min over an all-Inf device vector is Inf; a class with no
93 // demand anywhere is unconstrained, which the caller must handle.
94 if (!any) throw InputError("pfqn_mcub: a class has zero demand at every station");
95 r.Xub[s] = best;
96 }
97 return r;
98}
99
100template <class T>
101McubBounds<T> pfqn_mcub(const Matrix<T>& L, const std::vector<T>& N) {
102 return pfqn_mcub(L, N, std::vector<T>());
103}
104
105} // namespace pfqn
106} // namespace line
107
108#endif // LINE_API_PFQN_PFQN_MCUB_H
InputError(const std::string &what)
Definition error.h:39
std::size_t cols() const
Definition matrix.h:90
std::size_t rows() const
Definition matrix.h:89
NumericError(const std::string &what)
Definition error.h:45
The exception types the port throws.
Dense matrix and non-owning view.
McubBounds< T > pfqn_mcub(const Matrix< T > &L, const std::vector< T > &N, const std::vector< T > &Z)
Kerola's multiclass composite bound (Perf.
Definition pfqn_mcub.h:55
Number-type abstraction for the templated API port.
Return value of pfqn_mcub, mirroring [Xub, Xlb].
Definition pfqn_mcub.h:42
std::vector< T > Xlb
Definition pfqn_mcub.h:44
std::vector< T > Xub
Definition pfqn_mcub.h:43