LINE Solver
MATLAB API documentation
Loading...
Searching...
No Matches
solver_fluid_rmf.m
1function [QN, UN, RN, TN, xvec_iter, QNt, UNt, TNt, xvec_t, t] = solver_fluid_rmf(sn, options)
2% SOLVER_FLUID_RMF Refined mean field solver for multi-list cache analysis
3%
4% Implements mean field and refined mean field (1/N correction) analysis
5% for multi-list caches with RANDOM(m) replacement policy, based on the
6% DDPP (Density-Dependent Population Process) framework.
7%
8% The cache is modeled as a population process where each item can be in
9% one of h+1 states: list 1, list 2, ..., list h, or outside the cache
10% (list 0). Transitions occur when an item is requested: the requested
11% item moves up (toward list 1) while a displaced item moves down
12% (toward list 0).
13%
14% Reference:
15% N. Gast, "Expected Values Estimated via Mean-Field Approximation are
16% 1/N-Accurate", Proc. ACM Meas. Anal. Comput. Syst., 2017.
17
18% Copyright (c) 2012-2026, Imperial College London
19% All rights reserved.
20
21M = sn.nstations;
22K = sn.nclasses;
23
24% Initialize output arrays
25QN = NaN(M, K);
26UN = NaN(M, K);
27RN = NaN(M, K);
28TN = NaN(M, K);
29
30% Initialize transient outputs
31QNt = cell(M, K);
32UNt = cell(M, K);
33TNt = cell(M, K);
34for ist = 1:M
35 for r = 1:K
36 QNt{ist, r} = zeros(2, 1);
37 UNt{ist, r} = zeros(2, 1);
38 TNt{ist, r} = zeros(2, 1);
39 end
40end
41t = [0; 1];
42xvec_t = zeros(2, 1);
43xvec_iter = {zeros(1, 1)};
44
45% Scan for cache nodes
46for ind = 1:sn.nnodes
47 if sn.nodetype(ind) ~= NodeType.Cache
48 continue
49 end
50 ch = sn.nodeparam{ind};
51 if ch.nitems == 0
52 continue
53 end
54
55 % Extract cache parameters
56 n_items = ch.nitems;
57 itemcap = ch.itemcap;
58 pread = ch.pread;
59 h = length(itemcap); % number of lists
60 m = itemcap(:)'; % row vector of list capacities
61
62 % Initialize actual hit/miss probability arrays if needed
63 if ~isfield(ch, 'actualhitprob') || isempty(ch.actualhitprob)
64 ch.actualhitprob = zeros(1, K);
65 end
66 if ~isfield(ch, 'actualmissprob') || isempty(ch.actualmissprob)
67 ch.actualmissprob = zeros(1, K);
68 end
69
70 % Process each class
71 for r = 1:K
72 if r > length(pread) || isempty(pread{r}) || all(isnan(pread{r}))
73 continue
74 end
75
76 p = pread{r}(:)';
77 if length(p) ~= n_items
78 continue
79 end
80
81 % Normalize popularity distribution
82 p_sum = sum(p);
83 if p_sum <= 0
84 continue
85 end
86 p = p / p_sum;
87
88 % Build and solve the DDPP cache model
89 model_dim = n_items * (h + 1);
90
91 % Build initial state: first m(1) items in list 1, next m(2) in
92 % list 2, etc.; remaining items outside cache (list 0)
93 x0 = zeros(model_dim, 1);
94 obj_idx = 0;
95 for k = 1:h
96 for jj = 1:m(k)
97 obj_idx = obj_idx + 1;
98 if obj_idx <= n_items
99 x0(rmf_index(obj_idx, k, n_items)) = 1.0;
100 end
101 end
102 end
103 for i = (obj_idx + 1):n_items
104 x0(rmf_index(i, 0, n_items)) = 1.0;
105 end
106
107 % Compute mean field fixed point by ODE integration
108 pi = rmf_fixed_point(x0, p, m, n_items, h, model_dim);
109
110 % Compute hit/miss probabilities from fixed point
111 hit_prob = 0.0;
112 for k = 1:h
113 hit_prob = hit_prob + rmf_hit_rate(pi, p, k, n_items);
114 end
115 miss_prob = rmf_hit_rate(pi, p, 0, n_items);
116
117 % Try refined mean field (1/N correction)
118 try
119 [pi_mf, V] = rmf_expansion_steady_state(x0, p, m, n_items, h, model_dim);
120 pi_refined = pi_mf + V / n_items;
121
122 % Recompute hit/miss with refined approximation
123 hit_prob_refined = 0.0;
124 for k = 1:h
125 hit_prob_refined = hit_prob_refined + rmf_hit_rate(pi_refined, p, k, n_items);
126 end
127 miss_prob_refined = rmf_hit_rate(pi_refined, p, 0, n_items);
128 hit_prob = hit_prob_refined;
129 miss_prob = miss_prob_refined;
130 catch
131 % Fall back to plain mean field
132 end
133
134 % Store actual hit/miss probabilities, clipped to [0, 1]
135 ch.actualhitprob(r) = max(0, min(1, hit_prob));
136 ch.actualmissprob(r) = max(0, min(1, miss_prob));
137 end
138
139 % Store back
140 sn.nodeparam{ind} = ch;
141end
142
143end
144
145%% ========================================================================
146% Helper functions for DDPP cache model
147% ========================================================================
148
149function idx = rmf_index(i, k, n_items)
150% RMF_INDEX Map (item i, list k) to flat state index
151% i: item index (1-based)
152% k: list index (0 = outside cache, 1..h = cache lists)
153% n_items: total number of items
154idx = i + k * n_items;
155end
156
157function hr = rmf_hit_rate(x, p, list_number, n_items)
158% RMF_HIT_RATE Compute hit rate contribution from a specific list
159% hr = sum_i p(i) * x(index(i, list_number))
160hr = 0.0;
161for i = 1:n_items
162 hr = hr + p(i) * x(rmf_index(i, list_number, n_items));
163end
164end
165
166function dX = rmf_drift(x, p, m, n_items, h, model_dim)
167% RMF_DRIFT Compute mean field drift F(x) for RANDOM(m) replacement
168%
169% dx[i,k]/dt = -p(i)*x[i,k] + hitRate[k]*x[i,k+1]/m(k) (promotion from k to k+1)
170% dx[i,k+1]/dt = p(i)*x[i,k] - hitRate[k]*x[i,k+1]/m(k)
171
172hit_rates = zeros(1, h + 1);
173for k = 0:h
174 hit_rates(k + 1) = rmf_hit_rate(x, p, k, n_items);
175end
176
177dX = zeros(model_dim, 1);
178for i = 1:n_items
179 for k = 0:(h - 1)
180 flow = p(i) * x(rmf_index(i, k, n_items)) ...
181 - hit_rates(k + 1) * x(rmf_index(i, k + 1, n_items)) / m(k + 1);
182 dX(rmf_index(i, k, n_items)) = dX(rmf_index(i, k, n_items)) - flow;
183 dX(rmf_index(i, k + 1, n_items)) = dX(rmf_index(i, k + 1, n_items)) + flow;
184 end
185end
186end
187
188function Fp = rmf_jacobian(x, p, m, n_items, h, model_dim)
189% RMF_JACOBIAN Compute Jacobian dF/dx at state x
190
191hit_rates = zeros(1, h + 1);
192for k = 0:h
193 hit_rates(k + 1) = rmf_hit_rate(x, p, k, n_items);
194end
195
196Fp = zeros(model_dim, model_dim);
197for i = 1:n_items
198 for k = 0:(h - 1)
199 ik = rmf_index(i, k, n_items);
200 ik1 = rmf_index(i, k + 1, n_items);
201
202 % Direct rate terms
203 Fp(ik, ik) = Fp(ik, ik) - p(i);
204 Fp(ik1, ik) = Fp(ik1, ik) + p(i);
205 Fp(ik, ik1) = Fp(ik, ik1) + hit_rates(k + 1) / m(k + 1);
206 Fp(ik1, ik1) = Fp(ik1, ik1) - hit_rates(k + 1) / m(k + 1);
207
208 % Indirect terms via hit rate dependence on x(j,k)
209 for j = 1:n_items
210 jk = rmf_index(j, k, n_items);
211 jk1 = rmf_index(j, k + 1, n_items);
212 Fp(ik, jk1) = Fp(ik, jk1) - p(i) * x(ik) / m(k + 1);
213 Fp(ik1, jk1) = Fp(ik1, jk1) + p(i) * x(ik) / m(k + 1);
214 Fp(ik, jk) = Fp(ik, jk) + p(j) * x(ik1) / m(k + 1);
215 Fp(ik1, jk) = Fp(ik1, jk) - p(j) * x(ik1) / m(k + 1);
216 end
217 end
218end
219end
220
221function Fpp = rmf_hessian(~, p, m, n_items, h, model_dim)
222% RMF_HESSIAN Compute Hessian d^2F/dx^2 (constant for this quadratic drift)
223
224Fpp = zeros(model_dim, model_dim, model_dim);
225for i = 1:n_items
226 for k = 0:(h - 1)
227 ik = rmf_index(i, k, n_items);
228 ik1 = rmf_index(i, k + 1, n_items);
229 for j = 1:n_items
230 if j ~= i
231 jk = rmf_index(j, k, n_items);
232 jk1 = rmf_index(j, k + 1, n_items);
233 % d^2 F[ik] / (d x[jk] d x[ik1])
234 Fpp(ik, jk, ik1) = Fpp(ik, jk, ik1) + p(j) / m(k + 1);
235 Fpp(ik, ik1, jk) = Fpp(ik, ik1, jk) + p(j) / m(k + 1);
236 % d^2 F[ik] / (d x[jk1] d x[ik])
237 Fpp(ik, jk1, ik) = Fpp(ik, jk1, ik) - p(i) / m(k + 1);
238 Fpp(ik, ik, jk1) = Fpp(ik, ik, jk1) - p(i) / m(k + 1);
239 % Symmetric for ik1
240 Fpp(ik1, jk, ik1) = Fpp(ik1, jk, ik1) - p(j) / m(k + 1);
241 Fpp(ik1, ik1, jk) = Fpp(ik1, ik1, jk) - p(j) / m(k + 1);
242 Fpp(ik1, jk1, ik) = Fpp(ik1, jk1, ik) + p(i) / m(k + 1);
243 Fpp(ik1, ik, jk1) = Fpp(ik1, ik, jk1) + p(i) / m(k + 1);
244 end
245 end
246 end
247end
248end
249
250function Q = rmf_noise_matrix(x, p, m, n_items, h, model_dim)
251% RMF_NOISE_MATRIX Compute noise intensity matrix Q(x) for the DDPP
252%
253% Q[a,b] = sum_ell ell[a]*ell[b]*beta_ell(x)
254% Each transition swaps items i and j across lists k and k+1.
255
256Q = zeros(model_dim, model_dim);
257signs = [-1, 1, 1, -1];
258for i = 1:n_items
259 for k = 0:(h - 1)
260 for j = 1:n_items
261 rate = p(i) * x(rmf_index(i, k, n_items)) ...
262 * x(rmf_index(j, k + 1, n_items)) / m(k + 1);
263 indices = [rmf_index(i, k, n_items), ...
264 rmf_index(j, k, n_items), ...
265 rmf_index(i, k + 1, n_items), ...
266 rmf_index(j, k + 1, n_items)];
267 for ia = 1:4
268 for ib = 1:4
269 Q(indices(ia), indices(ib)) = Q(indices(ia), indices(ib)) ...
270 + rate * signs(ia) * signs(ib);
271 end
272 end
273 end
274 end
275end
276end
277
278function pi = rmf_fixed_point(x0, p, m, n_items, h, model_dim)
279% RMF_FIXED_POINT Compute mean field fixed point by ODE integration
280%
281% Integrates dx/dt = F(x) until steady state using LSODA.
282
283tmax = 10000;
284ode_func = @(t, x) rmf_drift(x, p, m, n_items, h, model_dim);
285odeopt = odeset('AbsTol', 1e-10, 'RelTol', 1e-8);
286%[~, xvec] = ode15s(ode_func, [0, tmax], x0, odeopt);
287[~, xvec] = lsoda_solve(ode_func, [0, tmax], x0, odeopt);
288pi = xvec(end, :)';
289end
290
291function [C, Cinv, rk] = rmf_dimension_reduction(Fp, n_items, h, model_dim)
292% RMF_DIMENSION_REDUCTION Compute change-of-basis for singular Jacobian
293%
294% The Jacobian is singular because item populations are conserved
295% (sum over lists for each item = 1). Returns matrices to project
296% onto the non-singular subspace.
297
298rk = rank(Fp);
299
300C = zeros(model_dim, model_dim);
301d = 0;
302for l_idx = 0:h
303 for i = 1:(n_items - 1)
304 d = d + 1;
305 C(d, rmf_index(i, l_idx, n_items)) = 1.0;
306 end
307end
308
309[U, ~, ~] = svd(Fp);
310C((rk + 1):model_dim, :) = U(:, (rk + 1):model_dim)';
311Cinv = inv(C);
312end
313
314function [pi, V] = rmf_expansion_steady_state(x0, p, m, n_items, h, model_dim)
315% RMF_EXPANSION_STEADY_STATE Compute refined mean field steady-state expansion
316%
317% Computes the mean field fixed point pi and the 1/N correction V
318% using the Lyapunov equation approach with dimension reduction.
319%
320% The refined approximation for a system of N items is:
321% E[X] ~ pi + V/N + O(1/N^2)
322
323pi = rmf_fixed_point(x0, p, m, n_items, h, model_dim);
324
325Fp = rmf_jacobian(pi, p, m, n_items, h, model_dim);
326Fpp = rmf_hessian(pi, p, m, n_items, h, model_dim);
327Q = rmf_noise_matrix(pi, p, m, n_items, h, model_dim);
328
329% Dimension reduction: project onto non-singular subspace
330[C, Cinv, rk] = rmf_dimension_reduction(Fp, n_items, h, model_dim);
331
332Fp_r = (C * Fp * Cinv);
333Fp_r = Fp_r(1:rk, 1:rk);
334
335% Reduce Hessian: Fpp_r(a,b,c) = sum_{i,j,k} C(a,i)*Fpp(i,j,k)*Cinv(j,b)*Cinv(k,c)
336% First contraction: tmp1(a,j,k) = sum_i C(a,i)*Fpp(i,j,k)
337tmp1 = zeros(model_dim, model_dim, model_dim);
338for a = 1:rk
339 for j = 1:model_dim
340 for k = 1:model_dim
341 tmp1(a, j, k) = C(a, :) * Fpp(:, j, k);
342 end
343 end
344end
345% Second contraction: tmp2(a,b,k) = sum_j tmp1(a,j,k)*Cinv(j,b)
346tmp2 = zeros(rk, rk, model_dim);
347for a = 1:rk
348 for b = 1:rk
349 for k = 1:model_dim
350 tmp2(a, b, k) = tmp1(a, :, k) * Cinv(:, b);
351 end
352 end
353end
354% Third contraction: Fpp_r(a,b,c) = sum_k tmp2(a,b,k)*Cinv(k,c)
355Fpp_r = zeros(rk, rk, rk);
356for a = 1:rk
357 for b = 1:rk
358 Fpp_r(a, b, :) = reshape(tmp2(a, b, :), 1, []) * Cinv(:, 1:rk);
359 end
360end
361
362Q_r = C * Q * C';
363Q_r = Q_r(1:rk, 1:rk);
364
365% Solve Lyapunov equation: Fp_r * W_r + W_r * Fp_r' + Q_r = 0
366W_r = lyap(Fp_r, Q_r);
367
368% First-order correction: V_r = -Fp_r \ (C_r / 2)
369% where C_r = sum_{b,c} Fpp_r(:,b,c) * W_r(b,c)
370C_r = zeros(rk, 1);
371for a = 1:rk
372 for b = 1:rk
373 for c = 1:rk
374 C_r(a) = C_r(a) + Fpp_r(a, b, c) * W_r(b, c);
375 end
376 end
377end
378V_r = -Fp_r \ (C_r / 2.0);
379
380% Expand back to full dimension
381V = Cinv(:, 1:rk) * V_r;
382end
Definition mmt.m:124