LINE Solver (C++)
Templated C++ port of the LINE queueing solver
Loading...
Searching...
No Matches
qsys_mg1_prio.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_QSYS_QSYS_MG1_PRIO_H
6#define LINE_API_QSYS_QSYS_MG1_PRIO_H
7
8/**
9 * @file
10 * @ingroup api_qsys
11 * M/G/1 with non-preemptive head-of-line priorities: per-class mean response
12 * times from the Cobham/Kleinrock formula.
13 *
14 * Templated port of matlab/src/api/qsys/qsys_mg1_prio.m, cross-checked against
15 * jar/src/main/java/jline/api/qsys/Qsys_mg1_prio.java (identical, including
16 * the rhohat convention below).
17 *
18 * rho_i = lambda_i/mu_i
19 * B_0 = (1/2) sum_i lambda_i (1 + cs_i^2)/mu_i^2 the mean work left
20 * Wq_k = B_0 / [ (1 - sum_{i<k} rho_i)(1 - sum_{i<=k} rho_i) ]
21 * W_k = Wq_k + 1/mu_k
22 *
23 * Class 1 is the highest priority. The returned rhohat is Q/(1+Q) with
24 * Q = sum_k lambda_k W_k, the qsys family convention, not the utilization:
25 * MATLAB computes the utilization into the same output variable and then
26 * overwrites it, so the utilization is not observable from the return value.
27 *
28 * Only squares of the coefficients of variation appear, so the whole
29 * computation is a rational function of the inputs and exact for
30 * T = Rational.
31 */
32
33#include <cstddef>
34#include <vector>
35
37#include "line/num/number.h"
38#include "line/util/error.h"
39
40namespace line {
41namespace qsys {
42
43template <class T>
45 std::vector<T> W; ///< per-class mean response time, class 1 first
46 T rhohat; ///< Q/(1+Q) with Q = sum_k lambda_k W_k
47};
48
49/**
50 * @brief M/G/1 with non-preemptive head-of-line priorities: per-class mean
51 * response times from the Cobham/Kleinrock formula.
52 *
53 * @param lambda per-class arrival rates, highest priority first
54 * @param mu per-class service rates
55 * @param cs per-class coefficients of variation of the service time
56 */
57template <class T>
58Mg1PrioResult<T> qsys_mg1_prio(const std::vector<T>& lambda, const std::vector<T>& mu,
59 const std::vector<T>& cs) {
60 const std::size_t K = lambda.size();
61 if (mu.size() != K || cs.size() != K)
62 throw InputError("qsys_mg1_prio: lambda, mu and cs must have the same length");
63 if (K == 0) throw InputError("qsys_mg1_prio: at least one class is required");
64 const T zero = num_traits<T>::from_int(0), one = num_traits<T>::from_int(1);
65 const T two = num_traits<T>::from_int(2);
66 for (std::size_t i = 0; i < K; ++i)
67 if (lambda[i] <= zero || mu[i] <= zero || cs[i] <= zero)
68 throw InputError("qsys_mg1_prio: lambda, mu and cs must all be positive");
69
70 std::vector<T> rho_i(K);
71 T rho = zero;
72 for (std::size_t i = 0; i < K; ++i) {
73 rho_i[i] = lambda[i] / mu[i];
74 rho += rho_i[i];
75 }
76 if (rho >= one) throw InputError("qsys_mg1_prio: system is unstable, rho >= 1");
77
78 T B_0 = zero;
79 for (std::size_t i = 0; i < K; ++i)
80 B_0 += lambda[i] * (one + cs[i] * cs[i]) / (mu[i] * mu[i]);
81 B_0 /= two;
82
84 r.W.resize(K);
85 T rho_prev = zero;
86 for (std::size_t k = 0; k < K; ++k) {
87 const T rho_curr = rho_prev + rho_i[k];
88 r.W[k] = B_0 / ((one - rho_prev) * (one - rho_curr)) + one / mu[k];
89 rho_prev = rho_curr;
90 }
91 T Q = zero;
92 for (std::size_t k = 0; k < K; ++k) Q += lambda[k] * r.W[k];
93 r.rhohat = Q / (one + Q);
94 return r;
95}
96
97} // namespace qsys
98} // namespace line
99
100#endif // LINE_API_QSYS_QSYS_MG1_PRIO_H
InputError(const std::string &what)
Definition error.h:39
The exception types the port throws.
Mg1PrioResult< T > qsys_mg1_prio(const std::vector< T > &lambda, const std::vector< T > &mu, const std::vector< T > &cs)
M/G/1 with non-preemptive head-of-line priorities: per-class mean response times from the Cobham/Klei...
Number-type abstraction for the templated API port.
Shared return type and arithmetic helpers for the templated qsys port.
T rhohat
Q/(1+Q) with Q = sum_k lambda_k W_k.
std::vector< T > W
per-class mean response time, class 1 first