LINE Solver (C++)
Templated C++ port of the LINE queueing solver
Loading...
Searching...
No Matches
cache_xi_fp.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_CACHE_XI_FP_H
6#define LINE_API_CACHE_XI_FP_H
7
8/**
9 * @file
10 * @ingroup api_cache
11 * Lagrange multipliers of a multi-list cache by fixed-point iteration.
12 *
13 * Templated port of matlab/src/api/cache/cache_xi_fp.m, cross-checked against
14 * jar/src/main/java/jline/api/cache/Cache_xi_fp.java.
15 *
16 * The asymptotic (large-cache) form of the list occupancy distribution is
17 *
18 * pij(k,l) = gamma(k,l) xi(l) / (1 + sum_s gamma(k,s) xi(s)),
19 * pi0(k) = 1 - sum_l pij(k,l),
20 *
21 * and the multipliers xi are fixed by the capacity constraints, which in this
22 * decoupled form read xi(l) = m(l) / sum_k pi0(k) gamma(k,l). Alternating the
23 * two updates from pi0 = 1/(h+1) is the iteration below; it stops when the
24 * relative change of pi0 falls under 1e-14 in the 1-norm.
25 *
26 * ARITHMETIC: every update is a field operation, but the iteration is stopped
27 * by a tolerance and the fixed point is not reached in finitely many exact
28 * steps, so the algorithm is inexact by nature. It is gated on transcendental
29 * arithmetic rather than offered at exact arithmetic, where a "1e-14" cutoff
30 * would be a rounding-free computation of a rounded answer.
31 *
32 * REFERENCE DEFECT (both codebases): the optional initial-xi argument is
33 * inert. MATLAB writes `xi=zeros(1,h);` before testing `nargin<3`, discarding
34 * the caller's vector, and in any case the first statement of the loop
35 * recomputes xi from pi0, so no initial xi can influence the result. The JAR
36 * has the same structure. The argument is therefore not offered here.
37 */
38
39#include <cstddef>
40#include <vector>
41
42#include "line/num/number.h"
43#include "line/util/error.h"
44#include "line/util/matrix.h"
45
46namespace line {
47namespace cache {
48
49/** Return value of cache_xi_fp, mirroring [xi,pi0,pij,it]. */
50template <class T>
52 std::vector<T> xi; ///< (h) Lagrange multipliers
53 std::vector<T> pi0; ///< (n) per-item miss probability
54 Matrix<T> pij; ///< (n x h) per-item per-list hit probability
55 int it; ///< iterations performed
56};
57
58/**
59 * @brief Lagrange multipliers of a multi-list cache by fixed-point iteration.
60 *
61 * @param gamma (n x h) access factors
62 * @param m (h) list capacities
63 */
64template <class T>
65CacheXiFpResult<T> cache_xi_fp(const Matrix<T>& gamma, const std::vector<int>& m) {
67 "cache_xi_fp requires transcendental arithmetic");
68 const std::size_t n = gamma.rows();
69 const std::size_t h = gamma.cols();
70 if (h != m.size()) throw InputError("cache_xi_fp: gamma and m disagree on the number of lists");
71
72 const T zero = num_traits<T>::from_int(0);
73 const T one = num_traits<T>::from_int(1);
74 const T tol = num_traits<T>::from_double(1e-14);
75
76 std::vector<T> pi0(n, one / num_traits<T>::from_int(static_cast<long>(h + 1)));
77 std::vector<T> xi(h, zero);
78 Matrix<T> pij(n, h, zero);
79
80 int it = 1;
81 for (; it <= 10000; ++it) {
82 const std::vector<T> pi0_1 = pi0;
83
84 // xi(l) = m(l) / sum_k pi0(k) gamma(k,l)
85 for (std::size_t l = 0; l < h; ++l) {
86 T d = zero;
87 for (std::size_t k = 0; k < n; ++k) d += pi0_1[k] * gamma(k, l);
88 if (d == zero)
89 throw NumericError("cache_xi_fp: a list has zero aggregate access factor");
90 xi[l] = num_traits<T>::from_int(static_cast<long>(m[l])) / d;
91 }
92
93 for (std::size_t k = 0; k < n; ++k) {
94 T s = zero;
95 for (std::size_t l = 0; l < h; ++l) s += gamma(k, l) * xi[l];
96 const T den = num_abs(T(one + s));
97 T hits = zero;
98 for (std::size_t l = 0; l < h; ++l) {
99 pij(k, l) = num_abs(T(gamma(k, l) * xi[l])) / den;
100 hits += pij(k, l);
101 }
102 const T v = one - hits;
103 pi0[k] = v > tol ? v : tol;
104 }
105
106 T delta = zero;
107 for (std::size_t k = 0; k < n; ++k) delta += num_abs(T(one - pi0[k] / pi0_1[k]));
108 if (delta < tol) break;
109 }
110 if (it > 10000) it = 10000;
111
112 for (std::size_t l = 0; l < h; ++l)
113 if (xi[l] < zero) xi[l] = tol;
114
116 r.xi = xi;
117 r.pi0 = pi0;
118 r.pij = pij;
119 r.it = it;
120 return r;
121}
122
123} // namespace cache
124} // namespace line
125
126#endif // LINE_API_CACHE_XI_FP_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
NumericError(const std::string &what)
Definition error.h:45
The exception types the port throws.
Dense matrix and non-owning view.
CacheXiFpResult< T > cache_xi_fp(const Matrix< T > &gamma, const std::vector< int > &m)
Lagrange multipliers of a multi-list cache by fixed-point iteration.
Definition cache_xi_fp.h:65
T num_abs(const T &v)
Definition number.h:172
Number-type abstraction for the templated API port.
Return value of cache_xi_fp, mirroring [xi,pi0,pij,it].
Definition cache_xi_fp.h:51
std::vector< T > pi0
(n) per-item miss probability
Definition cache_xi_fp.h:53
int it
iterations performed
Definition cache_xi_fp.h:55
std::vector< T > xi
(h) Lagrange multipliers
Definition cache_xi_fp.h:52
Matrix< T > pij
(n x h) per-item per-list hit probability
Definition cache_xi_fp.h:54