LINE Solver
MATLAB API documentation
Loading...
Searching...
No Matches
mamap22_fit_fs_multiclass.m
1function [mmap,fF,fS,exact] = mamap22_fit_fs_multiclass(map,p,F,S,classWeights,fsWeights,adjust)
2% Performs approximate fitting of a MMAP given the underlying AMAP(2),
3% the class probabilities (always fitted exactly), the forward 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% - F: vector of forward moments
9% - S: matrix of the class transition probabilities
10% - classWeights: optional vector of weights for each class
11% - fsWeights: optional 2-vector of weights of forward moments and the
12% class transition probabilities
13% Output
14% - mmap: fitted MAMAP[2]
15% - fF: vector of optimal feasible forward 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) F+S: form = %d\n', form);
33
34% number of classes
35k = length(p);
36if k ~= 2
37 error('Fitting MAMAP(2,2) F+S: only two classes supported');
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(fsWeights)
45 fsWeights = 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-3;
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(h1 - h2 + h2*r1) < degentol )) || ...
79 (form == 2 && (r2 > 1-degentol || abs(h1 - h2 + h2*r1) < 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) F+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 abs(h1 - h2 + h2*r1) < degentol
91 h1 = h2 * (1 - r1) + degentol;
92 end
93 % Reconstruct MAP with perturbed parameters
94 if form == 1
95 map{1} = [-1/h1, r1/h1; 0, -1/h2];
96 map{2} = [(1-r1)/h1, 0; r2/h2, (1-r2)/h2];
97 map = map_normalize(map);
98 mmap{1} = map{1}; mmap{2} = map{2};
99 [G,U,Y] = mamap2m_can1_coefficients(h1,h2,r1,r2);
100 fit = @fit_can1;
101 else
102 map{1} = [-1/h1, r1/h1; 0, -1/h2];
103 map{2} = [0, (1-r1)/h1; r2/h2, (1-r2)/h2];
104 map = map_normalize(map);
105 mmap{1} = map{1}; mmap{2} = map{2};
106 [E,V,Z] = mamap2m_can2_coefficients(h1,h2,r1,r2);
107 fit = @fit_can2;
108 end
109
110elseif form == 2 && r2 < degentol && abs(1-r1) < degentol
111
112 % DEGENERATE PHASE_TYPE
113 fprintf('Fitting MAMAP(2,2) F+S: detected degenerate phase-type form\n');
114
115 % only one degree of freedom: match class probabilites
116 q1 = p(1);
117 q2 = p(1);
118 q3 = p(1);
119
120elseif form == 1 && r2 < degentol
121
122 % CANONICAL PHASE_TYPE
123 fprintf('Fitting MAMAP(2,2) F+S: detected canonical phase-type form\n');
124
125 % convert to phase-type
126 aph = map;
127 aph{2}(2,2) = 0;
128 aph = map_normalize(aph);
129
130 % detect hypoexponential (SCV <= 1) and convert to non-canonical form
131 scv = map_scv(aph);
132 if scv < 1.0 + degentol
133 fprintf('Fitting MAMAP(2,2) F+S: hypoexponential detected (SCV=%.4f), converting to non-canonical form\n', scv);
134 aph = aph2_fit_map(map);
135 end
136
137 % the forward moments are always equal to the ordinary moments
138 % since the backward moments are not provided as arguments,
139 % we set the backward moments to the ordinary moments as well
140 B = zeros(2,1);
141 B(1) = map_mean(aph);
142 B(2) = map_mean(aph);
143 warning('Fitting MAMAP(2,2) F+S: setting backward moments to ordinary moments, you should try to fit B+S');
144
145 mmap = maph2m_fit_multiclass(aph, p, B, classWeights);
146
147 fF = mmap_forward_moment(mmap, 1);
148 fS = mmap_sigma(mmap);
149
150 return;
151
152elseif (form == 1 && abs(1-r1) < degentol) || ...
153 (form == 2 && abs(1-r1) < degentol)
154
155 % NON-CANONICAL PHASE_TYPE
156 fprintf('Fitting MAMAP(2,2) F+S: detected non-canonical phase-type form\n');
157
158 % two degrees of freedom: fit p and F, not S
159 [q1,q2,q3] = fit_can1_degen(F(1));
160
161 % if unfeasible, perform approximate fitting
162 if ~(isfeasible(q1) && isfeasible(q2) && isfeasible(q3))
163 % four inequalities, one variable
164 A = zeros(4,1);
165 b = zeros(4,1);
166 % coefficients
167 q2_F = - p(1) / (h1 * (r2-1));
168 q2_0 = + p(1) * h2 / (h1 * (r2-1));
169 q3_F = - p(1) / (h1 * r2);
170 q3_0 = + p(1) * (h1 + h2) / (h1 * r2);
171 % q2 >= 0
172 A(1,1) = -q2_F;
173 b(1) = q2_0;
174 % q2 <= 1
175 A(2,1) = +q2_F;
176 b(2) = 1 - q2_0;
177 % q3 >= 0
178 A(3,1) = -q3_F;
179 b(3) = q3_0;
180 % q3 <= 1
181 A(4,1) = +q3_F;
182 b(4) = 1 - q3_0;
183 % objective function
184 H = 2 / F(1)^2;
185 h = -2 / F(1);
186 % solve
187 fF1 = solve_quadprog();
188 % compute coefficient
189 [q1, q2, q3] = fit_can1_degen(fF1);
190 end
191
192elseif form == 2 && r2 < degentol
193
194 % DEGENERATE CASE FOR gamma < 0
195 fprintf('Fitting MAMAP(2,2) F+S: detected degenerate MMAP form\n');
196
197 if fsWeights(1) > fsWeights(2)
198 fprintf('Fitting MAMAP(2,2) F+S: fitting F\n');
199 [q1,q2,q3] = fit_can2_degen_forward(F(1));
200 if ~(isfeasible(q1) && isfeasible(q2) && isfeasible(q3))
201 % four inequalities, one variable
202 A = zeros(4,1);
203 b = zeros(4,1);
204 % coefficients
205 q1_F = - p(1) * (r1 - 2) / ((r1-1)*(h1-h2+h2*r1));
206 q1_0 = + p(1) * (r1 - 2)*(h1 + h2*r1) / ((r1-1)*(h1-h2+h2*r1));
207 q2_F = - p(1) * (r1 - 2) / ((h1-h2+h2*r1));
208 q2_0 = + p(1) * (r1 - 2)*h2 / ((h1-h2+h2*r1));
209 % q1 >= 0
210 A(1,1) = -q1_F;
211 b(1) = q1_0;
212 % q1 <= 1
213 A(2,1) = +q1_F;
214 b(2) = 1 - q1_0;
215 % q2 >= 0
216 A(3,1) = -q2_F;
217 b(3) = q2_0;
218 % q2 <= 1
219 A(4,1) = +q2_F;
220 b(4) = 1 - q2_0;
221 % objective function
222 H = 2 / F(1)^2;
223 h = -2 / F(1);
224 % solve
225 fF1 = solve_quadprog();
226 % compute coefficient
227 [q1,q2,q3] = fit_can2_degen_forward(fF1);
228 end
229 else
230 fprintf('Fitting MAMAP(2,2) F+S: fitting S\n');
231 [q1,q2,q3] = fit_can2_degen_transition(S(1,1));
232 if ~(isfeasible(q1) && isfeasible(q2) && isfeasible(q3))
233 % nonlinear constraints: use yalmip
234 varS11 = sdpvar(1,1);
235 options = sdpsettings('verbose',0);
236 boundS11 = [varS11 >= 0, varS11 <= p(1)^2];
237 q1lb = varS11 >= p(1)^2 * (1 - (1-r1)^2);
238 q2ub = varS11 >= p(1)^2 - (1 - p(1))^2;
239 constraints = [boundS11, q1lb, q2ub];
240 obj = (varS11 - S(1,1))^2;
241 sol = solvesdp(constraints, obj, options);
242 if sol.problem ~= 0
243 error('Fitting MAMAP(2,2) F+S: YALMIP = %s\n', sol.info);
244 else
245 fprintf('Fitting MAMAP(2,2) F+S: YALMIP objective = %f\n', double(obj));
246 end
247 % compute coefficient
248 [q1,q2,q3] = fit_can2_degen_transition(double(varS11));
249 end
250 end
251
252else
253
254 % FULL FORM or "GOOD" poisson process
255
256 if (form == 1 && abs(h2-h1*r2) < degentol) || (form == 2 && abs(h1 - h2 - h1*r1 + h1*r1*r2) < degentol)
257 fprintf('Fitting MAMAP(2,2) F+S: detected fittable Poisson process\n')
258 end
259
260 [q1,q2,q3] = fit(F(1), S(1,1));
261
262 % options used to solve the nonlinear problem
263 use_linprog_prepass = 1;
264 tol = 1e-6;
265 optim_space = 'hybrid';
266 %optim_space = 'hybrid-z';
267 %optim_space = 'param';
268 %optim_space = 'char';
269
270 yalmip_nonlinear_opt = sdpsettings(...
271 'verbose',2,...
272 'solver','bmibnb',...
273 'debug',0,...
274 'showprogress',0,...
275 'usex0',1,...
276 'bmibnb.relgaptol',1e-3,...
277 'bmibnb.absgaptol',1e-6,...
278 'bmibnb.maxiter',1000,...
279 'bmibnb.lowrank', 1,...
280 'bmibnb.lpreduce',1,... % without this, crappy lower bounds for some problems
281 'bmibnb.pdtol',-1e-8,... % x >= if x > -pdtol
282 'bmibnb.eqtol',+1e-10,... % x == 0 if abs(x) < +eqtol
283 'bmibnb.roottight',1,...
284 'bmibnb.uppersolver','fmincon-standard',...
285 'fmincon.Algorithm','sqp',...
286 'fmincon.TolCon',1e-6,...
287 'fmincon.TolX',1e-6,...
288 'fmincon.GradObj','on',...
289 'fmincon.GradConstr','on',...
290 'fmincon.Hessian','off',...
291 'fmincon.LargeScale','off');
292
293 % constants
294 M1 = map_mean(map);
295
296 if isfeasible(q1) && isfeasible(q2) && isfeasible(q3)
297 fprintf('Fitting MAMAP(2,2) F+S: exact fit found\n');
298 exact = 1;
299 elseif adjust
300 [q1,q2,q3] = solve_nonlinear(optim_space);
301 end
302
303end % end if/then/else for degenerate forms
304
305% check parameter feasibility
306if adjust && ~(isfeasible(q1) && isfeasible(q2) && isfeasible(q3))
307 error('Fitting MAMAP(2,2) F+S: Feasibility could not be restored: q1 = %e, q2 = %e, q3 = %e', q1, q2, q3);
308end
309% parameters feasible within feastol: restrict to [0,1]
310q1 = fix(q1);
311q2 = fix(q2);
312q3 = fix(q3);
313
314% compute D11,D12,...,D1k
315if form == 1
316 mmap{2+1} = mmap{2} .* [q1 0; q2 q3];
317 mmap{2+2} = mmap{2} .* [1-q1 0; 1-q2 1-q3];
318else
319 mmap{2+1} = mmap{2} .* [0 q1; q2 q3];
320 mmap{2+2} = mmap{2} .* [0 1-q1; 1-q2 1-q3];
321end
322
323fF = mmap_forward_moment(mmap, 1);
324fS = mmap_sigma(mmap);
325
326 function feas = isfeasible(q)
327 feas = q >= -feastol && q <= (1+feastol);
328 end
329
330 function qfix = fix(q)
331 qfix = max(min(q,1),0);
332 end
333
334 function [q1,q2,q3] = fit_can1(vF1,vS11)
335 denum = p(1) * (U(5) * vF1 + U(6));
336 if abs(denum) < denumtol
337 q1 = p(1);
338 q2 = p(1);
339 q3 = p(1);
340 else
341 q2 = (U(1) * vF1^2 * p(1)^2 + U(2) * vF1 * p(1)^2 + U(3) * vS11 + U(4) * p(1)^2)/denum;
342 q1 = -(G(15)*p(1) - vF1*G(3)*p(1) + (G(3)*G(14) - G(2)*G(15)) * q2)/Y(2);
343 q3 = +(G(13)*p(1) - vF1*G(1)*p(1) + (G(1)*G(14) - G(2)*G(13)) * q2)/Y(2);
344 end
345 end
346
347 function [q1,q2,q3] = fit_can1_degen(vF1)
348 q1 = p(1); % meangingless if really degenerate
349 q2 = p(1) * (h2 - vF1) / (h1 * (r2-1));
350 q3 = p(1) * (h1 + h2 - vF1) / (h1 * r2);
351 end
352
353 function [q1,q2,q3] = fit_can2_degen_forward(vF1)
354 q1 = + p(1) * (r1 - 2)*(h1 + h2*r1 - vF1)/((r1-1)*(h1-h2+h2*r1));
355 q2 = - p(1) * (vF1 - h2)*(r1 - 2)/((h1-h2+h2*r1));
356 q3 = p(1); % meangingless if really degenerate
357 end
358
359 function [q1,q2,q3] = fit_can2_degen_transition(vS11)
360 q1 = p(1) + (p(1)^2 - vS11)^(1/2)/(r1 - 1);
361 q2 = p(1) + (p(1)^2 - vS11)^(1/2);
362 q3 = p(1); % meangingless if really degenerate
363 end
364
365 function [q1,q2,q3] = fit_can2(vF1,vS11)
366 denum = (V(5) * vF1 * p(1) + V(6) * p(1));
367 if abs(denum) < denumtol
368 q1 = p(1);
369 q2 = p(1);
370 q3 = p(1);
371 else
372 q3 = (V(1) * vF1^2 * p(1)^2 + V(2) * vF1 * p(1)^2 + V(3) * p(1)^2 + V(4) * vS11)/denum;
373 q1 = -(E(13)*p(1) - vF1*E(2)*p(1) + (E(2)*E(14) - E(3)*E(13)) * q3)/Z(2);
374 q2 = +(E(12)*p(1) - vF1*E(1)*p(1) + (E(1)*E(14) - E(3)*E(12)) * q3)/Z(2);
375 end
376 end
377
378 function [pexp,pFexp,Sexp] = get_characteristics(q1,q2,q3)
379 if form == 1
380 pexp = G(1)*q1+G(2)*q2+G(3)*q3;
381 pFexp = G(13)*q1+G(14)*q2+G(15)*q3;
382 Sexp = G(4)*q1^2 + G(5)*q1*q2 + G(6)*q1*q3 + G(7)*q2^2 + G(8)*q2*q3 + G(9)*q3^2;
383 else
384 pexp = E(1)*q1+E(2)*q2+E(3)*q3;
385 pFexp = (E(12)*q1+E(13)*q2+E(14)*q3);
386 Sexp = E(4)*q1*q2 + E(5)*q1*q3 + E(6)*q2^2 + E(7)*q2*q3 + E(8)*q3^2;
387 end
388 end
389
390 function opt = get_yalmip_linear_options()
391 % we do not set solver so that YALMIP picks the best
392 opt = sdpsettings('verbose',0);
393 end
394
395 function [q1,q2,q3,obj] = solve_nonlinear(optim_space)
396
397 fprintf('Fitting MAMAP(2,2) F+S: running approximate fitting (nonlinear)\n');
398
399 if strcmp(optim_space, 'param')
400 [q1,q2,q3,obj] = solve_nonlinear_param();
401 else
402 if strcmp(optim_space, 'hybrid')
403 solve_nonlinear_func = @solve_nonlinear_hybrid;
404 elseif strcmp(optim_space, 'hybrid-z')
405 solve_nonlinear_func = @solve_nonlinear_hybrid_z;
406 elseif strcmp(optim_space, 'char')
407 solve_nonlinear_func = @solve_nonlinear_char;
408 else
409 error('Fitting MAMAP(2,2) F+S: invalid value for option "optim_space"');
410 end
411 % trivial solution
412 eobj = make_objective(M1, p(1)^2);
413 fprintf('Fitting MAMAP(2,2) F+S: F1 == M1, objective = %e\n', eobj);
414 % left solution
415 [lfeas,lobj,lF1,lS11] = solve_nonlinear_func('left');
416 if lfeas
417 fprintf('Fitting MAMAP(2,2) F+S: F1 < M1, objective = %e\n', lobj);
418 else
419 fprintf('Fitting MAMAP(2,2) F+S: F1 < M1 infeasible\n');
420 end
421 % right solution
422 [rfeas,robj,rF1,rS11] = solve_nonlinear_func('right');
423 if rfeas
424 fprintf('Fitting MAMAP(2,2) F+S: F1 > M1, objective = %e\n', robj);
425 else
426 fprintf('Fitting MAMAP(2,2) F+S: F1 > M1 infeasible\n');
427 end
428 % pick best solution
429 if (~lfeas && ~rfeas) || (eobj < lobj && eobj < robj)
430 obj = eobj;
431 q1 = p(1);
432 q2 = p(1);
433 q3 = p(1);
434 elseif ~rfeas || lobj < robj
435 obj = lobj;
436 [q1,q2,q3] = fit(lF1, lS11);
437 else
438 obj = robj;
439 [q1,q2,q3] = fit(rF1, rS11);
440 end
441 end
442
443 end
444
445% used for non-degenerate cases: parmeter space
446 function [q1,q2,q3,obj] = solve_nonlinear_param()
447 % find initial feasible solution
448 vq = sdpvar(3,1);
449 z = sdpvar(2,1);
450 % define expressions
451 [pexp,pFexp,Sexp] = get_characteristics(vq(1),vq(2),vq(3));
452 % set constraints
453 cstr_exact_p = pexp == p(1);
454 cstr_tighten_F = -z(1) <= (pFexp - p(1)*F(1))/(p(1)*F(1)) <= z(1);
455 cstr_tighten_S = -z(2) <= (Sexp - S(1,1))/S(1,1) <= z(2);
456 cstr = [0 <= vq(1) <= 1, ...
457 0 <= vq(2) <= 1, ...
458 0 <= vq(3) <= 1, ...
459 cstr_exact_p, ...
460 cstr_tighten_F,...
461 cstr_tighten_S,...
462 z(1) >= 0, z(2) >= 0];
463 % set objective
464 zobj = fsWeights(1) * z(1)^2 + fsWeights(2) * z(2)^2;
465 % run solver
466 zsol = solvesdp(cstr, zobj, yalmip_nonlinear_opt);
467 % check output
468 if zsol.problem == 0
469 q1 = double(vq(1));
470 q2 = double(vq(2));
471 q3 = double(vq(3));
472 obj = double(zobj);
473 fprintf('Fitting MAMAP(2,2) F+S: solver (parameter space) objective = %e\n', obj);
474 else
475 fname = tempname;
476 save(fname,'map','p','F','S');
477 error('Fitting MAMAP(2,2) F+S: solver (parameter space) error: %s, input saved to %s\n', zsol.info, fname);
478 end
479 end
480
481% used for non-degenerate cases: hybrid space
482 function [feas,bobj,bF1,bS11] = solve_nonlinear_hybrid(side)
483 vF1 = sdpvar(1,1);
484 vS11 = sdpvar(1,1);
485 if form == 1
486 vq2 = sdpvar(1,1);
487 scale = U(5);
488 q1exp = -(G(15)*p(1) - vF1*G(3)*p(1) + vq2*(G(14)*G(3)-G(15)*G(2)))/Y(2);
489 q2num = U(1)*vF1^2*p(1)^2 + U(2)*vF1*p(1)^2 + U(3)*vS11 + U(4)*p(1)^2;
490 q2den = p(1)*(U(5)*vF1 + U(6));
491 q3exp = +(G(13)*p(1) - vF1*G(1)*p(1) + vq2*(G(14)*G(1)-G(13)*G(2)))/Y(2);
492 hcstr = [0 <= q1exp <= 1, 0 <= vq2 <= 1, vq2*q2den/scale == q2num/scale, 0 <= q3exp <= 1, 0 <= vS11 <= 1, vF1 >= 0];
493 else
494 vq3 = sdpvar(1,1);
495 scale = V(5);
496 q1exp = -(E(13)*p(1) - vF1*E(2)*p(1) + vq3*(E(14)*E(2)-E(13)*E(3)))/Z(2);
497 q2exp = +(E(12)*p(1) - vF1*E(1)*p(1) + vq3*(E(14)*E(1)-E(12)*E(3)))/Z(2);
498 q3num = V(1)*vF1^2*p(1)^2 + V(2)*vF1*p(1)^2 + V(3)*p(1)^2 + V(4)*vS11;
499 q3den = p(1)*(V(5)*vF1 + V(6));
500 hcstr = [0 <= q1exp <= 1, 0 <= q2exp <= 1, vq3*q3den/scale == q3num/scale, 0 <= vq3 <= 1, 0 <= vS11 <= 1, vF1 >= 0];
501 end
502 if strcmp(side,'left')
503 hcstr = [hcstr, vF1 <= M1-tol];
504 else
505 hcstr = [hcstr, vF1 >= M1+tol];
506 end
507 hobj = make_objective(vF1,vS11);
508 hsol = solvesdp(hcstr, hobj, yalmip_nonlinear_opt);
509 if hsol.problem == 0
510 fprintf('Fitting MAMAP(2,2) F+S: solver (hybrid space) objective = %f\n', double(hobj));
511 feas = 1;
512 bobj = double(hobj);
513 bF1 = double(vF1);
514 bS11 = double(vS11);
515 elseif hsol.problem == 1 || hsol.problem == 12
516 fprintf('Fitting MAMAP(2,2) F+S: program is infeasible\n');
517 feas = 0;
518 bobj = nan;
519 bF1 = nan;
520 bS11 = nan;
521 else
522 fname = tempname;
523 save(fname,'map','p','F','S');
524 error('Fitting MAMAP(2,2) F+S: solver (hybrid space) error: %s, input saved to %s\n', hsol.info, fname);
525 end
526 end
527
528% used for non-degenerate cases: hybrid space with z variable and implicit vS11
529 function [feas,bobj,bF1,bS11] = solve_nonlinear_hybrid_z(side)
530 vF1 = sdpvar(1,1);
531 z = sdpvar(1,1);
532 if form == 1
533 vq2 = sdpvar(1,1);
534 q1exp = -(G(15)*p(1) - vF1*G(3)*p(1) + vq2*(G(14)*G(3)-G(15)*G(2)))/Y(2);
535 q2den = p(1)*(U(5)*vF1 + U(6));
536 q3exp = +(G(13)*p(1) - vF1*G(1)*p(1) + vq2*(G(14)*G(1)-G(13)*G(2)))/Y(2);
537 S11exp = (vq2*q2den - p(1)^2*(U(1)*vF1^2 + U(2)*vF1 + U(4)))/U(3);
538 tighten = -z <= S11exp - S(1,1) <= +z;
539 hcstr = [0 <= q1exp <= 1, 0 <= vq2 <= 1, 0 <= q3exp <= 1, vF1 >= 0, tighten];
540 else
541 vq3 = sdpvar(1,1);
542 q1exp = -(E(13)*p(1) - vF1*E(2)*p(1) + vq3*(E(14)*E(2)-E(13)*E(3)))/Z(2);
543 q2exp = +(E(12)*p(1) - vF1*E(1)*p(1) + vq3*(E(14)*E(1)-E(12)*E(3)))/Z(2);
544 q3den = p(1)*(V(5)*vF1 + V(6));
545 S11exp = (vq3*q3den - p(1)^2*(V(1)*vF1^2 + V(2)*vF1 + V(3)))/V(4);
546 tighten = -z <= S11exp - S(1,1) <= +z;
547 hcstr = [0 <= q1exp <= 1, 0 <= q2exp <= 1, 0 <= vq3 <= 1, vF1 >= 0, tighten];
548 end
549 if strcmp(side,'left')
550 hcstr = [hcstr, vF1 <= M1-tol];
551 else
552 hcstr = [hcstr, vF1 >= M1+tol];
553 end
554 hobj = fsWeights(1)*(vF1/F(1)-1)^2 + fsWeights(2)*(z/S(1,1))^2;
555 hsol = solvesdp(hcstr, hobj, yalmip_nonlinear_opt);
556 if hsol.problem == 0
557 fprintf('Fitting MAMAP(2,2) F+S: solver (hybrid-z space) objective = %f\n', double(hobj));
558 feas = 1;
559 bobj = double(hobj);
560 bF1 = double(vF1);
561 bS11 = double(S11exp);
562 elseif hsol.problem == 1 || hsol.problem == 12
563 fprintf('Fitting MAMAP(2,2) F+S: program is infeasible\n');
564 feas = 0;
565 bobj = nan;
566 bF1 = nan;
567 bS11 = nan;
568 else
569 fname = tempname;
570 save(fname,'map','p','F','S');
571 error('Fitting MAMAP(2,2) F+S: solver (hybrid-z space) error: %s, input saved to %s\n', hsol.info, fname);
572 end
573 end
574
575% used for non-degenerate cases: characteristic space
576 function [feas,bobj,bF1,bS11] = solve_nonlinear_char(side)
577 is_left = 0;
578 if strcmp(side,'left')
579 fprintf('Fitting MAMAP(2,2) F+S: optimizing for F11 < M1\n');
580 is_left = 1;
581 else
582 fprintf('Fitting MAMAP(2,2) F+S: optimizing for F11 > M1\n');
583 end
584 % find initial feasible solution
585 if use_linprog_prepass
586 % parameter variables vq and auxiliary variables
587 vq = sdpvar(3,1);
588 z = sdpvar(1,1);
589 % define expressions
590 [pexp,pFexp,Sexp] = get_characteristics(vq(1),vq(2),vq(3));
591 % set constraints
592 if is_left
593 cstr_side = pFexp <= pexp*(M1-tol);
594 else
595 cstr_side = pFexp >= pexp*(M1+tol);
596 end
597 cstr_exact_p = pexp == p(1);
598 cstr_tighten = -z <= pFexp-p(1)*F(1) <=z;
599 fcstr = [0 <= vq(1) <= 1, ...
600 0 <= vq(2) <= 1, ...
601 0 <= vq(3) <= 1, ...
602 cstr_exact_p, ...
603 cstr_side,...
604 cstr_tighten,...
605 z >= 0];
606 % run linear programming solver
607 lsol = solvesdp(fcstr,z, get_yalmip_linear_options());
608 % check output
609 if lsol.problem == 0
610 feas = 1;
611 iF1 = double(pFexp / pexp);
612 iS11 = double(Sexp);
613 elseif lsol.problem == 1 || lsol.problem == 12
614 fprintf('Fitting MAMAP(2,2) F+S: linear program is infeasible\n');
615 feas = 0;
616 else
617 fname = tempname;
618 save(fname,'map','p','F','S');
619 error('Fitting MAMAP(2,2) F+S: linear program error: %s, input saved to %s\n', lsol.info, fname);
620 end
621 else
622 % assume feasible
623 feas = 1;
624 end
625 % if feasible, solve nonlinear program
626 if feas
627 % declare variables for optimization in characteristic space
628 vF1 = sdpvar(1,1);
629 vS11 = sdpvar(1,1);
630 % initialize variables
631 if use_linprog_prepass
632 assign(vF1,iF1);
633 assign(vS11,iS11);
634 end
635 % define objective function
636 cobj = make_objective(vF1, vS11);
637 % define constraints
638 if is_left
639 if form == 1
640 [cstr,~] = make_constraints_can1(p(1), vF1, vS11);
641 else
642 [cstr,~] = make_constraints_can2(p(1), vF1, vS11);
643 end
644 else
645 if form == 1
646 [~,cstr] = make_constraints_can1(p(1), vF1, vS11);
647 else
648 [~,cstr] = make_constraints_can2(p(1), vF1, vS11);
649 end
650 end
651 % solve nonlinear problem
652 csol = solvesdp(cstr, cobj, yalmip_nonlinear_opt);
653 % check result
654 if csol.problem ~= 0
655 fname = tempname;
656 save(fname,'map','p','F','S');
657 error('Fitting MAMAP(2,2) F+S: solver (characteristic space) error: %s, input saved to %s\n', csol.info, fname);
658 else
659 bobj = double(cobj);
660 bF1 = double(vF1);
661 bS11 = double(vS11);
662 fprintf('Fitting MAMAP(2,2) F+S: solver (characteristic space) objective = %e\n', double(cobj));
663 end
664 else
665 % infeasible subproblem
666 bobj = nan;
667 bF1 = nan;
668 bS11 = nan;
669 end
670 end
671
672 function obj = make_objective(vF1, vS11)
673 obj = classWeights(1) * fsWeights(1) * (vF1/F(1) - 1)^2 + ...
674 classWeights(1) * fsWeights(2) * (vS11/S(1,1) - 1)^2;
675 end
676
677 function [q1n,q1d,q2n,q2d,q3] = make_q_can1(p, vF1, vS11)
678 % define coefficients of polynomials
679 q1n_F = p^2*(r1 - 1)*(r1*r2 - r2 + 1);
680 q1n_s = -r1*(h1 - h2 + h2*r1);
681 q1n_1 = h1*p^2*(r1*r2 - r2 + 1);
682 q1d_F = p*(r1 - 1)*(r1*r2 - r2 + 1);
683 q1d_1 = -p*(r1 - 1)*(h1 - h1*r2 + h2*r1);
684 q2n_Fsq = -p^2*(r1*r2 - r2 + 1)^2;
685 q2n_F = p^2*(r1*r2 - r2 + 1)*(2*h1 - h1*r1 - 2*h1*r2 + 3*h2*r1 - h2*r1^2 + h2*r1^2*r2 + h1*r1*r2 - h2*r1*r2);
686 q2n_s = -r1*(r2 - 1)*(h1 - h2 + h2*r1)^2;
687 q2n_1 = -p^2*(r1*r2 - r2 + 1)*(h2^2*r1 - h1^2*r2 + h1^2 + h1*h2*r1 - h1*h2*r1*r2);
688 q2d_F = p*r1*(r2 - 1)*(r1*r2 - r2 + 1)*(h1 - h2 + h2*r1);
689 q2d_1 = -p*r1*(r2 - 1)*(h1 - h1*r2 + h2*r1)*(h1 - h2 + h2*r1);
690 q3_F = -(p*(r1*r2 - r2 + 1))/(r1*r2*(h1 + h2*(r1 - 1)));
691 q3_1 = (p*(h1 + h2*r1)*(r1*r2 - r2 + 1))/(r1*r2*(h1 - h2 + h2*r1));
692 % return expressions
693 q1n = q1n_F * vF1 + q1n_s * vS11 + q1n_1;
694 q1d = q1d_F * vF1 + q1d_1;
695 q2n = q2n_Fsq * vF1^2 + q2n_F * vF1 + q2n_s * vS11 + q2n_1;
696 q2d = q2d_F * vF1 + q2d_1;
697 q3 = q3_F * vF1 + q3_1;
698 end
699
700 function [lcstr,rcstr] = make_constraints_can1(p, vF1, vS11)
701
702 % get fitting expressions
703 [q1n,q1d,q2n,q2d,q3] = make_q_can1(p, vF1, vS11);
704
705 % these are in common for the two subproblems
706 q3lb = q3 >= 0;
707 q3ub = q3 <= 1;
708
709 scale = 1/abs(U(5));
710 %scale = 1/abs(q2d{M1-tol});
711
712 % left constraints: F(1) < M1
713 q1lb = q1n >= 0;
714 q1ub = q1n <= q1d;
715 if h2 < h1/(1-r1)
716 % do not change direction of inequalities for q2
717 q2lb = scale*(q2n) >= 0;
718 q2ub = scale*(q2n) <= scale*(q2d);
719 else
720 % change direction of inequalities for q2
721 q2lb = scale*(q2n) <= 0;
722 q2ub = scale*(q2n) >= scale*(q2d);
723 end
724 F1bound = vF1 <= M1-tol;
725 lcstr = [q1lb,q1ub,q2lb,q2ub,q3lb,q3ub,F1bound,vS11 >= 0, vS11 <= 1];
726
727 % right constraints: F(1) > M1
728 q1lb = q1n <= 0;
729 q1ub = q1n >= q1d;
730 if h2 > h1/(1-r1)
731 % do not change direction of inequalities for q2
732 q2lb = scale*(q2n) >= 0;
733 q2ub = scale*(q2n) <= scale*(q2d);
734 else
735 % change direction of inequalities for q2
736 q2lb = scale*(q2n) <= 0;
737 q2ub = scale*(q2n) >= scale*(q2d);
738 end
739 F1bound = vF1 >= M1+tol;
740 rcstr = [q1lb,q1ub,q2lb,q2ub,q3lb,q3ub,F1bound,vS11 >= 0, vS11 <= 1];
741 end
742
743 function [q1n,q1d,q2,q3n,q3d] = make_q_can2(p, vF1, vS11)
744 % define coefficients of polynomials
745 q1n_F = p^2*(r1 - 1)*(r1 + r2 - r1*r2 - 2);
746 q1n_s = h1 - h2 + h2*r1;
747 q1n_1 = h1*p^2*(r1 + r2 - r1*r2 - 2);
748 q1d_F = p*(r1 - 1)*(r1 + r2 - r1*r2 - 2);
749 q1d_1 = p*(r1 - 1)*(h1 + h2 - h1*r2);
750 q2_F = p*(r1 + r2 - r1*r2 - 2)/(h2 - h1 + h1*r2 - h2*r1 - h2*r2 + h2*r1*r2);
751 q2_1 = -h2*p*(r1 + r2 - r1*r2 - 2)/(h2 - h1 + h1*r2 - h2*r1 - h2*r2 + h2*r1*r2);
752 q3n_Fsq = p^2*(r1 + r2 - r1*r2 - 2)^2;
753 q3n_F = p^2*(r1 + r2 - r1*r2 - 2)*(2*h1 + 2*h2 - h1*r2 - h2*r2 + h2*r1*r2);
754 q3n_s = -(r2 - 1)*(h1 - h2 + h2*r1)^2;
755 q3n_1 = -h2*p^2*(2*h1 - h1*r2 + h2*r1)*(r1 + r2 - r1*r2 - 2);
756 q3d_F = p*r2*(h1 - h2 + h2*r1)*(r1 + r2 - r1*r2 - 2);
757 q3d_1 = p*r2*(h1 + h2 - h1*r2)*(h1 - h2 + h2*r1);
758 % return expressions
759 q1n = q1n_F * vF1 + q1n_s * vS11 + q1n_1;
760 q1d = q1d_F * vF1 + q1d_1;
761 q2 = q2_F * vF1 + q2_1;
762 q3n = q3n_Fsq * vF1^2 + q3n_F * vF1 + q3n_s * vS11 + q3n_1;
763 q3d = q3d_F * vF1 + q3d_1;
764 end
765
766 function [lcstr,rcstr] = make_constraints_can2(p, vF1, vS11)
767
768 % get fitting expressions
769 [q1n,q1d,q2,q3n,q3d] = make_q_can2(p, vF1, vS11);
770
771 % these are in common for the two subproblems
772 q2lb = q2 >= 0;
773 q2ub = q2 <= 1;
774
775 scale = 1/abs(V(5));
776 %scale = 1/abs(q3d{M1-tol});
777
778 % left constraints: F1 < M1
779 q1lb = q1n <= 0;
780 q1ub = q1n >= q1d;
781 if (h1 - h2 + h2*r1) < 0
782 q3lb = scale*(q3n) <= 0;
783 q3ub = scale*(q3n) >= scale*(q3d);
784 else
785 q3lb = scale*(q3n) >= 0;
786 q3ub = scale*(q3n) <= scale*(q3d);
787 end
788 F1bound = vF1 <= M1-tol;
789 lcstr = [q1lb,q1ub,q2lb,q2ub,q3lb,q3ub,F1bound,vS11 >= 0, vS11 <= 1];
790
791 % rigt costraints: F1 > M1
792 q1lb = q1n >= 0;
793 q1ub = q1n <= q1d;
794 if (h1 - h2 + h2*r1) < 0
795 q3lb = scale*(q3n) >= 0;
796 q3ub = scale*(q3n) <= scale*(q3d);
797 else
798 q3lb = scale*(q3n) <= 0;
799 q3ub = scale*(q3n) >= scale*(q3d);
800 end
801 F1bound = vF1 >= M1+tol;
802 rcstr = [q1lb,q1ub,q2lb,q2ub,q3lb,q3ub,F1bound,vS11 >= 0, vS11 <= 1];
803 end
804
805% used for degenerate case
806 function x = solve_quadprog()
807 fprintf('Fitting MAMAP(2,2) F+S: running quadratic programming solver...\n');
808 options = optimset('Algorithm','interior-point-convex','Display','none');
809 %[x,fx,xflag] = quadprog(H, h, A, b, [], [], [], [], [], options);
810 lb = 1e-6*ones( size(A,2),1);
811 ub = 1e6*ones( size(A,2),1);
812 [x,fx,xflag]=QP(H, h, A, b, Aeq, beq, lb, ub, options);
813
814 if xflag ~= 1
815 error('Quadratic programming solver failed: %d\n', exit);
816 end
817 fit_error = fx + length(x);
818 fprintf('Fitting MAMAP(2,2) F+S: error = %f\n', fit_error);
819 end
820
821end