LINE Solver (C++)
Templated C++ port of the LINE queueing solver
Loading...
Searching...
No Matches
pfqn_aghq.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_AGHQ_H
6#define LINE_API_PFQN_PFQN_AGHQ_H
7
8/**
9 * @file
10 * @ingroup api_pfqn
11 * Adaptive Gauss-Hermite quadrature of the simplex factor of the McKenna-Mitra integral.
12 *
13 * Templated port of matlab/src/api/pfqn/pfqn_aghq.m. Rescaling by the logistic-expansion
14 * mode and curvature, w = w* + A^(-1/2) z, and applying the q-node probabilists'
15 * Gauss-Hermite rule in each of the M-1 simplex directions gives a convergent rule whose
16 * q = 1 member is pfqn_le itself: one node at the mode with weight sqrt(2 pi). So LE is
17 * the first term of a convergent quadrature rather than an approximation of unknown
18 * accuracy. Cost q^(M-1), which is what confines the method to small M.
19 *
20 * A tensor rule is NOT invariant to the choice of square root of A: any B with B B' =
21 * inv(A) is admissible and they place the nodes differently. The principal-axis frame is
22 * used here, as in the reference results; where two curvatures are close to equal that
23 * frame is close to arbitrary and two valid rules can part company well above their own
24 * error, converging back together as q grows. Do NOT compare across codebases node by
25 * node.
26 *
27 * With Z > 0 the radius is integrated numerically (pfqn_simplex.h) and the rule is applied
28 * to the M-1 simplex directions, so every node costs one radial quadrature. Because the
29 * radius is integrated rather than Laplaced, q = 1 there is the logistic expansion with an
30 * exact radius, which is NOT pfqn_le's own Z > 0 branch.
31 *
32 * ARITHMETIC. Gated on num_traits<T>::has_transcendental exactly as pfqn_le is.
33 *
34 * References:
35 * J. McKenna, D. Mitra, "Integral Representations and Asymptotic Expansions for Closed
36 * Markovian Queueing Networks: Normal Usage", Bell Syst. Tech. J. 61(5), 1982.
37 * Q. Liu, D. A. Pierce, "A Note on Gauss-Hermite Quadrature", Biometrika 81(3), 1994.
38 */
39
40#include <cmath>
41#include <cstddef>
42#include <vector>
43
48#include "line/num/number.h"
49#include "line/util/error.h"
50#include "line/util/matrix.h"
51
52namespace line {
53namespace pfqn {
54
55template <class T>
57
58template <class T>
59AghqResult<T> pfqn_aghq(const Matrix<T>& L, const std::vector<T>& N,
60 const std::vector<T>& Z, std::size_t q) {
62 "pfqn_aghq requires transcendental arithmetic (quadrature of an integral)");
63 using std::exp;
64 using std::log;
65 const std::size_t M = L.rows(), R = L.cols();
66 const T zero = num_traits<T>::from_int(0);
67 if (q == 0) throw InputError("pfqn_aghq: q must be at least 1");
68
69 T Ntot = zero, Lsum = zero, Zsum = zero;
70 for (const T& x : N) Ntot += x;
71 for (const T& x : Z) Zsum += x;
72 for (std::size_t i = 0; i < M; ++i)
73 for (std::size_t r = 0; r < R; ++r) Lsum += L(i, r);
74 if (M == 0 || N.empty() || Ntot == zero || num_traits<T>::to_double(Lsum) < 1e-4) {
75 return pfqn_le(L, N, Z);
76 }
77
78 const std::size_t d = M - 1;
79 const T half = num_traits<T>::from_double(0.5);
80 AghqResult<T> res;
81
83 const std::vector<T> umax = pfqn_le_fpi(L, N);
84 // M = 1 leaves a 0x0 reduced Hessian, which pfqn_le_hessian refuses to form;
85 // d = 0 then makes the rule a single node and ld = 0.
86 const Matrix<T> A = (M < 2) ? Matrix<T>(0, 0) : pfqn_le_hessian(L, N, umax);
87 const T ld = (M < 2) ? zero : detail::pfqn_logdet(A);
88 T S = zero, sum_lu = zero;
89 for (std::size_t r = 0; r < R; ++r) {
90 T uL = zero;
91 for (std::size_t i = 0; i < M; ++i) uL += umax[i] * L(i, r);
92 S += N[r] * log(uL);
93 }
94 for (std::size_t i = 0; i < M; ++i) sum_lu += log(umax[i]);
95 const T h0 = T(S + sum_lu);
96 std::vector<T> w0(d);
97 for (std::size_t i = 0; i < d; ++i) w0[i] = log(T(umax[i] / umax[M - 1]));
98 const Matrix<T>* Lp = &L;
99 const std::vector<T>* Np = &N;
100 auto h = [Lp, Np, M, R, zero](const std::vector<T>& w) {
101 using std::log;
102 std::vector<T> x = simplex::softmax_gauge(w);
103 T acc = zero;
104 for (std::size_t r = 0; r < R; ++r) {
105 T c = zero;
106 for (std::size_t i = 0; i < M; ++i) c += x[i] * (*Lp)(i, r);
107 acc += (*Np)[r] * log(c);
108 }
109 for (std::size_t i = 0; i < M; ++i) acc += log(x[i]);
110 return acc;
111 };
112 T lacc = simplex::aghq_rule(h, w0, h0, A, q, d);
113 T lG = detail::num_factln<T>(T(Ntot + num_traits<T>::from_int(static_cast<long>(M) - 1)));
114 for (std::size_t r = 0; r < R; ++r) lG -= detail::num_factln<T>(N[r]);
115 res.lG = T(lG + h0 + lacc - half * ld);
116 } else {
118 std::vector<T> w0(d);
119 for (std::size_t i = 0; i < d; ++i) w0[i] = log(T(mode.x[i] / mode.x[M - 1]));
120 const Matrix<T>* Lp = &L;
121 const std::vector<T>* Np = &N;
122 const std::vector<T>* Zp = &Z;
123 auto h = [Lp, Np, Zp, M, R, zero](const std::vector<T>& w) {
124 using std::log;
125 std::vector<T> x = simplex::softmax_gauge(w);
126 std::vector<T> c(R, zero);
127 for (std::size_t r = 0; r < R; ++r)
128 for (std::size_t i = 0; i < M; ++i) c[r] += x[i] * (*Lp)(i, r);
129 T acc = simplex::radial(c, *Np, *Zp, M).lJ;
130 for (std::size_t i = 0; i < M; ++i) acc += log(x[i]);
131 return acc;
132 };
133 T lacc = simplex::aghq_rule(h, w0, mode.h0, mode.A, q, d);
134 T lG = zero;
135 for (std::size_t r = 0; r < R; ++r) lG -= detail::num_factln<T>(N[r]);
136 res.lG = T(lG + mode.h0 + lacc - half * mode.ld);
137 }
138 res.G = exp(res.lG);
139 return res;
140}
141
142template <class T>
143AghqResult<T> pfqn_aghq(const Matrix<T>& L, const std::vector<T>& N,
144 const std::vector<T>& Z) {
145 return pfqn_aghq(L, N, Z, static_cast<std::size_t>(3));
146}
147
148template <class T>
149AghqResult<T> pfqn_aghq(const Matrix<T>& L, const std::vector<T>& N) {
150 return pfqn_aghq(L, N, std::vector<T>(), static_cast<std::size_t>(3));
151}
152
153} // namespace pfqn
154} // namespace line
155
156#endif // LINE_API_PFQN_PFQN_AGHQ_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
The exception types the port throws.
Enumerations and the minimal distribution descriptor shared by the model layer of the C++ port.
Dense matrix and non-owning view.
std::vector< T > softmax_gauge(const std::vector< T > &w)
softmax of [w; 0], the logistic parametrisation of the simplex with gauge w_M = 0.
T aghq_rule(const F &h, const std::vector< T > &w0, const T &h0, const Matrix< T > &A, std::size_t q, std::size_t d)
Log of the tensor Gauss-Hermite sum, accumulated with a running maximum; the det(A)^(-1/2) of the rul...
Mode< T > simplex_mode(const Matrix< T > &L, const std::vector< T > &N, const std::vector< T > &Z)
Mode and curvature of h(w) = log J(L'x(w)) + sum_i log x_i with J the exact radial integral.
Radial< T > radial(const std::vector< T > &c, const std::vector< T > &N, const std::vector< T > &Z, std::size_t M)
log J(c) = log int_0^inf exp(-v) v^(M-1) prod_r (Z_r + v c_r)^N_r dv, plus the moments of the tilted ...
AghqResult< T > pfqn_aghq(const Matrix< T > &L, const std::vector< T > &N, const std::vector< T > &Z, std::size_t q)
Definition pfqn_aghq.h:59
std::vector< T > pfqn_le_fpi(const Matrix< T > &L, const std::vector< T > &N)
Mode of the logistic-transformed integrand, Z = 0 case (pfqn_le_fpi).
Definition pfqn_le.h:59
LeResult< T > AghqResult
Definition pfqn_aghq.h:56
LeResult< T > pfqn_le(const Matrix< T > &L, const std::vector< T > &N, const std::vector< T > &Z)
Logistic expansion estimate of the normalizing constant.
Definition pfqn_le.h:245
Matrix< T > pfqn_le_hessian(const Matrix< T > &L, const std::vector< T > &N, const std::vector< T > &u0)
Hessian of the Z = 0 logistic integrand at the mode ((M-1) x (M-1)).
Definition pfqn_le.h:136
Number-type abstraction for the templated API port.
Shared scalar machinery for the integration / asymptotic members of the pfqn family (pfqn_le,...
Logistic expansion (LE) asymptotic approximation of the normalizing constant of a closed product-form...
Shared machinery for closures of the simplex factor of the McKenna-Mitra integral,...
static constexpr double Zero
Definition lang_types.h:670
Return value of pfqn_le, mirroring [Gn, lGn].
Definition pfqn_le.h:233
Mode, curvature and log-integrand at the mode of the simplex factor.