LINE Solver (C++)
Templated C++ port of the LINE queueing solver
Loading...
Searching...
No Matches
fj_xmax_coxian.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_FJ_XMAX_COXIAN_H
6#define LINE_API_FJ_XMAX_COXIAN_H
7
8/**
9 * @file
10 * @ingroup api_fj
11 * Expected maximum of K i.i.d. two-stage Coxian variables.
12 *
13 * Templated port of matlab/src/api/fj/fj_xmax_coxian.m.
14 *
15 * With X = T1 + B T2, T1 ~ Exp(mu1), T2 ~ Exp(mu2) and B ~ Bernoulli(q), the
16 * survival function is a two-term exponential mixture
17 *
18 * S(t) = A exp(-mu1 t) + B exp(-mu2 t),
19 * A = (1-q) + q mu2/(mu2-mu1), B = -q mu1/(mu2-mu1),
20 *
21 * so expanding 1 - (1-S)^K binomially and integrating term by term gives
22 *
23 * E[Y_K] = sum_{j=1..K} (-1)^(j+1) C(K,j)
24 * sum_{i=0..j} C(j,i) A^(j-i) B^i / ((j-i) mu1 + i mu2).
25 *
26 * At coincident stage rates the mixture degenerates into
27 * S(t) = (1 + q mu t) exp(-mu t) and the same expansion is carried out with
28 * integral t^m exp(-j mu t) dt = m!/(j mu)^(m+1), which is selected
29 * automatically.
30 */
31
33#include "line/num/number.h"
34#include "line/util/error.h"
35
36namespace line {
37namespace fj {
38
39/** [Xmax, m1, c2] of fj_xmax_coxian. */
40template <class T>
43 T m1;
44 T c2;
45};
46
47/**
48 * @brief Expected maximum of K i.i.d. two-stage Coxian variables.
49 *
50 * @param K number of branches, K >= 1
51 * @param mu1 rate of the first stage
52 * @param mu2 rate of the second stage
53 * @param q probability that the second stage is visited, in [0,1]
54 * @return the exact expected maximum with the branch mean and SCV
55 */
56template <class T>
57FJXmaxCoxianResult<T> fj_xmax_coxian(unsigned K, const T& mu1, const T& mu2, const T& q) {
58 detail::require_positive_K(K, "fj_xmax_coxian");
59 const T zero = num_traits<T>::from_int(0), one = num_traits<T>::from_int(1),
61 if (!(mu1 > zero) || !(mu2 > zero))
62 throw InputError("fj_xmax_coxian: both stage rates must be positive");
63 if (q < zero || q > one)
64 throw InputError("fj_xmax_coxian: the branching probability must lie in [0,1]");
65 if (K > 60) throw InputError("fj_xmax_coxian: the binomial expansion loses precision past K=60");
66
68 out.m1 = one / mu1 + q / mu2;
69 const T var1 = one / (mu1 * mu1) + q * (two - q) / (mu2 * mu2);
70 out.c2 = var1 / (out.m1 * out.m1);
71
72 T acc = zero;
73 const double gap = num_traits<T>::to_double(mu2 - mu1);
74 const double scale = num_traits<T>::to_double(mu1 > mu2 ? mu1 : mu2);
75 if ((gap > 0 ? gap : -gap) > 1e-12 * scale) {
76 const T A = (one - q) + q * mu2 / (mu2 - mu1);
77 const T B = -q * mu1 / (mu2 - mu1);
78 for (unsigned j = 1; j <= K; ++j) {
79 T inner = zero;
80 for (unsigned i = 0; i <= j; ++i) {
81 const T rate = num_traits<T>::from_int(static_cast<long>(j - i)) * mu1 +
82 num_traits<T>::from_int(static_cast<long>(i)) * mu2;
83 T Apw = one, Bpw = one;
84 for (unsigned e = 0; e < j - i; ++e) Apw *= A;
85 for (unsigned e = 0; e < i; ++e) Bpw *= B;
86 inner += detail::fj_binom<T>(j, i) * Apw * Bpw / rate;
87 }
88 const T term = detail::fj_binom<T>(K, j) * inner;
89 if (j % 2 == 1) acc += term; else acc -= term;
90 }
91 } else {
92 // Coincident stage rates: S(t) = (1 + q mu t) exp(-mu t)
93 const T mu = mu1;
94 for (unsigned j = 1; j <= K; ++j) {
95 T inner = zero;
96 const T jmu = num_traits<T>::from_int(static_cast<long>(j)) * mu;
97 for (unsigned i = 0; i <= j; ++i) {
98 T num = one, den = one, fact = one;
99 for (unsigned e = 0; e < i; ++e) num *= q * mu;
100 for (unsigned e = 2; e <= i; ++e) fact *= num_traits<T>::from_int(static_cast<long>(e));
101 for (unsigned e = 0; e <= i; ++e) den *= jmu;
102 inner += detail::fj_binom<T>(j, i) * num * fact / den;
103 }
104 const T term = detail::fj_binom<T>(K, j) * inner;
105 if (j % 2 == 1) acc += term; else acc -= term;
106 }
107 }
108 out.Xmax = acc;
109 return out;
110}
111
112} // namespace fj
113} // namespace line
114
115#endif // LINE_API_FJ_XMAX_COXIAN_H
InputError(const std::string &what)
Definition error.h:39
The exception types the port throws.
Shared return types and arithmetic helpers for the templated fork-join port.
FJXmaxCoxianResult< T > fj_xmax_coxian(unsigned K, const T &mu1, const T &mu2, const T &q)
Expected maximum of K i.i.d.
Number-type abstraction for the templated API port.
[Xmax, m1, c2] of fj_xmax_coxian.