LINE Solver
MATLAB API documentation
Loading...
Searching...
No Matches
infer_fmlps.m
1function demandEst = infer_fmlps(model, node, rt, class, ql, W)
2% INFER_FMLPS FMLPS demand estimation using sn struct-level operations.
3%
4% Estimates service demands at a PS queue using the Fluid Maximum
5% Likelihood for Processor Sharing method. Uses sn_set_service for
6% fast parameter updates, avoiding model.reset()/getStruct() in the
7% optimization loop.
8%
9% Inputs:
10% model - LINE Network model with delay rates set and queue rates to estimate
11% node - PS queue node (Station object)
12% rt - response time samples (column vector, n x 1)
13% class - class of each sample (column vector, n x 1)
14% ql - queue lengths at arrival (n x R matrix, per-class)
15% W - total population (number of threads/jobs)
16%
17% Returns:
18% demandEst - 1 x R vector of estimated mean service demands
19%
20% Copyright (c) 2012-2026, Imperial College London
21% All rights reserved.
22% This code is released under the 3-Clause BSD License.
23
24sn = model.getStruct();
25R = sn.nclasses;
26V = node.getNumberOfServers();
27stIdx = node.stationIndex;
28
29xLB = min(rt) * ones(1, R) / W;
30xUB = max(rt) * ones(1, R);
31
32% Initial point estimate
33meanQL = mean(sum(ql, 2));
34Vtilde = min(meanQL, V);
35x0 = zeros(1, R);
36for j = 1:R
37 if ~isempty(rt(class == j))
38 x0(j) = Vtilde * mean(rt(class == j)) / meanQL;
39 else
40 x0(j) = xLB(j);
41 end
42end
43
44% Cache station indices (invariant across iterations)
45delayIdx = 0;
46refIdx = 0;
47for ii = 1:sn.nstations
48 if sn.sched(ii) == SchedStrategy.INF
49 delayIdx = ii;
50 else
51 refIdx = ii;
52 end
53end
54
55% Cache delay rates (invariant across iterations)
56delayRates = zeros(1, R);
57for kk = 1:R
58 delayRates(kk) = sn.mu{delayIdx}{kk}(1);
59end
60
61%% Optimization options
62options = optimset();
63options.Display = 'iter';
64options.Algorithm = 'interior-point';
65options.LargeScale = 'on';
66options.MaxIter = 1e10;
67options.MaxFunEvals = 1e10;
68options.MaxSQPIter = 5000;
69options.TolCon = 1e-6;
70options.TolX = 1e-10;
71
72[demandEst, ~] = fmincon(@objfun, x0, [], [], [], [], xLB, xUB, [], options);
73
74 function f = objfun(x)
75 TOL = 1e-6;
76
77 % Update service rates (cell-of-cells format for solver compatibility)
78 for r = 1:R
79 sn = sn_set_service_coc(sn, stIdx, r, 1/x(r));
80 end
81
82 % Build augmented ODE for each unique tagged class (once per iteration)
83 uniqueTC = unique(class);
84 ftemp = zeros(size(rt));
85
86 for u = 1:length(uniqueTC)
87 tc = uniqueTC(u);
88 mask = (class == tc);
89 rt_tc = rt(mask);
90 ql_tc = ql(mask, :);
91
92 % Build augmented model and ODE handle from sn struct directly
93 [ode_h, q_idx, augPhases] = infer_fluid_ps_rt_likelihood(sn, tc);
94
95 % Solve each sample reusing the same ODE handle
96 ftemp_tc = zeros(size(rt_tc));
97 for rr = 1:length(rt_tc)
98 like = solve_fmlps_sample(ode_h, q_idx, augPhases, ...
99 delayRates, delayIdx, refIdx, R, ...
100 ql_tc(rr,:), W, tc, rt_tc(rr));
101 ftemp_tc(rr) = log(TOL + like);
102 end
103 ftemp(mask) = ftemp_tc;
104 end
105 f = -sum(ftemp);
106 end
107
108end
109
110
111function LIKE = solve_fmlps_sample(ode_h, q_indices, augPhases, ...
112 delayRates, delayIdx, refIdx, K, aQueue, W, taggedClass, Rsampled)
113% Solve the fluid ODE for a single sample and extract the response time likelihood.
114%
115% Uses the pre-built ODE handle from the augmented model. Only computes
116% the sample-specific initial condition and solves the ODE.
117
118newK = K + 1;
119newFluid = 1;
120
121% Compute initial fluid levels
122y0_levels = zeros(size(augPhases, 1), K);
123
124% Delay station: distribute remaining fluid proportionally to delay rates
125delayJobs = (W - sum(aQueue)) * delayRates / sum(delayRates);
126y0_levels(delayIdx, :) = delayJobs;
127
128% Queue station: observed queue lengths per class
129y0_levels(refIdx, :) = aQueue;
130
131% Build state vector from fluid levels
132totalPhases = sum(augPhases(:));
133y0 = zeros(1, totalPhases);
134M = size(augPhases, 1);
135for i = 1:M
136 for k = 1:K
137 if augPhases(i, k) > 0
138 y0(q_indices(i, k)) = y0_levels(i, k);
139 end
140 end
141end
142
143% Move fluid from taggedClass to Tagged at refNode
144y0(q_indices(refIdx, taggedClass)) = y0(q_indices(refIdx, taggedClass)) - newFluid;
145y0(q_indices(refIdx, newK)) = newFluid;
146
147% Solve ODE from 0 to Rsampled
148refTagIdx = q_indices(refIdx, newK);
149opt = odeset('AbsTol', 1e-8, 'RelTol', 1e-5, 'NonNegative', 1:length(y0), ...
150 'Events', @(t,y) ode_events(t, y, refTagIdx));
151[t, yt] = ode15s(ode_h, [0 Rsampled], y0, opt);
152
153% Extract likelihood from terminal state derivative
154if Rsampled <= t(end)
155 lastState = yt(end,:);
156 lastRates = ode_h(t(end), lastState');
157 LIKE = -lastRates(refTagIdx) / newFluid;
158else
159 LIKE = 0;
160end
161
162end
163
164
165function [value, isterminal, direction] = ode_events(~, y, idx)
166 value = y(idx);
167 isterminal = 1;
168 direction = 0;
169end