LINE Solver (C++)
Templated C++ port of the LINE queueing solver
Loading...
Searching...
No Matches
pfqn_nintmva.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_NINTMVA_H
6#define LINE_API_PFQN_NINTMVA_H
7
8/**
9 * @file
10 * @ingroup api_pfqn
11 * Mean value analysis at a nonintegral population (fractional-base aMVA).
12 *
13 * Templated port of matlab/src/api/pfqn/pfqn_nintmva.m.
14 *
15 * The exact MVA recursion started from the FRACTIONAL base n_0 = N - floor(N)
16 * instead of from the empty network, giving mean performance measures of a
17 * single-class closed product-form network at a real-valued population (Dowdy
18 * and Gordon 1984, "aMVA"). The recursion is the standard Reiser-Lavenberg one,
19 *
20 * R_i(n) = D_i (1 + Q_i(n-1)), X(n) = n / (Z + sum_i R_i(n)), Q_i(n) = X R_i,
21 *
22 * stepped in unit increments from n = n_0 (where the arrival-theorem term
23 * Q_i(n_0 - 1) is taken as 0, the network below the base being empty) up to
24 * n = N. At integer N the base is 0 and the recursion is bit-identical to exact
25 * MVA; at fractional N it interpolates smoothly through the integral points,
26 * which is what a nonintegral degree of multiprogramming (a time-average over a
27 * measurement window) calls for.
28 *
29 * Unlike pfqn_dnc this accepts a think time, since the delay enters the
30 * recursion and not a partial-fraction continuation. It is single-class: the
31 * multiclass recursion has no one-dimensional step. For fractional multiclass
32 * populations use pfqn_bs, which accepts them directly.
33 *
34 * Reference: L. W. Dowdy, K. D. Gordon, "Algorithms for Nonintegral Degrees of
35 * Multiprogramming in Closed Queuing Networks", Performance Evaluation
36 * 4(1):19-28, 1984.
37 *
38 * Arithmetic: EXACT-CAPABLE. Only field operations on T; the integer part of N
39 * is read through a double, which is lossless for any population a closed model
40 * can carry.
41 */
42
43#include <cmath>
44#include <cstddef>
45#include <vector>
46
47#include "line/num/number.h"
48#include "line/util/error.h"
49
50namespace line {
51namespace pfqn {
52
53/** Mean performance measures of pfqn_nintmva at the requested population. */
54template <class T>
56 T X; ///< throughput at population N
57 std::vector<T> Q; ///< (M) mean queue lengths
58 std::vector<T> U; ///< (M) utilizations
59 std::vector<T> R; ///< (M) residence times
60};
61
62/**
63 * @brief Mean value analysis at a nonintegral population (fractional-base
64 * aMVA).
65 *
66 * @param L (M) service demands of the queueing stations
67 * @param N population, real and nonnegative (may be fractional)
68 * @param Z think time
69 */
70template <class T>
71NintMvaResult<T> pfqn_nintmva(const std::vector<T>& L, const T& N, const T& Z) {
72 const std::size_t M = L.size();
73 const T zero = num_traits<T>::from_int(0);
74 const T one = num_traits<T>::from_int(1);
75 if (N < zero) throw InputError("pfqn_nintmva requires a nonnegative population");
76
78 res.Q.assign(M, zero);
79 res.U.assign(M, zero);
80 res.R.assign(M, zero);
81 res.X = zero;
82 if (N == zero) return res;
83
84 // n_0 = N - floor(N), with the integral case starting the recursion at 1
85 const double Nd = num_traits<T>::to_double(N);
86 T n = T(N - num_traits<T>::from_int(static_cast<long>(std::floor(Nd))));
87 if (n == zero) n = one;
88
89 // The reference guards the real-valued loop bound with an absolute 1e-12
90 const T stop = T(N + num_traits<T>::from_double(1e-12));
91 while (n <= stop) {
92 T sumR = zero;
93 for (std::size_t i = 0; i < M; ++i) {
94 res.R[i] = T(L[i] * T(one + res.Q[i]));
95 sumR += res.R[i];
96 }
97 const T den = T(Z + sumR);
98 if (den == zero) throw NumericError("pfqn_nintmva: the network has zero total demand");
99 res.X = T(n / den);
100 for (std::size_t i = 0; i < M; ++i) res.Q[i] = T(res.X * res.R[i]);
101 n += one;
102 }
103 for (std::size_t i = 0; i < M; ++i) res.U[i] = T(res.X * L[i]);
104 return res;
105}
106
107/** MATLAB default: no think time. */
108template <class T>
109NintMvaResult<T> pfqn_nintmva(const std::vector<T>& L, const T& N) {
110 return pfqn_nintmva(L, N, num_traits<T>::from_int(0));
111}
112
113} // namespace pfqn
114} // namespace line
115
116#endif // LINE_API_PFQN_NINTMVA_H
InputError(const std::string &what)
Definition error.h:39
NumericError(const std::string &what)
Definition error.h:45
The exception types the port throws.
NintMvaResult< T > pfqn_nintmva(const std::vector< T > &L, const T &N, const T &Z)
Mean value analysis at a nonintegral population (fractional-base aMVA).
Number-type abstraction for the templated API port.
Mean performance measures of pfqn_nintmva at the requested population.
std::vector< T > R
(M) residence times
std::vector< T > U
(M) utilizations
T X
throughput at population N
std::vector< T > Q
(M) mean queue lengths