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