LINE Solver (C++)
Templated C++ port of the LINE queueing solver
Loading...
Searching...
No Matches
cache_t_hlru.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_T_HLRU_H
6#define LINE_API_CACHE_T_HLRU_H
7
8/**
9 * @file
10 * @ingroup api_cache
11 * Characteristic times of the h-LRU / LRU(m) TTL approximation.
12 *
13 * Templated port of matlab/src/api/cache/cache_t_hlru.m, cross-checked against
14 * jar/src/main/java/jline/api/cache/Cache_t_hlru.java.
15 *
16 * Under the characteristic-time (Che) approximation each list l of an h-LRU
17 * cache has a time T(l) such that an item of request rate lam is evicted from
18 * list l if it is not requested within T(l). The level of an item is then a
19 * birth-death chain with e(l) = exp(-lam T(l)), giving unnormalized weights
20 *
21 * w(0) = 1, w(l) = w(l-1) (1 - e(l)) / e(l),
22 *
23 * and pi_l = w(l)/sum(w). The times are fixed by sum_k pi_l(k;T) = m(l), one
24 * equation per list. sum_k pi_l is increasing in T(l), so each equation is
25 * solved by bisection (bracketed by doubling the upper end until the occupancy
26 * reaches the capacity, then 100 halvings), swept Gauss-Seidel over the lists
27 * until the times move by less than 1e-8 relative.
28 *
29 * ARITHMETIC: exp is required and the answer is defined by a bisection
30 * tolerance, so this needs transcendental arithmetic.
31 *
32 * Reference: Gast and Van Houdt, SIGMETRICS 2015. For h = 1 the fixed point
33 * reduces exactly to the Che approximation of LRU.
34 */
35
36#include <cmath>
37#include <cstddef>
38#include <vector>
39
40#include "line/num/number.h"
41#include "line/util/error.h"
42#include "line/util/matrix.h"
43
44namespace line {
45namespace cache {
46
47namespace detail {
48
49/** LINE's GlobalConstants.Zero and FineTol, as set by lineStart. */
50template <class T>
51T hlru_zero() {
52 return num_traits<T>::from_double(1e-14);
53}
54template <class T>
55T hlru_finetol() {
56 return num_traits<T>::from_double(1e-8);
57}
58
59/**
60 * Birth-death level probabilities pi(k,l), l = 0..h, for request rates lam and
61 * characteristic times T.
62 */
63template <class T>
64Matrix<T> hlru_levelprobs(const std::vector<T>& lam, const std::vector<T>& T_) {
65 using std::exp;
66 const std::size_t n = lam.size();
67 const std::size_t h = T_.size();
68 const T one = num_traits<T>::from_int(1);
69 const T zeroTol = hlru_zero<T>();
70 Matrix<T> P(n, h + 1, num_traits<T>::from_int(0));
71 for (std::size_t k = 0; k < n; ++k) {
72 std::vector<T> w(h + 1, one);
73 for (std::size_t l = 0; l < h; ++l) {
74 const T e = exp(T(-lam[k] * T_[l]));
75 const T den = e > zeroTol ? e : zeroTol;
76 w[l + 1] = w[l] * (one - e) / den;
77 }
78 T s = num_traits<T>::from_int(0);
79 for (std::size_t l = 0; l <= h; ++l) s += w[l];
80 for (std::size_t l = 0; l <= h; ++l) P(k, l) = w[l] / s;
81 }
82 return P;
83}
84
85/** Total occupancy of list l when its characteristic time is set to Tl. */
86template <class T>
87T hlru_occ(const std::vector<T>& lam, std::vector<T> T_, std::size_t l, const T& Tl) {
88 T_[l] = Tl;
89 const Matrix<T> P = hlru_levelprobs(lam, T_);
90 T occ = num_traits<T>::from_int(0);
91 for (std::size_t k = 0; k < lam.size(); ++k) occ += P(k, l + 1);
92 return occ;
93}
94
95/** The shared Gauss-Seidel + bisection fixed point for the times. */
96template <class T>
97std::vector<T> hlru_solve_times(const std::vector<T>& lam, const std::vector<int>& m) {
98 const std::size_t n = lam.size();
99 const std::size_t h = m.size();
100 if (n == 0) throw InputError("cache_t_hlru: no items");
101 const T zero = num_traits<T>::from_int(0);
102 const T two = num_traits<T>::from_int(2);
103
104 T mean = zero;
105 for (std::size_t k = 0; k < n; ++k) mean += lam[k];
106 mean /= num_traits<T>::from_int(static_cast<long>(n));
107 const T scale = mean > hlru_finetol<T>() ? mean : hlru_finetol<T>();
108 const T T0 = num_traits<T>::from_int(1) / scale;
109 const T hicap = num_traits<T>::from_double(1e12);
110
111 std::vector<T> Tv(h, T0);
112 for (int sweep = 0; sweep < 200; ++sweep) {
113 const std::vector<T> Told = Tv;
114 for (std::size_t l = 0; l < h; ++l) {
115 const T ml = num_traits<T>::from_int(static_cast<long>(m[l]));
116 T lo = zero;
117 T hi = Tv[l] > T0 ? Tv[l] : T0;
118 while (hlru_occ(lam, Tv, l, hi) < ml && hi < hicap) hi = two * hi;
119 for (int b = 0; b < 100; ++b) {
120 const T mid = (lo + hi) / two;
121 if (hlru_occ(lam, Tv, l, mid) < ml)
122 lo = mid;
123 else
124 hi = mid;
125 }
126 Tv[l] = (lo + hi) / two;
127 }
128 T rel = zero;
129 for (std::size_t l = 0; l < h; ++l) {
130 const T den = Told[l] > hlru_zero<T>() ? Told[l] : hlru_zero<T>();
131 const T d = num_abs(T(Tv[l] - Told[l])) / den;
132 if (d > rel) rel = d;
133 }
134 if (rel < hlru_finetol<T>()) break;
135 }
136 return Tv;
137}
138
139} // namespace detail
140
141/**
142 * @brief Characteristic times of the h-LRU / LRU(m) TTL approximation.
143 *
144 * @param gamma (n x 1) per-item request rates; an (n x h) matrix is accepted
145 * for backward compatibility and its first column is used, as in
146 * the MATLAB reference
147 * @param m (h) list capacities
148 * @return (h) characteristic times
149 */
150template <class T>
151std::vector<T> cache_t_hlru(const Matrix<T>& gamma, const std::vector<int>& m) {
153 "cache_t_hlru requires transcendental arithmetic");
154 if (gamma.cols() == 0) throw InputError("cache_t_hlru: empty rate matrix");
155 std::vector<T> lam(gamma.rows());
156 for (std::size_t k = 0; k < gamma.rows(); ++k) lam[k] = gamma(k, 0);
157 return detail::hlru_solve_times(lam, m);
158}
159
160} // namespace cache
161} // namespace line
162
163#endif // LINE_API_CACHE_T_HLRU_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
The exception types the port throws.
Dense matrix and non-owning view.
std::vector< T > cache_t_hlru(const Matrix< T > &gamma, const std::vector< int > &m)
Characteristic times of the h-LRU / LRU(m) TTL approximation.
T num_abs(const T &v)
Definition number.h:172
Number-type abstraction for the templated API port.