LINE Solver
MATLAB API documentation
Loading...
Searching...
No Matches
mamap22_fit_bs_multiclass.m
1function [mmap,fB,fS,exact] = mamap22_fit_bs_multiclass(map,p,B,S,classWeights,bsWeights,adjust)
2% Performs approximate fitting of a MMAP given the underlying AMAP(2),
3% the class probabilities (always fitted exactly), the backward moments,
4% and the one-step class transition probabilities.
5% Input
6% - map: second-order AMAP underlying the MAMAP[2]
7% - p: vector of class probabilities
8% - B: vector of backward moments
9% - S: matrix of the class transition probabilities
10% - classWeights: optional vector of weights for each class
11% - bsWeights: optional 2-vector of weights of backward moments and the
12% class transition probabilities
13% Output
14% - mmap: fitted MAMAP[2]
15% - fB: vector of optimal feasible backward moments
16% - fS: vector of optimal feasible class transition probabilities
17
18if (size(map{1},1) ~= 2)
19 error('Underlying MAP must be of second-order.');
20end
21if (map{1}(2,1) ~= 0)
22 error('Underlying MAP must be acyclic');
23end
24if (map{2}(1,2) == 0)
25 form = 1;
26elseif (map{2}(1,1) == 0)
27 form = 2;
28else
29 error('Underlying MAP must be in canonical acyclic form');
30end
31
32fprintf('Fitting MAMAP(2,2) B+S: form = %d\n', form);
33
34% number of classes
35k = length(p);
36if k ~= 2
37 error('Fitting MAMAP(2,2) B+S: fitting backward and transition probabilities only supports two classes');
38end
39
40% default weights to use in the objective function
41if nargin < 5 || isempty(classWeights)
42 classWeights = ones(k,1);
43end
44if nargin < 6 || isempty(bsWeights)
45 bsWeights = ones(2,1);
46end
47if nargin < 7
48 adjust = 1;
49end
50
51% result
52mmap = cell(1,2+k);
53mmap{1} = map{1};
54mmap{2} = map{2};
55
56% get parameters of the underlying AMAP(2)
57h1 = -1/map{1}(1,1);
58h2 = -1/map{1}(2,2);
59r1 = map{1}(1,2) * h1;
60r2 = map{2}(2,2) * h2;
61
62% set tolerance constants
63degentol = 1e-6;
64feastol = 1e-4;
65denumtol = 1e-12;
66
67% generate required coefficients
68if form == 1
69 [G,U,Y] = mamap2m_can1_coefficients(h1,h2,r1,r2);
70 fit = @fit_can1;
71elseif form == 2
72 [E,V,Z] = mamap2m_can2_coefficients(h1,h2,r1,r2);
73 fit = @fit_can2;
74end
75
76exact = 0;
77
78if (form == 1 && (r1 < degentol || r2 > 1-degentol || abs(h2-h1*r2) < degentol )) || ...
79 (form == 2 && (r2 > 1-degentol || abs(h1 - h2 - h1*r1 + h1*r1*r2) < degentol ))
80
81 % Transform into a valid second-order Poisson process by perturbing
82 % degenerate parameters to maintain 2-state structure
83 fprintf('Fitting MAMAP(2,2) B+S: perturbing degenerate Poisson to second-order\n');
84 if r1 < degentol
85 r1 = degentol;
86 end
87 if r2 > 1-degentol
88 r2 = 1 - degentol;
89 end
90 if form == 1 && abs(h2-h1*r2) < degentol
91 h2 = h1 * r2 + degentol;
92 end
93 if form == 2 && abs(h1 - h2 - h1*r1 + h1*r1*r2) < degentol
94 h1 = (h2 + degentol) / (1 - r1 + r1*r2);
95 end
96 % Reconstruct MAP with perturbed parameters
97 if form == 1
98 map{1} = [-1/h1, r1/h1; 0, -1/h2];
99 map{2} = [(1-r1)/h1, 0; r2/h2, (1-r2)/h2];
100 map = map_normalize(map);
101 mmap{1} = map{1}; mmap{2} = map{2};
102 [G,U,Y] = mamap2m_can1_coefficients(h1,h2,r1,r2);
103 fit = @fit_can1;
104 else
105 map{1} = [-1/h1, r1/h1; 0, -1/h2];
106 map{2} = [0, (1-r1)/h1; r2/h2, (1-r2)/h2];
107 map = map_normalize(map);
108 mmap{1} = map{1}; mmap{2} = map{2};
109 [E,V,Z] = mamap2m_can2_coefficients(h1,h2,r1,r2);
110 fit = @fit_can2;
111 end
112
113elseif form == 2 && r2 < degentol && abs(1-r1) < degentol
114
115 % DEGENERATE PHASE_TYPE
116 fprintf('Fitting MAMAP(2,2) B+S: detected degenerate phase-type form\n');
117
118 % only one degree of freedom: match class probabilites
119 q1 = p(1);
120 q2 = p(1);
121 q3 = p(1);
122
123elseif form == 1 && r2 < degentol
124
125 % CANONICAL PHASE_TYPE
126 fprintf('Fitting MAMAP(2,2) B+S: detected canonical phase-type form\n');
127
128 % convert to phase-type
129 aph = map;
130 aph{2}(2,2) = 0;
131 aph = map_normalize(aph);
132
133 mmap = maph2m_fit_multiclass(aph, p, B, classWeights);
134
135 fB = mmap_backward_moment(mmap, 1);
136 fS = mmap_sigma(mmap);
137
138 return;
139
140elseif (form == 1 && abs(1-r1) < degentol) || ...
141 (form == 2 && abs(1-r1) < degentol)
142
143 % NON-CANONICAL PHASE_TYPE
144 fprintf('Fitting MAMAP(2,2) B+S: detected non-canonical phase-type form, converting to canonical form\n');
145
146 aph = aph2_fit_map(map);
147
148 mmap = maph2m_fit_multiclass(aph, p, B, classWeights);
149
150 fB = mmap_backward_moment(mmap, 1);
151 fS = mmap_sigma(mmap);
152
153 return;
154
155elseif form == 2 && r2 < degentol
156
157 % DEGENERATE CASE FOR gamma < 0
158 fprintf('Fitting MAMAP(2,2) B+S: detected degenerate MMAP form\n');
159
160 if bsWeights(1) > bsWeights(2)
161 fprintf('Fitting MAMAP(2,2) B+S: fitting B\n');
162 [q1,q2,q3] = fit_can2_degen_backward(B(1));
163 if ~(isfeasible(q1) && isfeasible(q2) && isfeasible(q3))
164 % four inequalities, one variable
165 A = zeros(4,1);
166 b = zeros(4,1);
167 % coefficients
168 q1_B = - p(1) * (r1-2)/((r1-1)*(h2-h1+h1*r1));
169 q1_0 = + p(1) * (r1-2)*(h2+h1*r1)/((r1-1)*(h2-h1+h1*r1));
170 q2_B = - p(1) * (r1-2)/(h2-h1+h1*r1);
171 q2_0 = + p(1) * (r1-2)*h1/(h2-h1+h1*r1);
172 % q1 >= 0
173 A(1,1) = -q1_B;
174 b(1) = q1_0;
175 % q1 <= 1
176 A(2,1) = +q1_B;
177 b(2) = 1 - q1_0;
178 % q2 >= 0
179 A(3,1) = -q2_B;
180 b(3) = q2_0;
181 % q2 <= 1
182 A(4,1) = +q2_B;
183 b(4) = 1 - q2_0;
184 % objective function
185 H = 2 / B(1)^2;
186 h = -2 / B(1);
187 % solve
188 fB1 = solve_quadprog();
189 % compute coefficient
190 [q1,q2,q3] = fit_can2_degen_backward(fB1);
191 end
192 else
193 fprintf('Fitting MAMAP(2,2) B+S: fitting S\n');
194 [q1,q2,q3] = fit_can2_degen_transition(S(1,1));
195 if ~(isfeasible(q1) && isfeasible(q2) && isfeasible(q3))
196 % bound constraints on S11
197 safetytol = 1e-10;
198 q1lb = p(1)^2 * (1 - (1-r1)^2);
199 q2ub = p(1)^2 - (1 - p(1))^2;
200 if S(1,1) <= q1lb
201 fS11 = q1lb + safetytol;
202 elseif S(1,1) >= q2ub
203 fS11 = q2ub - safetytol;
204 else
205 fS11 = S(1,1);
206 end
207 % compute parameters
208 [q1,q2,q3] = fit_can2_degen_transition(fS11);
209 end
210 end
211
212else
213
214 % FULL FORM or "GOOD" poisson process
215
216 if (form == 1 && abs(h1 - h2 + h2*r1) < degentol) || (form == 2 && abs(h1 - h2 + h2*r1) < degentol)
217 fprintf('Fitting MAMAP(2,2) B+S: detected fittable Poisson process\n')
218 end
219
220 [q1,q2,q3] = fit(B(1), S(1,1));
221
222 % options used to solve nonlinear problem
223 tol = 1e-6;
224
225 yalmip_nonlinear_opt = sdpsettings(...
226 'verbose',2,...
227 'solver','bmibnb',...
228 'debug',0,...
229 'showprogress',0,...
230 'usex0',1,...
231 'bmibnb.relgaptol',1e-3,...
232 'bmibnb.absgaptol',1e-6,...
233 'bmibnb.maxiter',1000,...
234 'bmibnb.lowrank', 1,...
235 'bmibnb.lpreduce',1,... % without this, crappy lower bounds for some problems
236 'bmibnb.pdtol',-1e-8,... % x >= if x > -pdtol
237 'bmibnb.eqtol',+1e-10,... % x == 0 if abs(x) < +eqtol
238 'bmibnb.roottight',1,...
239 'bmibnb.uppersolver','fmincon-standard',...
240 'fmincon.Algorithm','sqp',...
241 'fmincon.TolCon',1e-6,...
242 'fmincon.TolX',1e-6,...
243 'fmincon.GradObj','on',...
244 'fmincon.GradConstr','on',...
245 'fmincon.Hessian','off',...
246 'fmincon.LargeScale','off');
247
248 % constants
249 M1 = map_mean(map);
250
251 if isfeasible(q1) && isfeasible(q2) && isfeasible(q3)
252 fprintf('Fitting MAMAP(2,2) B+S: exact fit found\n');
253 exact = 1;
254 elseif adjust
255 [q1,q2,q3] = solve_nonlinear();
256 end
257
258end % end if/then/else for degenerate forms
259
260% check parameter feasibility
261if adjust && ~(isfeasible(q1) && isfeasible(q2) && isfeasible(q3))
262 error('Fitting MAMAP(2,2) B+S: Feasibility could not be restored');
263end
264% parameters feasible within feastol: restrict to [0,1]
265q1 = fix(q1);
266q2 = fix(q2);
267q3 = fix(q3);
268
269% compute D11,D12,...,D1k
270if form == 1
271 mmap{2+1} = mmap{2} .* [q1 0; q2 q3];
272 mmap{2+2} = mmap{2} .* [1-q1 0; 1-q2 1-q3];
273else
274 mmap{2+1} = mmap{2} .* [0 q1; q2 q3];
275 mmap{2+2} = mmap{2} .* [0 1-q1; 1-q2 1-q3];
276end
277
278fB = mmap_backward_moment(mmap, 1);
279fS = mmap_sigma(mmap);
280
281 function feas = isfeasible(q)
282 feas = q >= -feastol && q <= (1+feastol);
283 end
284
285 function qfix = fix(q)
286 qfix = max(min(q,1),0);
287 end
288
289 function [q1,q2,q3] = fit_can1(vB1,vS11)
290 denum = U(11) * vB1 * p(1) + U(12) * p(1);
291 if abs(denum) < denumtol
292 q1 = p(1);
293 q2 = p(1);
294 q3 = p(1);
295 else
296 q2 = (U(7) * vB1^2 * p(1)^2 + U(8) * vB1 * p(1)^2 + U(9) * vS11 + U(10) * p(1)^2)/denum;
297 q1 = -(G(12)*p(1) - vB1*G(3)*p(1) + (G(3)*G(11) - G(2)*G(12))*q2)/Y(3);
298 q3 = +(G(10)*p(1) - vB1*G(1)*p(1) + (G(1)*G(11) - G(2)*G(10))*q2)/Y(3);
299 end
300 end
301
302 function [q1,q2,q3] = fit_can2(vB1,vS11)
303 denum = (V(11) * vB1 * p(1) + V(12) * p(1));
304 if abs(denum) < denumtol
305 q1 = p(1);
306 q2 = p(1);
307 q3 = p(1);
308 else
309 q3 = (V(7) * vB1^2 * p(1)^2 + V(8) * vB1 * p(1)^2 + V(9) * p(1)^2 + V(10) * vS11)/denum;
310 q1 = +(E(10)*p(1) - vB1*E(2)*p(1) + (E(2)*E(11) - E(3)*E(10))*q3)/Z(3);
311 q2 = -(E(9)*p(1) - vB1*E(1)*p(1) + (E(1)*E(11) - E(3)*E(9))*q3)/Z(3);
312 end
313 end
314
315 function [q1,q2,q3] = fit_can2_degen_backward(vB1)
316 q1 = (p(1)*(r1 - 2)*(h2 - vB1 + h1*r1))/((r1 - 1)*(h2 - h1 + h1*r1));
317 q2 = -(p(1)*(vB1 - h1)*(r1 - 2))/(h2 - h1 + h1*r1);
318 q3 = p(1); % meangingless if really degenerate
319 end
320
321 function [q1,q2,q3] = fit_can2_degen_transition(vS11)
322 q1 = p(1) + (p(1)^2 - vS11)^(1/2)/(r1 - 1);
323 q2 = p(1) + (p(1)^2 - vS11)^(1/2);
324 q3 = p(1); % meangingless if really degenerate
325 end
326
327 function [q1,q2,q3,obj] = solve_nonlinear()
328
329 fprintf('Fitting MAMAP(2,2) B+S: running approximate fitting (nonlinear)\n');
330
331 % for now we support only one of the formulations
332 solve_nonlinear_func = @solve_nonlinear_hybrid;
333
334 % trivial solution
335 eobj = make_objective(M1, p(1)^2);
336 fprintf('Fitting MAMAP(2,2) B+S: B1 == M1, objective = %e\n', eobj);
337 % left solution
338 [lfeas,lobj,lF1,lS11] = solve_nonlinear_func('left');
339 if lfeas
340 fprintf('Fitting MAMAP(2,2) B+S: B1 < M1, objective = %e\n', lobj);
341 else
342 fprintf('Fitting MAMAP(2,2) B+S: B1 < M1 infeasible\n');
343 end
344 % right solution
345 [rfeas,robj,rF1,rS11] = solve_nonlinear_func('right');
346 if rfeas
347 fprintf('Fitting MAMAP(2,2) B+S: B1 > M1, objective = %e\n', robj);
348 else
349 fprintf('Fitting MAMAP(2,2) B+S: B1 > M1 infeasible\n');
350 end
351 % pick best solution
352 if (~lfeas && ~rfeas) || (eobj < lobj && eobj < robj)
353 obj = eobj;
354 q1 = p(1);
355 q2 = p(1);
356 q3 = p(1);
357 elseif ~rfeas || lobj < robj
358 obj = lobj;
359 [q1,q2,q3] = fit(lF1, lS11);
360 else
361 obj = robj;
362 [q1,q2,q3] = fit(rF1, rS11);
363 end
364
365 end
366
367% used for non-degenerate cases: hybrid space
368 function [feas,bobj,bB1,bS11] = solve_nonlinear_hybrid(side)
369 vB1 = sdpvar(1,1);
370 vS11 = sdpvar(1,1);
371 if form == 1
372 vq2 = sdpvar(1,1);
373 scale = U(11);
374 q1exp = -(G(12)*p(1) - vB1*G(3)*p(1) + vq2*(G(11)*G(3) - G(12)*G(2)))/Y(3);
375 q2num = U(7)*vB1^2*p(1)^2 + U(8)*vB1*p(1)^2 + U(9)*vS11 + U(10)*p(1)^2;
376 q2den = p(1)*(U(11)*vB1 + U(12));
377 q3exp = +(G(10)*p(1) - vB1*G(1)*p(1) + vq2*(G(11)*G(1) - G(10)*G(2)))/Y(3);
378 hcstr = [0 <= q1exp <= 1, 0 <= vq2 <= 1, vq2*q2den/scale == q2num/scale, 0 <= q3exp <= 1, 0 <= vS11 <= 1, vB1 >= 0];
379 else
380 vq3 = sdpvar(1,1);
381 scale = V(11);
382 q1exp = +(E(10)*p(1) - vB1*E(2)*p(1) + vq3*(E(11)*E(2) - E(10)*E(3)))/Z(3);
383 q2exp = -(E(9)*p(1) - vB1*E(1)*p(1) + vq3*(E(11)*E(1) - E(3)*E(9)))/Z(3);
384 q3num = V(7)*vB1^2*p(1)^2 + V(8)*vB1*p(1)^2 + V(9)*p(1)^2 + V(10)*vS11;
385 q3den = p(1)*(V(11)*vB1 + V(12));
386 hcstr = [0 <= q1exp <= 1, 0 <= q2exp <= 1, vq3*q3den/scale == q3num/scale, 0 <= vq3 <= 1, 0 <= vS11 <= 1, vB1 >= 0];
387 end
388 if strcmp(side,'left')
389 hcstr = [hcstr, vB1 <= M1-tol];
390 else
391 hcstr = [hcstr, vB1 >= M1+tol];
392 end
393 hobj = make_objective(vB1,vS11);
394 hsol = solvesdp(hcstr, hobj, yalmip_nonlinear_opt);
395 if hsol.problem == 0
396 fprintf('Fitting MAMAP(2,2) B+S: solver (hybrid space) objective = %f\n', double(hobj));
397 feas = 1;
398 bobj = double(hobj);
399 bB1 = double(vB1);
400 bS11 = double(vS11);
401 elseif hsol.problem == 1 || hsol.problem == 12
402 fprintf('Fitting MAMAP(2,2) B+S: program is infeasible\n');
403 feas = 0;
404 bobj = nan;
405 bB1 = nan;
406 bS11 = nan;
407 else
408 fname = tempname;
409 save(fname,'map','p','B','S');
410 error('Fitting MAMAP(2,2) B+S: solver (hybrid space) error: %s, input saved to %s\n', hsol.info, fname);
411 end
412 end
413
414 function obj = make_objective(vB1, vS11)
415 obj = classWeights(1) * bsWeights(1) * (vB1/B(1) - 1)^2 + ...
416 classWeights(1) * bsWeights(2) * (vS11/S(1,1) - 1)^2;
417 end
418
419 function x = solve_quadprog()
420 fprintf('Fitting MAMAP(2,2) B+S: running quadratic programming solver...\n');
421 options = optimset('Algorithm','interior-point-convex','Display','none');
422 %[x,fx,xflag] = quadprog(H, h, A, b, [], [], [], [], [], options);
423 lb = 1e-6*ones( size(A,2),1);
424 ub = 1e6*ones( size(A,2),1);
425 [x,fx,xflag]=QP(H, h, A, b, Aeq, beq, lb, ub, options);
426
427 if xflag ~= 1
428 error('Quadratic programming solver failed: %d\n', exit);
429 end
430 fit_error = fx + length(x);
431 fprintf('Fitting MAMAP(2,2) B+S: error = %f\n', fit_error);
432 end
433
434end