LINE Solver (C++)
Templated C++ port of the LINE queueing solver
Loading...
Searching...
No Matches
cache_t_lrum_map.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_LRUM_MAP_H
6#define LINE_API_CACHE_T_LRUM_MAP_H
7
8/**
9 * @file
10 * @ingroup api_cache
11 * Characteristic times of the LRU(m)-MAP TTL approximation.
12 *
13 * Templated port of matlab/src/api/cache/cache_t_lrum_map.m, cross-checked
14 * against jar/src/main/java/jline/api/cache/Cache_t_lrum_map.java. The times
15 * T_1..T_h are fixed by equating the expected occupancy of each list to its
16 * capacity,
17 *
18 * sum_k occ_l(item k; T) = m_l, l = 1..h,
19 *
20 * with occ from cache_lrum_map_levelstats (Gast and Van Houdt, Performance
21 * Evaluation 2017, Section 3.1.2).
22 *
23 * HOW THE SYSTEM IS SOLVED, and why it is not a multivariate optimizer:
24 * occ_l is strictly increasing in T_l (a longer timer keeps the item in list l
25 * longer), so each equation is a well-posed SCALAR root problem in its own
26 * unknown once the other times are held fixed. The system is therefore solved
27 * by Gauss-Seidel sweeps of bracketed scalar solves -- the same structure
28 * cache_t_hlru.h already uses for h-LRU -- with the bracket found by doubling
29 * and closed by bisection. The result is deterministic and needs no derivative,
30 * no line search and no trust region.
31 *
32 * That is a real improvement on both references. MATLAB calls fsolve on
33 * log(T) from a fixed zero start, so it needs the Optimization Toolbox and
34 * stops on fsolve's default tolerances (the reference instance in the tests
35 * leaves a capacity residual of about 1e-10). The JAR does not solve the
36 * system at all: it hands the residual NORM to COBYLA, a derivative-free
37 * constrained optimizer, which turns h independent monotone equations into one
38 * nonconvex minimization -- and COBYLA is stopped at rhoend = 1e-6, so its
39 * times carry a much larger error than either the MATLAB or this port.
40 *
41 * ARITHMETIC: transcendental, through cache_lrum_map_levelstats.
42 */
43
44#include <cstddef>
45#include <vector>
46
49#include "line/num/number.h"
50#include "line/util/error.h"
51#include "line/util/matrix.h"
52#include "line/util/rootfind.h"
53
54namespace line {
55namespace cache {
56
57namespace detail {
58
59/** Total occupancy of every list at the characteristic times Tv. */
60template <class T>
61std::vector<T> lrum_map_occupancy(const std::vector<mam::Map<T>>& items, const std::vector<T>& Tv) {
62 std::vector<T> occ(Tv.size(), num_traits<T>::from_int(0));
63 for (std::size_t k = 0; k < items.size(); ++k) {
64 const CacheLrumMapLevelStats<T> st =
65 cache_lrum_map_levelstats(items[k].D0, items[k].D1, Tv);
66 for (std::size_t l = 0; l < Tv.size(); ++l) occ[l] += st.occ[l];
67 }
68 return occ;
69}
70
71} // namespace detail
72
73/**
74 * @brief Characteristic times of the LRU(m)-MAP TTL approximation.
75 *
76 * @param items (n) per-item request MAPs
77 * @param m (h) list capacities, 0 < sum(m) < n
78 * @param tol relative tolerance on the times, e.g. 1e-12
79 * @param maxswp cap on Gauss-Seidel sweeps
80 * @return (h) characteristic times
81 */
82template <class T>
83std::vector<T> cache_t_lrum_map(const std::vector<mam::Map<T>>& items, const std::vector<T>& m,
84 const T& tol, unsigned maxswp = 200) {
86 "cache_t_lrum_map requires transcendental arithmetic");
87 const std::size_t n = items.size();
88 const std::size_t h = m.size();
89 if (n == 0) throw InputError("cache_t_lrum_map: no items");
90 if (h == 0) throw InputError("cache_t_lrum_map: no lists");
91 const T zero = num_traits<T>::from_int(0);
92 T total = zero;
93 for (std::size_t l = 0; l < h; ++l) {
94 if (!(m[l] > zero)) throw InputError("cache_t_lrum_map: list capacities must be positive");
95 total += m[l];
96 }
97 if (!(total < num_traits<T>::from_int(static_cast<long>(n))))
98 throw InputError("cache_t_lrum_map: the cache is not smaller than the item catalogue");
99
100 std::vector<T> Tv(h, num_traits<T>::from_int(1));
101 for (unsigned sweep = 0; sweep < maxswp; ++sweep) {
102 const std::vector<T> Told = Tv;
103 for (std::size_t l = 0; l < h; ++l) {
104 std::vector<T> work = Tv;
105 // Residual of list l as a function of its own characteristic time,
106 // increasing, negative at zero.
107 auto resid = [&](const T& x) {
108 work[l] = x;
109 return T(detail::lrum_map_occupancy(items, work)[l] - m[l]);
110 };
111 T lo = num_traits<T>::from_double(1e-12);
112 T hi = Tv[l] > lo ? Tv[l] : num_traits<T>::from_int(1);
113 if (!(resid(lo) < zero))
114 throw NumericError("cache_t_lrum_map: list occupancy exceeds its capacity even at "
115 "a vanishing characteristic time");
116 bracket_expand<T>(resid, lo, hi, 200);
117 const RootResult<T> r = root_bisect<T>(resid, lo, hi, T(tol * hi), 400);
118 Tv[l] = r.root;
119 }
120 T rel = zero;
121 for (std::size_t l = 0; l < h; ++l) {
122 const T den = Told[l] > tol ? Told[l] : tol;
123 const T d = num_abs(T(Tv[l] - Told[l])) / den;
124 if (d > rel) rel = d;
125 }
126 if (rel < tol) break;
127 }
128 return Tv;
129}
130
131} // namespace cache
132} // namespace line
133
134#endif // LINE_API_CACHE_T_LRUM_MAP_H
Level statistics of one item's embedded (list, phase) chain in the LRU(m)-MAP TTL approximation.
InputError(const std::string &what)
Definition error.h:39
NumericError(const std::string &what)
Definition error.h:45
The exception types the port throws.
Markovian arrival process descriptors: stationary vectors, rate, moments, autocorrelation and the ind...
Dense matrix and non-owning view.
CacheLrumMapLevelStats< T > cache_lrum_map_levelstats(const Matrix< T > &D0, const Matrix< T > &D1, const std::vector< T > &Tv)
Level statistics of one item's embedded (list, phase) chain in the LRU(m)-MAP TTL approximation.
std::vector< T > cache_t_lrum_map(const std::vector< mam::Map< T > > &items, const std::vector< T > &m, const T &tol, unsigned maxswp=200)
Characteristic times of the LRU(m)-MAP TTL approximation.
T num_abs(const T &v)
Definition number.h:172
RootResult< T > root_bisect(F f, const T &a, const T &b, const T &tol, unsigned maxiter=200)
Bisection on a bracket with a sign change.
Definition rootfind.h:70
void bracket_expand(F f, const T &a, T &b, unsigned maxdoubling=200)
Expand a bracket to the right until f changes sign, doubling the upper end.
Definition rootfind.h:357
Number-type abstraction for the templated API port.
Deterministic scalar root finding.
Outcome of a scalar solve.
Definition rootfind.h:52
T root
best estimate of the root
Definition rootfind.h:53
A MAP as the pair of matrices (D0, D1).
Definition map_moment.h:53