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.
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
14% - mmap: fitted MAMAP[2]
15% - fB: vector of optimal feasible backward moments
16% - fS: vector of optimal feasible
class transition probabilities
18if (size(
map{1},1) ~= 2)
19 error('Underlying MAP must be of second-order.');
22 error('Underlying MAP must be acyclic');
26elseif (
map{2}(1,1) == 0)
29 error('Underlying MAP must be in canonical acyclic form');
32fprintf('Fitting MAMAP(2,2) B+S: form = %d\n', form);
37 error('Fitting MAMAP(2,2) B+S: fitting backward and transition probabilities only supports two
classes');
40% default weights to use in the objective function
41if nargin < 5 || isempty(classWeights)
42 classWeights = ones(k,1);
44if nargin < 6 || isempty(bsWeights)
45 bsWeights = ones(2,1);
56% get parameters of the underlying AMAP(2)
62% set tolerance constants
67% generate required coefficients
69 [G,U,Y] = mamap2m_can1_coefficients(h1,h2,r1,r2);
72 [E,V,Z] = mamap2m_can2_coefficients(h1,h2,r1,r2);
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 ))
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');
90 if form == 1 && abs(h2-h1*r2) < degentol
91 h2 = h1 * r2 + degentol;
93 if form == 2 && abs(h1 - h2 - h1*r1 + h1*r1*r2) < degentol
94 h1 = (h2 + degentol) / (1 - r1 + r1*r2);
96 % Reconstruct MAP with perturbed parameters
98 map{1} = [-1/h1, r1/h1; 0, -1/h2];
99 map{2} = [(1-r1)/h1, 0; r2/h2, (1-r2)/h2];
101 mmap{1} =
map{1}; mmap{2} =
map{2};
102 [G,U,Y] = mamap2m_can1_coefficients(h1,h2,r1,r2);
105 map{1} = [-1/h1, r1/h1; 0, -1/h2];
106 map{2} = [0, (1-r1)/h1; r2/h2, (1-r2)/h2];
108 mmap{1} =
map{1}; mmap{2} =
map{2};
109 [E,V,Z] = mamap2m_can2_coefficients(h1,h2,r1,r2);
113elseif form == 2 && r2 < degentol && abs(1-r1) < degentol
115 % DEGENERATE PHASE_TYPE
116 fprintf(
'Fitting MAMAP(2,2) B+S: detected degenerate phase-type form\n');
118 % only one degree of freedom: match
class probabilites
123elseif form == 1 && r2 < degentol
125 % CANONICAL PHASE_TYPE
126 fprintf(
'Fitting MAMAP(2,2) B+S: detected canonical phase-type form\n');
128 % convert to phase-type
133 mmap = maph2m_fit_multiclass(
aph, p, B, classWeights);
135 fB = mmap_backward_moment(mmap, 1);
136 fS = mmap_sigma(mmap);
140elseif (form == 1 && abs(1-r1) < degentol) || ...
141 (form == 2 && abs(1-r1) < degentol)
143 % NON-CANONICAL PHASE_TYPE
144 fprintf(
'Fitting MAMAP(2,2) B+S: detected non-canonical phase-type form, converting to canonical form\n');
148 mmap = maph2m_fit_multiclass(
aph, p, B, classWeights);
150 fB = mmap_backward_moment(mmap, 1);
151 fS = mmap_sigma(mmap);
155elseif form == 2 && r2 < degentol
157 % DEGENERATE CASE FOR gamma < 0
158 fprintf(
'Fitting MAMAP(2,2) B+S: detected degenerate MMAP form\n');
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
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);
188 fB1 = solve_quadprog();
189 % compute coefficient
190 [q1,q2,q3] = fit_can2_degen_backward(fB1);
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
198 q1lb = p(1)^2 * (1 - (1-r1)^2);
199 q2ub = p(1)^2 - (1 - p(1))^2;
201 fS11 = q1lb + safetytol;
202 elseif S(1,1) >= q2ub
203 fS11 = q2ub - safetytol;
208 [q1,q2,q3] = fit_can2_degen_transition(fS11);
214 % FULL FORM or "GOOD" poisson process
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')
220 [q1,q2,q3] = fit(B(1), S(1,1));
222 % options used to solve nonlinear problem
225 yalmip_nonlinear_opt = sdpsettings(...
227 'solver','bmibnb',...
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');
251 if isfeasible(q1) && isfeasible(q2) && isfeasible(q3)
252 fprintf('Fitting MAMAP(2,2) B+S: exact fit found\n');
255 [q1,q2,q3] = solve_nonlinear();
258end % end if/then/else for degenerate forms
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');
264% parameters feasible within feastol: restrict to [0,1]
269% compute D11,D12,...,D1k
271 mmap{2+1} = mmap{2} .* [q1 0; q2 q3];
272 mmap{2+2} = mmap{2} .* [1-q1 0; 1-q2 1-q3];
274 mmap{2+1} = mmap{2} .* [0 q1; q2 q3];
275 mmap{2+2} = mmap{2} .* [0 1-q1; 1-q2 1-q3];
278fB = mmap_backward_moment(mmap, 1);
279fS = mmap_sigma(mmap);
281 function feas = isfeasible(q)
282 feas = q >= -feastol && q <= (1+feastol);
285 function qfix = fix(q)
286 qfix = max(min(q,1),0);
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
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);
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
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);
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
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
327 function [q1,q2,q3,obj] = solve_nonlinear()
329 fprintf('Fitting MAMAP(2,2) B+S: running approximate fitting (nonlinear)\n');
331 % for now we support only one of the formulations
332 solve_nonlinear_func = @solve_nonlinear_hybrid;
335 eobj = make_objective(M1, p(1)^2);
336 fprintf('Fitting MAMAP(2,2) B+S: B1 == M1, objective = %e\n', eobj);
338 [lfeas,lobj,lF1,lS11] = solve_nonlinear_func('left');
340 fprintf('Fitting MAMAP(2,2) B+S: B1 < M1, objective = %e\n', lobj);
342 fprintf('Fitting MAMAP(2,2) B+S: B1 < M1 infeasible\n');
345 [rfeas,robj,rF1,rS11] = solve_nonlinear_func('right');
347 fprintf('Fitting MAMAP(2,2) B+S: B1 > M1, objective = %e\n', robj);
349 fprintf('Fitting MAMAP(2,2) B+S: B1 > M1 infeasible\n');
352 if (~lfeas && ~rfeas) || (eobj < lobj && eobj < robj)
357 elseif ~rfeas || lobj < robj
359 [q1,q2,q3] = fit(lF1, lS11);
362 [q1,q2,q3] = fit(rF1, rS11);
367% used for non-degenerate cases: hybrid space
368 function [feas,bobj,bB1,bS11] = solve_nonlinear_hybrid(side)
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];
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];
388 if strcmp(side,'left')
389 hcstr = [hcstr, vB1 <= M1-tol];
391 hcstr = [hcstr, vB1 >= M1+tol];
393 hobj = make_objective(vB1,vS11);
394 hsol = solvesdp(hcstr, hobj, yalmip_nonlinear_opt);
396 fprintf('Fitting MAMAP(2,2) B+S: solver (hybrid space) objective = %f\n',
double(hobj));
401 elseif hsol.problem == 1 || hsol.problem == 12
402 fprintf('Fitting MAMAP(2,2) B+S: program
is infeasible\n');
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);
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;
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);
428 error('Quadratic programming solver failed: %d\n', exit);
430 fit_error = fx + length(x);
431 fprintf('Fitting MAMAP(2,2) B+S: error = %f\n', fit_error);