LINE Solver (C++)
Templated C++ port of the LINE queueing solver
Loading...
Searching...
No Matches
cache_rrm_meanfield_ode.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_RRM_MEANFIELD_ODE_H
6#define LINE_API_CACHE_RRM_MEANFIELD_ODE_H
7
8/**
9 * @file
10 * @ingroup api_cache
11 * Mean-field drift of the RANDOM(m) multi-list cache.
12 *
13 * Templated port of matlab/src/api/cache/cache_rrm_meanfield_ode.m,
14 * cross-checked against jar/src/main/java/jline/api/cache/
15 * Cache_rrm_meanfield_ode.java.
16 *
17 * The state x(k,s) is the probability that item k occupies list s, with s = 0
18 * meaning "not cached". A request for item k while it is in list s promotes it
19 * to list s+1 and demotes a uniformly chosen occupant of list s+1; hence the
20 * drift
21 *
22 * dx(k,s)/dt = lambda(k) x(k,s-1)
23 * - sum_j lambda(j)/m(s) x(j,s-1) x(k,s)
24 * + sum_j lambda(j)/m(s+1) x(j,s) x(k,s+1) - lambda(k) x(k,s)
25 *
26 * for 1 <= s < h, without the last two terms at s = h (an item already in the
27 * top list stays there), and dx(k,0)/dt = -sum_{s>=1} dx(k,s)/dt so that each
28 * item's occupancies stay on the simplex.
29 *
30 * Bilinear in x with rational coefficients, so the drift is a field
31 * expression: no transcendental requirement, and the exact instantiation
32 * evaluates it without rounding. Note this is the right-hand side only. The
33 * steady state (matlab's cache_rrm_meanfield script) needs a stiff ODE
34 * integrator, which is out of scope for this header.
35 *
36 * The state vector is flat in MATLAB's column-major reshape order:
37 * x[k + s*n] is x(k,s), k = 0..n-1 the item and s = 0..h the level.
38 */
39
40#include <cstddef>
41#include <vector>
42
43#include "line/num/number.h"
44#include "line/util/error.h"
45
46namespace line {
47namespace cache {
48
49/**
50 * @brief Mean-field drift of the RANDOM(m) multi-list cache.
51 *
52 * @param x (n*(h+1)) occupancies, x[k + s*n] = x(item k, level s)
53 * @param lambda (n) per-item request rates
54 * @param m (h) list capacities
55 * @return the drift, same layout as x
56 */
57template <class T>
58std::vector<T> cache_rrm_meanfield_ode(const std::vector<T>& x, const std::vector<T>& lambda,
59 const std::vector<int>& m) {
60 const std::size_t n = lambda.size();
61 const std::size_t h = m.size();
62 if (x.size() != n * (h + 1))
63 throw InputError("cache_rrm_meanfield_ode: state vector has the wrong length");
64
65 const T zero = num_traits<T>::from_int(0);
66 std::vector<T> dxdt(n * (h + 1), zero);
67
68 for (std::size_t k = 0; k < n; ++k) {
69 for (std::size_t s = 1; s <= h; ++s) {
70 if (m[s - 1] == 0)
71 throw InputError("cache_rrm_meanfield_ode: a list has zero capacity");
72 const T ms = num_traits<T>::from_int(static_cast<long>(m[s - 1]));
73
74 // outflow of item k from level s caused by promotions into level s
75 T sum1 = zero;
76 for (std::size_t j = 0; j < n; ++j)
77 sum1 += lambda[j] / ms * x[j + (s - 1) * n] * x[k + s * n];
78
79 // inflow from level s+1 (demotions), minus k's own promotion out
80 T sum2 = zero;
81 if (s < h) {
82 if (m[s] == 0) throw InputError("cache_rrm_meanfield_ode: a list has zero capacity");
83 const T ms1 = num_traits<T>::from_int(static_cast<long>(m[s]));
84 for (std::size_t j = 0; j < n; ++j)
85 sum2 += lambda[j] / ms1 * x[j + s * n] * x[k + (s + 1) * n];
86 sum2 -= lambda[k] * x[k + s * n];
87 }
88
89 dxdt[k + s * n] = lambda[k] * x[k + (s - 1) * n] - sum1 + sum2;
90 }
91 T acc = zero;
92 for (std::size_t s = 1; s <= h; ++s) acc += dxdt[k + s * n];
93 dxdt[k] = -acc;
94 }
95 return dxdt;
96}
97
98} // namespace cache
99} // namespace line
100
101#endif // LINE_API_CACHE_RRM_MEANFIELD_ODE_H
InputError(const std::string &what)
Definition error.h:39
The exception types the port throws.
std::vector< T > cache_rrm_meanfield_ode(const std::vector< T > &x, const std::vector< T > &lambda, const std::vector< int > &m)
Mean-field drift of the RANDOM(m) multi-list cache.
Number-type abstraction for the templated API port.