LINE Solver (C++)
Templated C++ port of the LINE queueing solver
Loading...
Searching...
No Matches
fj_char_max_discrete.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_CHAR_MAX_DISCRETE_H
6#define LINE_API_FJ_CHAR_MAX_DISCRETE_H
7
8/**
9 * @file
10 * @ingroup api_fj
11 * Characteristic maximum of a lattice random variable.
12 *
13 * Templated port of matlab/src/api/fj/fj_char_max_discrete.m.
14 *
15 * With m_K the smallest integer at which P(X > m_K) <= 1/K,
16 *
17 * M_K = m_K + K sum_{k >= m_K} P(X > k),
18 *
19 * which upper bounds the expected maximum of K i.i.d. copies at O(1) instead of
20 * the alternating binomial sum. Two lattice laws close the tail sum:
21 *
22 * geometric, P(X = k) = (1-p) p^k:
23 * m_K = ceil(-ln K / ln p), M_K = m_K + K p^(m_K+1)/(1-p),
24 * exact E[Y_K] = sum_k C(K,k) (-1)^(k+1) p^k/(1-p^k);
25 * Poisson:
26 * M_K = m_K (1 - K P(X > m_K)) + K theta P(X > m_K - 1).
27 */
28
29#include <cmath>
30#include <cstddef>
31#include <vector>
32
34#include "line/num/number.h"
35#include "line/util/error.h"
36
37namespace line {
38namespace fj {
39
40/** The lattice laws for which the characteristic maximum is closed. */
42
43/** [MK, mK, exact] of fj_char_max_discrete. */
44template <class T>
46 T MK;
47 unsigned mK;
49};
50
51/**
52 * @brief Characteristic maximum of a lattice random variable.
53 *
54 * @param K number of i.i.d. copies, K >= 1
55 * @param dist the lattice law
56 * @param par p in (0,1) for the geometric, theta > 0 for the Poisson
57 * @return characteristic maximum, its threshold, and the exact maximum
58 */
59template <class T>
61 detail::require_positive_K(K, "fj_char_max_discrete");
62 const T zero = num_traits<T>::from_int(0), one = num_traits<T>::from_int(1);
64
65 if (dist == FJDiscreteDist::Geometric) {
66 const T p = par;
67 if (!(p > zero) || !(p < one))
68 throw InputError("fj_char_max_discrete: the geometric parameter must lie in (0,1)");
69 // Smallest integer k with p^k <= 1/K
70 const double mkd = -std::log(static_cast<double>(K)) /
71 std::log(num_traits<T>::to_double(p));
72 long mk = static_cast<long>(std::ceil(mkd - 1e-12));
73 if (mk < 0) mk = 0;
74 out.mK = static_cast<unsigned>(mk);
75 T pw = one;
76 for (unsigned e = 0; e <= out.mK; ++e) pw *= p;
77 out.MK = num_traits<T>::from_int(mk) + num_traits<T>::from_int(static_cast<long>(K)) * pw /
78 (one - p);
79 // Exact maximum by inclusion-exclusion on the geometric tail
80 T acc = zero;
81 T pk = one;
82 for (unsigned k = 1; k <= K; ++k) {
83 pk *= p;
84 const T term = detail::fj_binom<T>(K, k) * pk / (one - pk);
85 if (k % 2 == 1) acc += term; else acc -= term;
86 }
87 out.exact = acc;
88 return out;
89 }
90
91 const T theta = par;
92 if (!(theta > zero))
93 throw InputError("fj_char_max_discrete: the Poisson mean must be positive");
94 const double th = num_traits<T>::to_double(theta);
95 const std::size_t kmax = static_cast<std::size_t>(std::ceil(th + 12 * std::sqrt(th) + 40));
96 std::vector<T> pmf(kmax + 1), cdf(kmax + 1), tail(kmax + 1);
97 T term = detail::num_exp<T>(-theta);
98 T acc = zero;
99 for (std::size_t k = 0; k <= kmax; ++k) {
100 if (k > 0) term = term * theta / num_traits<T>::from_int(static_cast<long>(k));
101 pmf[k] = term;
102 acc += term;
103 cdf[k] = (acc > one) ? one : acc;
104 tail[k] = one - cdf[k];
105 }
106 std::size_t mk = kmax + 1;
107 const T thr = one / num_traits<T>::from_int(static_cast<long>(K));
108 for (std::size_t k = 0; k <= kmax; ++k)
109 if (tail[k] <= thr) { mk = k; break; }
110 if (mk > kmax)
111 throw NumericError("fj_char_max_discrete: the Poisson lattice truncation never reached 1/K");
112 out.mK = static_cast<unsigned>(mk);
113 const T tail_prev = (mk == 0) ? one : tail[mk - 1];
114 out.MK = num_traits<T>::from_int(static_cast<long>(mk)) *
115 (one - num_traits<T>::from_int(static_cast<long>(K)) * tail[mk]) +
116 num_traits<T>::from_int(static_cast<long>(K)) * theta * tail_prev;
117 // Exact maximum as the sum over the lattice of 1 - F(k)^K
118 T ex = zero;
119 for (std::size_t k = 0; k <= kmax; ++k) {
120 T pw = one;
121 for (unsigned e = 0; e < K; ++e) pw *= cdf[k];
122 ex += one - pw;
123 }
124 out.exact = ex;
125 return out;
126}
127
128} // namespace fj
129} // namespace line
130
131#endif // LINE_API_FJ_CHAR_MAX_DISCRETE_H
InputError(const std::string &what)
Definition error.h:39
NumericError(const std::string &what)
Definition error.h:45
The exception types the port throws.
Shared return types and arithmetic helpers for the templated fork-join port.
FJCharMaxDiscreteResult< T > fj_char_max_discrete(unsigned K, FJDiscreteDist dist, const T &par)
Characteristic maximum of a lattice random variable.
FJDiscreteDist
The lattice laws for which the characteristic maximum is closed.
Number-type abstraction for the templated API port.
[MK, mK, exact] of fj_char_max_discrete.