LINE Solver
MATLAB API documentation
Loading...
Searching...
No Matches
cache_miss_rmf.m
1%{ @file cache_miss_rmf.m
2 % @brief Computes miss rates using the refined mean field (RMF) method
3 %
4 % @author LINE Development Team
5%}
6
7%{
8 % @brief Computes cache miss rates for RANDOM(m) replacement via refined mean field
9 %
10 % @details
11 % This function computes global, per-user, and per-item miss rates for
12 % multi-list caches with RANDOM(m) replacement using the DDPP mean field
13 % approximation with 1/N correction (refined mean field). The cache
14 % occupancy is computed from the aggregate request stream; per-user miss
15 % rates weight the per-item miss probabilities by each user's rates.
16 %
17 % Reference:
18 % N. Gast, "Expected Values Estimated via Mean-Field Approximation are
19 % 1/N-Accurate", Proc. ACM Meas. Anal. Comput. Syst., 2017.
20 %
21 % @par Syntax:
22 % @code
23 % [M, MU, MI, pi0] = cache_miss_rmf(gamma, m, lambda)
24 % @endcode
25 %
26 % @par Parameters:
27 % <table>
28 % <tr><th>Name<th>Description
29 % <tr><td>gamma<td>Item access factors (used for sizing only)
30 % <tr><td>m<td>Cache capacity vector
31 % <tr><td>lambda<td>Arrival rates per user per item per list
32 % </table>
33 %
34 % @par Returns:
35 % <table>
36 % <tr><th>Name<th>Description
37 % <tr><td>M<td>Global miss rate
38 % <tr><td>MU<td>Per-user miss rate
39 % <tr><td>MI<td>Per-item miss rate
40 % <tr><td>pi0<td>Per-item miss probability
41 % </table>
42%}
43function [M,MU,MI,pi0,tout,pi0_t,MU_t,xtraj] = cache_miss_rmf(gamma, m, lambda, tspan, x0init) %#ok<INUSL>
44% Optional TSPAN = [t0, t1] and initial occupancy X0INIT request the
45% transient mean-field trajectory: integrating the same drift F(x) that
46% RMF_FIXED_POINT drives to steady state, over the finite window. Returns
47% the time grid TOUT, the per-item list-0 occupancy PI0_T (n_items x nt)
48% and the per-user miss-rate trajectory MU_T (u x nt). Omitting TSPAN
49% preserves the original steady-state-only contract.
50if nargin < 4, tspan = []; end
51if nargin < 5, x0init = []; end
52u = size(lambda,1);
53n_items = size(lambda,2);
54h = length(m);
55m = m(:)';
56
57% aggregate per-item request rates over users
58lam_i = zeros(1, n_items);
59for v = 1:u
60 row = lambda(v,:,1);
61 row(~isfinite(row)) = 0;
62 lam_i = lam_i + row;
63end
64p = lam_i / sum(lam_i);
65
66model_dim = n_items * (h + 1);
67
68% Build initial state: first m(1) items in list 1, next m(2) in
69% list 2, etc.; remaining items outside cache (list 0)
70x0 = zeros(model_dim, 1);
71obj_idx = 0;
72for k = 1:h
73 for jj = 1:m(k)
74 obj_idx = obj_idx + 1;
75 if obj_idx <= n_items
76 x0(rmf_index(obj_idx, k, n_items)) = 1.0;
77 end
78 end
79end
80for i = (obj_idx + 1):n_items
81 x0(rmf_index(i, 0, n_items)) = 1.0;
82end
83
84% Mean field fixed point, then 1/N refinement when computable. The
85% refinement solves a reduced Jacobian/Lyapunov system that turns singular
86% for small or non-hyperbolic fixed points; MATLAB signals this with a
87% (non-error) warning and returns non-finite entries rather than throwing,
88% so a bare try/catch does not catch it. Accept the 1/N correction only
89% when it is finite, otherwise keep the plain mean-field fixed point.
90xss = rmf_fixed_point(x0, p, m, n_items, h, model_dim);
91% The refinement's reduced linear system is expected to be singular for
92% small/non-hyperbolic fixed points; silence only that specific warning here
93% since the non-finite result is detected and rejected below.
94ws1 = warning('off', 'MATLAB:singularMatrix');
95ws2 = warning('off', 'MATLAB:nearlySingularMatrix');
96restoreWarn = onCleanup(@() warning([ws1 ws2]));
97try
98 [pi_mf, V] = rmf_expansion_steady_state(x0, p, m, n_items, h, model_dim);
99 xref = pi_mf + V / n_items;
100 if all(isfinite(xref))
101 xss = xref;
102 end
103catch
104 % Fall back to plain mean field
105end
106clear restoreWarn
107
108% Per-item miss probability (occupancy of list 0), clipped to [0,1]
109pi0 = zeros(n_items, 1);
110for i = 1:n_items
111 pi0(i) = max(0, min(1, xss(rmf_index(i, 0, n_items))));
112end
113
114MI = lam_i(:) .* pi0;
115MU = zeros(1, u);
116for v = 1:u
117 row = lambda(v,:,1);
118 row(~isfinite(row)) = 0;
119 MU(v) = row * pi0;
120end
121M = sum(MI);
122
123% Transient mean-field trajectory (optional): integrate the drift over the
124% requested window from the supplied (or default) initial occupancy. XTRAJ is
125% the full DDPP occupancy trajectory (model_dim x nt), used to carry the cache
126% mean occupancy across environment switches.
127tout = []; pi0_t = []; MU_t = []; xtraj = [];
128if ~isempty(tspan)
129 if isempty(x0init)
130 x0init = x0;
131 else
132 x0init = x0init(:);
133 end
134 ode_func = @(t, x) rmf_drift(x, p, m, n_items, h, model_dim);
135 odeopt = odeset('AbsTol', 1e-10, 'RelTol', 1e-8);
136 [tout, xtraj] = ode15s(ode_func, tspan, x0init, odeopt);
137 xtraj = xtraj'; % model_dim x nt
138 nt = numel(tout);
139 pi0_t = zeros(n_items, nt);
140 for i = 1:n_items
141 pi0_t(i,:) = max(0, min(1, xtraj(rmf_index(i, 0, n_items), :)));
142 end
143 MU_t = zeros(u, nt);
144 for v = 1:u
145 row = lambda(v,:,1);
146 row(~isfinite(row)) = 0;
147 MU_t(v,:) = row * pi0_t;
148 end
149end
150end
151
152function idx = rmf_index(i, k, n_items)
153% RMF_INDEX Map (item i, list k) to flat state index
154% i: item index (1-based)
155% k: list index (0 = outside cache, 1..h = cache lists)
156% n_items: total number of items
157idx = i + k * n_items;
158end
159
160function hr = rmf_hit_rate(x, p, list_number, n_items)
161% RMF_HIT_RATE Compute hit rate contribution from a specific list
162% hr = sum_i p(i) * x(index(i, list_number))
163hr = 0.0;
164for i = 1:n_items
165 hr = hr + p(i) * x(rmf_index(i, list_number, n_items));
166end
167end
168
169function dX = rmf_drift(x, p, m, n_items, h, model_dim)
170% RMF_DRIFT Compute mean field drift F(x) for RANDOM(m) replacement
171%
172% dx[i,k]/dt = -p(i)*x[i,k] + hitRate[k]*x[i,k+1]/m(k) (promotion from k to k+1)
173% dx[i,k+1]/dt = p(i)*x[i,k] - hitRate[k]*x[i,k+1]/m(k)
174
175hit_rates = zeros(1, h + 1);
176for k = 0:h
177 hit_rates(k + 1) = rmf_hit_rate(x, p, k, n_items);
178end
179
180dX = zeros(model_dim, 1);
181for i = 1:n_items
182 for k = 0:(h - 1)
183 flow = p(i) * x(rmf_index(i, k, n_items)) ...
184 - hit_rates(k + 1) * x(rmf_index(i, k + 1, n_items)) / m(k + 1);
185 dX(rmf_index(i, k, n_items)) = dX(rmf_index(i, k, n_items)) - flow;
186 dX(rmf_index(i, k + 1, n_items)) = dX(rmf_index(i, k + 1, n_items)) + flow;
187 end
188end
189end
190
191function Fp = rmf_jacobian(x, p, m, n_items, h, model_dim)
192% RMF_JACOBIAN Compute Jacobian dF/dx at state x
193
194hit_rates = zeros(1, h + 1);
195for k = 0:h
196 hit_rates(k + 1) = rmf_hit_rate(x, p, k, n_items);
197end
198
199Fp = zeros(model_dim, model_dim);
200for i = 1:n_items
201 for k = 0:(h - 1)
202 ik = rmf_index(i, k, n_items);
203 ik1 = rmf_index(i, k + 1, n_items);
204
205 % Direct rate terms
206 Fp(ik, ik) = Fp(ik, ik) - p(i);
207 Fp(ik1, ik) = Fp(ik1, ik) + p(i);
208 Fp(ik, ik1) = Fp(ik, ik1) + hit_rates(k + 1) / m(k + 1);
209 Fp(ik1, ik1) = Fp(ik1, ik1) - hit_rates(k + 1) / m(k + 1);
210
211 % Indirect terms via hit rate dependence on x(j,k)
212 for j = 1:n_items
213 jk = rmf_index(j, k, n_items);
214 jk1 = rmf_index(j, k + 1, n_items);
215 Fp(ik, jk1) = Fp(ik, jk1) - p(i) * x(ik) / m(k + 1);
216 Fp(ik1, jk1) = Fp(ik1, jk1) + p(i) * x(ik) / m(k + 1);
217 Fp(ik, jk) = Fp(ik, jk) + p(j) * x(ik1) / m(k + 1);
218 Fp(ik1, jk) = Fp(ik1, jk) - p(j) * x(ik1) / m(k + 1);
219 end
220 end
221end
222end
223
224function Fpp = rmf_hessian(~, p, m, n_items, h, model_dim)
225% RMF_HESSIAN Compute Hessian d^2F/dx^2 (constant for this quadratic drift)
226
227Fpp = zeros(model_dim, model_dim, model_dim);
228for i = 1:n_items
229 for k = 0:(h - 1)
230 ik = rmf_index(i, k, n_items);
231 ik1 = rmf_index(i, k + 1, n_items);
232 for j = 1:n_items
233 if j ~= i
234 jk = rmf_index(j, k, n_items);
235 jk1 = rmf_index(j, k + 1, n_items);
236 % d^2 F[ik] / (d x[jk] d x[ik1])
237 Fpp(ik, jk, ik1) = Fpp(ik, jk, ik1) + p(j) / m(k + 1);
238 Fpp(ik, ik1, jk) = Fpp(ik, ik1, jk) + p(j) / m(k + 1);
239 % d^2 F[ik] / (d x[jk1] d x[ik])
240 Fpp(ik, jk1, ik) = Fpp(ik, jk1, ik) - p(i) / m(k + 1);
241 Fpp(ik, ik, jk1) = Fpp(ik, ik, jk1) - p(i) / m(k + 1);
242 % Symmetric for ik1
243 Fpp(ik1, jk, ik1) = Fpp(ik1, jk, ik1) - p(j) / m(k + 1);
244 Fpp(ik1, ik1, jk) = Fpp(ik1, ik1, jk) - p(j) / m(k + 1);
245 Fpp(ik1, jk1, ik) = Fpp(ik1, jk1, ik) + p(i) / m(k + 1);
246 Fpp(ik1, ik, jk1) = Fpp(ik1, ik, jk1) + p(i) / m(k + 1);
247 end
248 end
249 end
250end
251end
252
253function Q = rmf_noise_matrix(x, p, m, n_items, h, model_dim)
254% RMF_NOISE_MATRIX Compute noise intensity matrix Q(x) for the DDPP
255%
256% Q[a,b] = sum_ell ell[a]*ell[b]*beta_ell(x)
257% Each transition swaps items i and j across lists k and k+1.
258
259Q = zeros(model_dim, model_dim);
260signs = [-1, 1, 1, -1];
261for i = 1:n_items
262 for k = 0:(h - 1)
263 for j = 1:n_items
264 rate = p(i) * x(rmf_index(i, k, n_items)) ...
265 * x(rmf_index(j, k + 1, n_items)) / m(k + 1);
266 indices = [rmf_index(i, k, n_items), ...
267 rmf_index(j, k, n_items), ...
268 rmf_index(i, k + 1, n_items), ...
269 rmf_index(j, k + 1, n_items)];
270 for ia = 1:4
271 for ib = 1:4
272 Q(indices(ia), indices(ib)) = Q(indices(ia), indices(ib)) ...
273 + rate * signs(ia) * signs(ib);
274 end
275 end
276 end
277 end
278end
279end
280
281function pi = rmf_fixed_point(x0, p, m, n_items, h, model_dim)
282% RMF_FIXED_POINT Compute mean field fixed point by ODE integration
283%
284% Integrates dx/dt = F(x) until steady state using ode15s.
285
286tmax = 10000;
287ode_func = @(t, x) rmf_drift(x, p, m, n_items, h, model_dim);
288odeopt = odeset('AbsTol', 1e-10, 'RelTol', 1e-8);
289[~, xvec] = ode15s(ode_func, [0, tmax], x0, odeopt);
290%[~, xvec] = lsoda_solve(ode_func, [0, tmax], x0, odeopt);
291pi = xvec(end, :)';
292end
293
294function [C, Cinv, rk] = rmf_dimension_reduction(Fp, n_items, h, model_dim)
295% RMF_DIMENSION_REDUCTION Compute change-of-basis for singular Jacobian
296%
297% The Jacobian is singular because item populations are conserved
298% (sum over lists for each item = 1). Returns matrices to project
299% onto the non-singular subspace.
300
301rk = rank(Fp);
302
303C = zeros(model_dim, model_dim);
304d = 0;
305for l_idx = 0:h
306 for i = 1:(n_items - 1)
307 d = d + 1;
308 C(d, rmf_index(i, l_idx, n_items)) = 1.0;
309 end
310end
311
312[U, ~, ~] = svd(Fp);
313C((rk + 1):model_dim, :) = U(:, (rk + 1):model_dim)';
314Cinv = inv(C);
315end
316
317function [pi, V] = rmf_expansion_steady_state(x0, p, m, n_items, h, model_dim)
318% RMF_EXPANSION_STEADY_STATE Compute refined mean field steady-state expansion
319%
320% Computes the mean field fixed point pi and the 1/N correction V
321% using the Lyapunov equation approach with dimension reduction.
322%
323% The refined approximation for a system of N items is:
324% E[X] ~ pi + V/N + O(1/N^2)
325
326pi = rmf_fixed_point(x0, p, m, n_items, h, model_dim);
327
328Fp = rmf_jacobian(pi, p, m, n_items, h, model_dim);
329Fpp = rmf_hessian(pi, p, m, n_items, h, model_dim);
330Q = rmf_noise_matrix(pi, p, m, n_items, h, model_dim);
331
332% Dimension reduction: project onto non-singular subspace
333[C, Cinv, rk] = rmf_dimension_reduction(Fp, n_items, h, model_dim);
334
335Fp_r = (C * Fp * Cinv);
336Fp_r = Fp_r(1:rk, 1:rk);
337
338% Reduce Hessian: Fpp_r(a,b,c) = sum_{i,j,k} C(a,i)*Fpp(i,j,k)*Cinv(j,b)*Cinv(k,c)
339% First contraction: tmp1(a,j,k) = sum_i C(a,i)*Fpp(i,j,k)
340tmp1 = zeros(model_dim, model_dim, model_dim);
341for a = 1:rk
342 for j = 1:model_dim
343 for k = 1:model_dim
344 tmp1(a, j, k) = C(a, :) * Fpp(:, j, k);
345 end
346 end
347end
348% Second contraction: tmp2(a,b,k) = sum_j tmp1(a,j,k)*Cinv(j,b)
349tmp2 = zeros(rk, rk, model_dim);
350for a = 1:rk
351 for b = 1:rk
352 for k = 1:model_dim
353 tmp2(a, b, k) = tmp1(a, :, k) * Cinv(:, b);
354 end
355 end
356end
357% Third contraction: Fpp_r(a,b,c) = sum_k tmp2(a,b,k)*Cinv(k,c)
358Fpp_r = zeros(rk, rk, rk);
359for a = 1:rk
360 for b = 1:rk
361 Fpp_r(a, b, :) = reshape(tmp2(a, b, :), 1, []) * Cinv(:, 1:rk);
362 end
363end
364
365Q_r = C * Q * C';
366Q_r = Q_r(1:rk, 1:rk);
367
368% Solve Lyapunov equation: Fp_r * W_r + W_r * Fp_r' + Q_r = 0
369W_r = lyap(Fp_r, Q_r);
370
371% First-order correction: V_r = -Fp_r \ (C_r / 2)
372% where C_r = sum_{b,c} Fpp_r(:,b,c) * W_r(b,c)
373C_r = zeros(rk, 1);
374for a = 1:rk
375 for b = 1:rk
376 for c = 1:rk
377 C_r(a) = C_r(a) + Fpp_r(a, b, c) * W_r(b, c);
378 end
379 end
380end
381V_r = -Fp_r \ (C_r / 2.0);
382
383% Expand back to full dimension
384V = Cinv(:, 1:rk) * V_r;
385end
Definition Station.m:245