LINE Solver (C++)
Templated C++ port of the LINE queueing solver
Toggle main menu visibility
Loading...
Searching...
No Matches
pfqn_grnmol.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_GRNMOL_H
6
#define LINE_API_PFQN_PFQN_GRNMOL_H
7
8
/**
9
* @file
10
* @ingroup api_pfqn
11
* Normalizing constant by the closed-form Grundmann-Moeller rule.
12
*
13
* Templated port of matlab/src/api/pfqn/pfqn_grnmol.m, which applies the rule
14
* directly rather than through the successive-degree recursion of pfqn_cub:
15
*
16
* G = [ (sum N + M - 1)! / prod_r N_r! ] * sum_{i=0}^{S} w_i H_i
17
* w_i = 2^{-2S} (-1)^i c_i^{2S+1} / (i! (i + c_i)!), c_i = 2(S-i) + M
18
* H_i = sum_{|b| = S-i} prod_r ( ((2b+1)/c_i)' L(:,r) )^{N_r}
19
*
20
* with b ranging over the M-vectors of non-negative integers summing to S-i,
21
* which is what the reference's call to matlab/util/sprod.m enumerates. The
22
* point (2b+1)/c_i is barycentric by construction, since sum_m (2b_m+1) = c_i.
23
*
24
* DEGREE. pfqn_grnmol.m sets S = ceil((sum(N)-1)/2), the value pfqn_cub.m
25
* uses, so the rule is exact for every total population, odd or even. (An
26
* earlier reference wrote ceil(sum(N)-1)/2, a half-integer S for even sum(N)
27
* that made the function uncallable there; MATLAB has been corrected and this
28
* port follows it, accepting even populations.)
29
*
30
* ARITHMETIC. Every ingredient -- the barycentric points, the binomial-like
31
* weights, the integer powers -- is rational, and the factorial prefactor is
32
* formed as an exact factorial rather than through gammaln. The routine is
33
* therefore EXACT in rational arithmetic and is deliberately left ungated:
34
* at the reference degree it returns the exact normalizing constant, and
35
* checking that against pfqn_ca is the sharpest test the rule admits.
36
*/
37
38
#include <cstddef>
39
#include <vector>
40
41
#include "
line/num/number.h
"
42
#include "
line/util/error.h
"
43
#include "
line/util/matrix.h
"
44
45
namespace
line
{
46
namespace
pfqn
{
47
48
namespace
detail {
49
50
/**
51
* Advance b to the next M-vector of non-negative integers with a fixed sum,
52
* in the order matlab/util/sprod.m produces through multichoose. Returns
53
* false once the enumeration is exhausted.
54
*/
55
inline
bool
next_composition(std::vector<long>& b,
long
total) {
56
const
std::size_t M = b.size();
57
if
(M < 2)
return
false
;
58
// Find the rightmost position that can be decremented with something to
59
// its right to absorb the unit.
60
for
(std::size_t i = M - 1; i-- > 0;) {
61
if
(b[i] > 0) {
62
b[i] -= 1;
63
long
rest = total;
64
for
(std::size_t k = 0; k <= i; ++k) rest -= b[k];
65
for
(std::size_t k = i + 1; k < M; ++k) b[k] = 0;
66
b[i + 1] = rest;
67
return
true
;
68
}
69
}
70
return
false
;
71
}
72
73
}
// namespace detail
74
75
/**
76
* @brief Normalizing constant by the closed-form Grundmann-Moeller rule.
77
*
78
* @param L (M x R) demands, @param N (R) population
79
* @return the normalizing constant
80
*/
81
template
<
class
T>
82
T
pfqn_grnmol
(
const
Matrix<T>
& L,
const
std::vector<int>& N) {
83
const
std::size_t M = L.
rows
(), R = L.
cols
();
84
if
(N.size() != R)
throw
InputError
(
"pfqn_grnmol: L and N disagree on the class count"
);
85
if
(M == 0)
throw
InputError
(
"pfqn_grnmol: empty demand matrix"
);
86
long
Nt = 0;
87
for
(
int
v : N) {
88
if
(v < 0)
throw
InputError
(
"pfqn_grnmol: negative population"
);
89
Nt += v;
90
}
91
if
(Nt == 0)
return
num_traits<T>::from_int
(1);
92
// S = ceil((sum(N)-1)/2), i.e. floor(Nt/2): (Nt-1)/2 for odd Nt, Nt/2 for even Nt
93
const
long
S = Nt / 2;
94
const
T zero =
num_traits<T>::from_int
(0), one =
num_traits<T>::from_int
(1);
95
96
T G = zero;
97
for
(
long
i = 0; i <= S; ++i) {
98
const
long
ci = 2 * (S - i) +
static_cast<
long
>
(M);
99
T w = T(one /
num_pow_int
(
num_traits<T>::from_int
(2),
static_cast<
unsigned
>
(2 * S)));
100
if
(i % 2 == 1) w = T(-w);
101
w *=
num_pow_int
(
num_traits<T>::from_int
(ci),
static_cast<
unsigned
>
(2 * S + 1));
102
w /=
num_factorial<T>
(
static_cast<
unsigned
>
(i));
103
w /=
num_factorial<T>
(
static_cast<
unsigned
>
(i + ci));
104
105
const
long
tot = S - i;
106
std::vector<long> b(M, 0);
107
b[0] = tot;
108
T H = zero;
109
while
(
true
) {
110
T prod = one;
111
for
(std::size_t r = 0; r < R; ++r) {
112
if
(N[r] == 0)
continue
;
113
T uL = zero;
114
for
(std::size_t m = 0; m < M; ++m)
115
uL += T(
num_traits<T>::from_int
(2 * b[m] + 1) /
num_traits<T>::from_int
(ci)) *
116
L(m, r);
117
prod *=
num_pow_int
(uL,
static_cast<
unsigned
>
(N[r]));
118
}
119
H += prod;
120
if
(!detail::next_composition(b, tot))
break
;
121
}
122
G += w * H;
123
}
124
125
G *=
num_factorial<T>
(
static_cast<
unsigned
>
(Nt +
static_cast<
long
>
(M) - 1));
126
for
(std::size_t r = 0; r < R; ++r) G /=
num_factorial<T>
(
static_cast<
unsigned
>
(N[r]));
127
return
G;
128
}
129
130
}
// namespace pfqn
131
}
// namespace line
132
133
#endif
// LINE_API_PFQN_PFQN_GRNMOL_H
line::InputError::InputError
InputError(const std::string &what)
Definition
error.h:105
line::Matrix
Definition
matrix.h:56
line::Matrix::cols
std::size_t cols() const
Definition
matrix.h:90
line::Matrix::rows
std::size_t rows() const
Definition
matrix.h:89
error.h
The exception types the port throws.
matrix.h
Dense matrix and non-owning view.
line::pfqn
Definition
cd_peak_scaling.h:43
line::pfqn::pfqn_grnmol
T pfqn_grnmol(const Matrix< T > &L, const std::vector< int > &N)
Normalizing constant by the closed-form Grundmann-Moeller rule.
Definition
pfqn_grnmol.h:82
line
Conservation laws of a layered queueing network, enumerated from its structure.
Definition
aoi_dist2ph.h:52
line::num_factorial
T num_factorial(unsigned n)
Factorial as a value of T.
Definition
number.h:196
line::num_pow_int
T num_pow_int(const T &base, unsigned e)
Integer power, valid in any field (no transcendental requirement).
Definition
number.h:204
number.h
Number-type abstraction for the templated API port.
line::num_traits
Definition
number.h:123
include
line
api
pfqn
pfqn_grnmol.h
Generated by
1.18.0