LINE Solver (C++)
Templated C++ port of the LINE queueing solver
Loading...
Searching...
No Matches
aph_fit_moments.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_MAM_APH_FIT_MOMENTS_H
6#define LINE_API_MAM_APH_FIT_MOMENTS_H
7
8/**
9 * @file
10 * @ingroup api_mam
11 * Acyclic phase-type fitters from the first two moments.
12 *
13 * Port of BUTools' `APHFrom2Moments` and of MATLAB `APH.fitMeanAndSCV`. Both
14 * lived in solver_mna.h until a second caller appeared: the closed
15 * setup/delay-off branch of solver_mam_basic fits its delay-off with
16 * `APH.fitMeanAndSCV`, exactly as the reference does, and solver_mna.h already
17 * includes solver_mam_basic.h, so leaving them there would have been a cycle.
18 *
19 * These are NOT the canonical Coxian of `coxian_phase_subgen`
20 * (qbd_setupdelayoff.h). The two agree in the first two moments but not in
21 * shape: the Coxian is entered at phase 1, this APH is entered at phase 1 with
22 * probability p and at the LAST phase otherwise. Anything reading more than the
23 * first two moments -- an LST, for instance -- sees the difference, so a caller
24 * must use whichever one the reference names for that call site.
25 */
26
27#include <algorithm>
28#include <cmath>
29#include <string>
30#include <vector>
31
34#include "line/num/number.h"
35#include "line/util/error.h"
36#include "line/util/matrix.h"
37
38namespace line {
39namespace mam {
40
41/**
42 * Port of BUTools' `APHFrom2Moments`.
43 *
44 * Absorption is possible ONLY from the last phase: the first N-1 rows of the
45 * generator have a zero row sum by construction, so D1 is zero everywhere
46 * except its last row. That is the shape, not an artifact of the fit.
47 */
48template <class T>
49Map<T> aph_from_2moments(const T& e1, const T& e2) {
50 const T zero = num_traits<T>::from_int(0), one = num_traits<T>::from_int(1);
51 const T cv2 = T(T(e2 / T(e1 * e1)) - one);
52 const double cv2d = num_traits<T>::to_double(cv2);
53 if (!(cv2d > 0.0))
54 throw NumericError(
55 "APHFrom2Moments: the moment pair implies a non-positive squared coefficient of "
56 "variation (" + std::to_string(cv2d) +
57 "), for which the reference's order ceil(1/cv2) is not a positive integer");
58 const T lambda = T(one / e1);
59 const long N = std::max(static_cast<long>(std::ceil(1.0 / cv2d)), 2L);
60 const std::size_t n = static_cast<std::size_t>(N);
61 const T Nt = num_traits<T>::from_int(N);
62 const T p = T(one / T(cv2 + one + T(T(cv2 - one) / num_traits<T>::from_int(N - 1))));
63
64 Matrix<T> A(n, n, zero);
65 const T d = T(lambda * p * Nt);
66 for (std::size_t i = 0; i < n; ++i) A(i, i) = T(-d);
67 for (std::size_t i = 0; i + 1 < n; ++i) A(i, i + 1) = d;
68 A(n - 1, n - 1) = T(-T(lambda * Nt));
69
70 std::vector<T> alpha(n, zero);
71 alpha[0] = p;
72 alpha[n - 1] = T(one - p);
73
74 Map<T> m;
75 m.D0 = A;
76 m.D1 = Matrix<T>(n, n, zero);
77 for (std::size_t i = 0; i < n; ++i) {
78 T ex = zero;
79 for (std::size_t j = 0; j < n; ++j) ex += A(i, j);
80 for (std::size_t j = 0; j < n; ++j) m.D1(i, j) = T(-ex * alpha[j]);
81 }
82 return m;
83}
84
85/** Port of `APH.fitMeanAndSCV`, the entry point the analyzers fit arrivals with. */
86template <class T>
87Map<T> aph_fit_mean_scv(const T& mean, const T& scv) {
88 const T zero = num_traits<T>::from_int(0), one = num_traits<T>::from_int(1);
90 // A sub-tolerance mean is answered by an exponential, and a
91 // non-positive one by the Zero-mean surrogate the reference names.
92 const T m = (mean > zero) ? mean : num_traits<T>::from_double(lang::GlobalConstants::Zero);
93 return map_exponential(T(one / m));
94 }
95 if (scv == one) return map_exponential(T(one / mean));
96 return aph_from_2moments(mean, T(T(one + scv) * mean * mean));
97}
98
99} // namespace mam
100} // namespace line
101
102#endif // LINE_API_MAM_APH_FIT_MOMENTS_H
NumericError(const std::string &what)
Definition error.h:45
The exception types the port throws.
Enumerations and the minimal distribution descriptor shared by the model layer of the C++ port.
Markovian arrival process descriptors: stationary vectors, rate, moments, autocorrelation and the ind...
Dense matrix and non-owning view.
Map< T > aph_fit_mean_scv(const T &mean, const T &scv)
Port of APH.fitMeanAndSCV, the entry point the analyzers fit arrivals with.
Map< T > aph_from_2moments(const T &e1, const T &e2)
Port of BUTools' APHFrom2Moments.
Map< T > map_exponential(const T &lambda)
Two-phase MAP constructor for a Poisson process of rate lambda.
Definition map_moment.h:213
Number-type abstraction for the templated API port.
static constexpr double FineTol
Definition lang_types.h:668
static constexpr double Zero
Definition lang_types.h:670
A MAP as the pair of matrices (D0, D1).
Definition map_moment.h:53
Matrix< T > D1
Definition map_moment.h:55
Matrix< T > D0
Definition map_moment.h:54