LINE Solver (C++)
Templated C++ port of the LINE queueing solver
Loading...
Searching...
No Matches
fj_qgb.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_FJ_QGB_H
6#define LINE_API_FJ_QGB_H
7
8/**
9 * @file
10 * @ingroup api_fj
11 * Geometric bound on the queue length of a fork-join subnetwork.
12 *
13 * Templated port of matlab/src/api/fj/fj_qgb.m.
14 *
15 * y_n(M) = D_n M / (Z + sum_j D_j H_{P_j} + Dmax M)
16 * Q_n(M) = H_{P_n} [ y_n/(1-y_n) - y_n^(M+1)/(1-y_n) ]
17 *
18 * The harmonic weights are what distinguishes this from pfqn_qzgblow: a P-way
19 * fork-join subnetwork inflates its own demand by H_P in the denominator and
20 * its queue length by H_P in the numerator, and setting every P_n to one
21 * recovers the ordinary geometric bound exactly.
22 */
23
24#include <cstddef>
25#include <vector>
26
29#include "line/num/number.h"
30#include "line/util/error.h"
31
32namespace line {
33namespace fj {
34
35/** [Q, y] of fj_qgb: the bounded queue lengths and the geometric ratios. */
36template <class T>
38 std::vector<T> Q;
39 std::vector<T> y;
40};
41
42/**
43 * @brief Geometric bound on the queue length of a fork-join subnetwork.
44 *
45 * @param D per-visit service demand of each subnetwork
46 * @param P fork degree of each subnetwork, P[n] >= 1
47 * @param M number of circulating jobs, M >= 1
48 * @param Z think time, Z >= 0
49 * @return the bounded queue lengths and the geometric ratios
50 */
51template <class T>
52FJQgbResult<T> fj_qgb(const std::vector<T>& D, const std::vector<unsigned>& P, unsigned M,
53 const T& Z) {
54 if (D.size() != P.size())
55 throw InputError("fj_qgb: D and P must have the same number of elements");
56 if (D.empty()) throw InputError("fj_qgb: at least one subnetwork is required");
57 if (M < 1) throw InputError("fj_qgb: M must be a positive integer");
58 const T zero = num_traits<T>::from_int(0), one = num_traits<T>::from_int(1);
59 if (Z < zero) throw InputError("fj_qgb: the think time must be non-negative");
60
61 const std::size_t N = D.size();
62 std::vector<T> H(N);
63 T Dtot = zero, Dmax = zero;
64 for (std::size_t n = 0; n < N; ++n) {
65 if (D[n] < zero) throw InputError("fj_qgb: service demands must be non-negative");
66 H[n] = fj_harmonic<T>(P[n]);
67 Dtot += D[n] * H[n];
68 if (n == 0 || D[n] > Dmax) Dmax = D[n];
69 }
70
72 out.Q.resize(N);
73 out.y.resize(N);
74 const T Mt = num_traits<T>::from_int(static_cast<long>(M));
75 for (std::size_t n = 0; n < N; ++n) {
76 out.y[n] = D[n] * Mt / (Z + Dtot + Dmax * Mt);
77 if (out.y[n] < one) {
78 T pw = one;
79 for (unsigned e = 0; e <= M; ++e) pw *= out.y[n];
80 out.Q[n] = H[n] * (out.y[n] / (one - out.y[n]) - pw / (one - out.y[n]));
81 } else {
82 // Degenerate ratio: the bound collapses onto the full population
83 out.Q[n] = Mt;
84 }
85 }
86 return out;
87}
88
89} // namespace fj
90} // namespace line
91
92#endif // LINE_API_FJ_QGB_H
InputError(const std::string &what)
Definition error.h:39
The exception types the port throws.
Harmonic number H_K = sum_{k=1..K} 1/k.
Shared return types and arithmetic helpers for the templated fork-join port.
FJQgbResult< T > fj_qgb(const std::vector< T > &D, const std::vector< unsigned > &P, unsigned M, const T &Z)
Geometric bound on the queue length of a fork-join subnetwork.
Definition fj_qgb.h:52
T fj_harmonic(unsigned K)
Harmonic number H_K = sum_{k=1..K} 1/k.
Definition fj_harmonic.h:37
Number-type abstraction for the templated API port.
[Q, y] of fj_qgb: the bounded queue lengths and the geometric ratios.
Definition fj_qgb.h:37
std::vector< T > y
Definition fj_qgb.h:39
std::vector< T > Q
Definition fj_qgb.h:38