LINE Solver
MATLAB API documentation
Loading...
Searching...
No Matches
estimator_mle.m
1function [estVal,fObjFun] = estimator_mle(self, nodes)
2node = nodes{1};
3% MLE Maximum likelihood demand estimator
4%
5% Uses a LINE solver (default: SolverAuto) to compute predicted
6% response times and utilizations, replacing the M/GI/1-PS formula.
7% Updates service rates efficiently via sn_set_service.
8%
9% Copyright (c) 2012-2026, Imperial College London
10% All rights reserved.
11% This code is released under the 3-Clause BSD License.
12
13% This estimator at present can handle estimation on a single resource.
14
15%%
16% rescale utilization to be mean number of busy servers
17sn = self.model.getStruct;
18
19if isfinite(node.getNumberOfServers())
20 U = self.getAggrUtil(node);
21 if ~isempty(U)
22 avgU = U.data * node.getNumberOfServers();
23 end
24end
25
26% obtain per class metrics
27for r=1:sn.nclasses
28 avgArvR{r} = self.getArvR(node, self.model.classes{r});
29 if isempty(avgArvR{r})
30 error('Arrival rate data for node %d in class %d is missing.', self.model.getNodeIndex(node), r);
31 else
32 avgArvR{r} = avgArvR{r}.data;
33 end
34 avgRespT{r} = self.getRespT(node, self.model.classes{r});
35 if isempty(avgRespT{r})
36 error('Response time data for node %d in class %d is missing.', self.model.getNodeIndex(node), r);
37 else
38 avgRespT{r} = avgRespT{r}.data;
39 end
40end
41
42try
43 avgA = cell2mat(avgArvR);
44 avgR = cell2mat(avgRespT);
45catch me
46 switch me.identifier
47 case 'MATLAB:catenate:dimensionMismatch'
48 error('Sampled metrics have different number of samples, use interpolate() before starting this estimation algorithm.');
49 end
50end
51
52% Get solver class from options (default: @SolverAuto)
53if isfield(self.options, 'solver') && ~isempty(self.options.solver)
54 solverType = self.options.solver;
55else
56 solverType = @SolverAuto;
57end
58
59[estVal, fObjFun] = mle_data(avgU, avgR, avgA, node.getNumberOfServers(), self.options.iter_max, self.model, node, solverType);
60estVal = estVal(:)';
61end
62
63% MLE procedure using LINE solver for predicted measurements
64function [demEst,fObjFun] = mle_data(cpuUtil, rAvgTimes, avgArvR, numServers, ITERMAX, model, node, solverType)
65a = isnan(cpuUtil);
66if sum(a) > 0
67 disp('NaN values found for CPU Utilization. Removing NaN values.');
68 cpuUtil = cpuUtil(a == 0);
69 rAvgTimes = rAvgTimes(a == 0,:);
70 avgArvR = avgArvR(a == 0,:);
71end
72
73a = sum(avgArvR,2) == 0;
74if sum(a) > 0
75 disp('Removing sampling intervals with zero throughput for all request types.');
76 cpuUtil = cpuUtil(a == 0);
77 rAvgTimes = rAvgTimes(a == 0,:);
78 avgArvR = avgArvR(a == 0,:);
79end
80
81%% number of classes
82R = size(rAvgTimes,2);
83
84%% Initialize solver: get sn struct and solver options once
85sn = model.getStruct();
86stIdx = node.stationIndex;
87
88solver = solverType(model);
89solverOpts = solver.getOptions();
90solverAnalyzer = getSolverAnalyzer(solver, solverOpts);
91
92%% initial point
93x0 = rand(1,R).*max(rAvgTimes);
94
95%% options
96options = optimset();
97options.Display = 'off';
98options.LargeScale = 'off';
99options.MaxIter = ITERMAX;
100options.MaxFunEvals = 1e10;
101options.MaxSQPIter = 5000;
102options.TolCon = 1e-8;
103options.Algorithm = 'interior-point';
104
105XLB = x0*0 + options.TolCon;
106XUB = max(rAvgTimes);
107
108%% optimization program
109N = size(cpuUtil,1);
110w = avgArvR./(sum(avgArvR,2)*ones(1,R));
111[demEst, fObjFun]=fmincon(@objfun,x0,[],[],[],[],XLB,XUB,[],options);
112
113 function f = objfun(x)
114 % Update service rates via sn_set_service
115 for c = 1:R
116 sn = sn_set_service_coc(sn, stIdx, c, 1/x(c));
117 end
118
119 % Solve model to get predicted response times and utilization
120 [~, U_pred, R_pred] = solverAnalyzer(sn);
121
122 % Predicted response times and utilization at the target station
123 predR = R_pred(stIdx, 1:R);
124 predU = sum(U_pred(stIdx, 1:R));
125
126 % Compute objective: weighted response time error + utilization error
127 deltaj = repmat(predR, N, 1) - rAvgTimes;
128 epsi = predU * ones(N, 1) - cpuUtil;
129 f = 0;
130 for i = 1:N
131 f = f + w(i,:) .* deltaj(i,:).^2;
132 end
133 f = sum(f(:));
134 for i = 1:N
135 f = f + epsi(i).^2;
136 end
137 end
138
139end
140
141function solverAnalyzer = getSolverAnalyzer(solver, solverOpts)
142% Return a function handle that takes sn and returns [Q,U,R,T].
143% Selects the appropriate low-level analyzer based on solver type,
144% calling the solver's analyzer function directly to avoid OOP overhead.
145 if isa(solver, 'SolverMVA')
146 solverAnalyzer = @(sn_arg) solver_mva_analyzer(sn_arg, solverOpts);
147 elseif isa(solver, 'SolverAUTO') || isa(solver, 'SolverAuto')
148 mvaOpts = SolverMVA.defaultOptions;
149 solverAnalyzer = @(sn_arg) solver_mva_analyzer(sn_arg, mvaOpts);
150 elseif isa(solver, 'SolverNC')
151 solverAnalyzer = @(sn_arg) solver_nc_analyzer(sn_arg, solverOpts);
152 elseif isa(solver, 'SolverCTMC')
153 solverAnalyzer = @(sn_arg) solver_ctmc_analyzer(sn_arg, solverOpts);
154 elseif isa(solver, 'SolverFluid')
155 solverAnalyzer = @(sn_arg) solver_fluid_analyzer(sn_arg, solverOpts);
156 elseif isa(solver, 'SolverMAM')
157 solverAnalyzer = @(sn_arg) solver_mam_analyzer(sn_arg, solverOpts);
158 else
159 % Fallback: wrap via the solver object
160 solverAnalyzer = @(sn_arg) solverAnalyzerWrapper(solver, sn_arg);
161 end
162end
163
164function [Q,U,R,T] = solverAnalyzerWrapper(solver, sn)
165% Generic wrapper: update the model's cached sn and re-solve.
166 solver.model.sn = sn;
167 solver.result = [];
168 Q = solver.getAvgQLen();
169 U = solver.getAvgUtil();
170 R = solver.getAvgRespT();
171 T = solver.getAvgTput();
172end
Definition mmt.m:124