LINE Solver (C++)
Templated C++ port of the LINE queueing solver
Loading...
Searching...
No Matches
aph2_adjust.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_APH2_ADJUST_H
6#define LINE_API_MAM_APH2_ADJUST_H
7
8/**
9 * @file
10 * @ingroup api_mam
11 * Nearest APH(2)-feasible values of the second and third moments
12 * (matlab/lib/m3a/m3a/aph2/aph2_adjust.m, method 'simple').
13 *
14 * Applies the closed-form bounds of Telek and Heindl (2002): the SCV is
15 * lifted to 1/2 when it falls below it, and the third moment is clamped into
16 * [lb, ub] for SCV <= 1 and above lb (times 1 + tol) for SCV > 1.
17 *
18 * Only the 'simple' method is ported. The other four methods of the reference
19 * ('opt_param', 'opt_param_gads', 'opt_char', 'opt_char_gads') minimize a
20 * distance with fmincon or GlobalSearch and are therefore out of scope; they
21 * are documented as skipped rather than approximated.
22 *
23 * Gated on transcendental arithmetic: the lower bound for SCV <= 1 contains
24 * sqrt(2) and (1 - scv)^(3/2).
25 */
26
28#include "line/num/number.h"
29#include "line/util/error.h"
30
31namespace line {
32namespace mam {
33
34/** Result of aph2_adjust. */
35template <class T>
37 T M2a;
38 T M3a;
39};
40
41/**
42 * Feasible (M2, M3) closest to the input, holding M1 fixed. tol is the
43 * relative slack applied above the SCV > 1 lower bound (MATLAB uses 1e-4).
44 */
45template <class T>
46Aph2AdjustResult<T> aph2_adjust(const T& M1, const T& M2, const T& M3, const T& tol) {
48 "aph2_adjust requires transcendental arithmetic");
49 using fitdetail::num_sqrt;
50 using fitdetail::pw;
51
52 const T one = num_traits<T>::from_int(1);
53 const T two = num_traits<T>::from_int(2);
54 const T three = num_traits<T>::from_int(3);
55 const T six = num_traits<T>::from_int(6);
56 const T half = num_traits<T>::from_rational(1, 2);
57
58 if (M1 <= num_traits<T>::from_int(0)) throw InputError("aph2_adjust: non-positive first moment");
59
60 const T M1sq = M1 * M1;
61 const T scv = (M2 - M1sq) / M1sq;
62
64 T scva;
65 if (scv < half) {
66 r.M2a = three / two * M1sq;
67 scva = (r.M2a - M1sq) / M1sq;
68 } else {
69 r.M2a = M2;
70 scva = scv;
71 }
72
73 if (scva <= one) {
74 const T d = one - scva;
75 const T lb = three * pw(M1, 3) * (three * scva - one + num_sqrt(two) * d * num_sqrt(d));
76 const T ub = six * pw(M1, 3) * scva;
77 if (M3 < lb)
78 r.M3a = lb;
79 else if (M3 > ub)
80 r.M3a = ub;
81 else
82 r.M3a = M3;
83 } else {
84 const T lb = three / two * pw(M1, 3) * (one + scva) * (one + scva);
85 r.M3a = (M3 <= lb) ? T(lb * (one + tol)) : M3;
86 }
87 return r;
88}
89
90/** aph2_adjust with the MATLAB default slack tol = 1e-4. */
91template <class T>
92Aph2AdjustResult<T> aph2_adjust(const T& M1, const T& M2, const T& M3) {
93 return aph2_adjust(M1, M2, M3, T(num_traits<T>::from_double(1e-4)));
94}
95
96} // namespace mam
97} // namespace line
98
99#endif // LINE_API_MAM_APH2_ADJUST_H
InputError(const std::string &what)
Definition error.h:39
The exception types the port throws.
Scalar helpers shared by the MAP/PH moment-matching headers.
Aph2AdjustResult< T > aph2_adjust(const T &M1, const T &M2, const T &M3, const T &tol)
Feasible (M2, M3) closest to the input, holding M1 fixed.
Definition aph2_adjust.h:46
Number-type abstraction for the templated API port.
Result of aph2_adjust.
Definition aph2_adjust.h:36