LINE Solver
MATLAB API documentation
Loading...
Searching...
No Matches
test_qrf_noblo_mmi_linear.m
1function test_qrf_noblo_mmi_linear
2% Regression test for the QRF no-blocking MMI polytope (linear assembly).
3%
4% Self-contained: no LINE dependencies and no LP solver. It uses feasibility
5% of a known-exact point as the oracle, which is what actually discriminates
6% the polytope (an fmincon iterate does not).
7%
8% The instance is the 2-station closed network with exponential service and
9% load-dependent rates alpha(i,n), for which the exact stationary law is the
10% birth-death chain
11%
12% mu(2)*alpha(2,N-n) * g(n) = mu(1)*alpha(1,n+1) * g(n+1), g(n)=P(n1=n).
13%
14% Three properties are asserted:
15% 1. q is 5-D, [M M max(K) max(K) N+1], per qrboundsrsrd_skel.mod.
16% 2. The exact point is feasible.
17% 3. A point built from the WRONG rates is infeasible. This is the property
18% that failed before the 6-subscript-write / 4-subscript-read defect was
19% fixed: q then read as all zeros, every q-weighted row (THM1, THM30,
20% THM3, THM3f) was a vacuous 0=0 row, and the polytope did not depend on
21% mu or alpha at all.
22
23N = 3; M = 2; rt = [0 1; 1 0];
24tol = 1e-9;
25
26cases = { ...
27 struct('mu',[1.0 1.0],'alpha',[1 1 1]), ...
28 struct('mu',[4.0 1.0],'alpha',[1 1 1]), ...
29 struct('mu',[0.5 1.0],'alpha',[1 1 1]), ...
30 struct('mu',[1.0 1.0],'alpha',[1 2 3]), ...
31 struct('mu',[1.0 1.0],'alpha',[1 3 9])};
32
33for t = 1:numel(cases)
34 mu = cases{t}.mu;
35 alpha = ones(M,N); alpha(1,:) = cases{t}.alpha;
36 MAPs = {{-mu(1), mu(1)}; {-mu(2), mu(2)}};
37
38 [~,~,~,lp] = qrf_noblo_mmi_linear(MAPs,N,rt,alpha,true);
39
40 % 1. arity of q
41 q = local_q(MAPs,N,rt,alpha);
42 assert(isequal(size(q),[M M 1 1 N+1]), ...
43 'case %d: q must be 5-D [M M K K N+1], got %s', t, mat2str(size(q)));
44
45 % 2. the exact point is feasible
46 g = local_exact(N,mu,alpha);
47 x = local_point(N,M,g);
48 [rEq,rIn] = local_residuals(lp,x);
49 assert(rEq < tol, 'case %d: exact point violates an equality by %g', t, rEq);
50 assert(rIn < tol, 'case %d: exact point violates an inequality by %g', t, rIn);
51
52 % 3. a point built from the wrong rates is infeasible
53 gBad = local_exact(N,[mu(1)*3 mu(2)],alpha);
54 if max(abs(gBad-g)) > 1e-6
55 xBad = local_point(N,M,gBad);
56 rEqBad = local_residuals(lp,xBad);
57 assert(rEqBad > 1e-3, ...
58 ['case %d: a point built from the wrong service rates is feasible ' ...
59 '(residual %g). The polytope does not depend on the rates.'], t, rEqBad);
60 end
61end
62
63fprintf('test_qrf_noblo_mmi_linear: %d cases passed\n', numel(cases));
64end
65
66function q = local_q(MAPs,N,rt,alpha)
67% Rebuild q exactly as qrf_noblo_mmi_linear does, to assert its arity.
68M = length(MAPs);
69for i=1:M, K(i)=size(MAPs{i}{1},1); end
70q = zeros(M,M,max(K),max(K),N+1);
71for i = 1:M, for j = 1:M, for k = 1:K(i), for h = 1:K(i), for ni = 1:N
72 mu = MAPs{i}{2}(k,h);
73 if k==h, v = 0; else, v = MAPs{i}{1}(k,h); end
74 if j ~= i
75 q(i,j,k,h,1+ni) = rt(i,j)*mu*alpha(i,ni);
76 else
77 q(i,j,k,h,1+ni) = v*alpha(i,ni)+rt(i,i)*mu*alpha(i,ni);
78 end
79end, end, end, end, end
80end
81
82function g = local_exact(N,mu,alpha)
83% g(1+n) = P(n1 = n) for the 2-station load-dependent birth-death chain.
84g = zeros(1,N+1); g(1) = 1;
85for n = 0:N-1
86 g(1+n+1) = g(1+n) * (mu(2)*alpha(2,N-n)) / (mu(1)*alpha(1,n+1));
87end
88g = g / sum(g);
89end
90
91function x = local_point(N,M,g)
92% Assemble the decision vector in the layout used by deltap2/deltae, for the
93% single-phase two-station case: p2 is supported on n1+n2 = N.
94MR = 1; Km = 1;
95nx = M*(N+1)*Km*M*(N+1)*Km*MR + M*Km;
96x = zeros(nx,1);
97gi = @(i,n) g(1 + (i==1)*n + (i==2)*(N-n)); % P(n_i = n)
98for j = 1:M, for nj = 0:N, for i = 1:M, for ni = 0:N
99 if i == j
100 if nj == ni, val = gi(i,ni); else, val = 0; end
101 else
102 if nj + ni == N, val = gi(i,ni); else, val = 0; end
103 end
104 if val ~= 0
105 x(local_idx(N,M,j,1+nj,i,1+ni)) = val;
106 end
107end, end, end, end
108% e(i,k) = P(n_i >= 1)
109base = M*(N+1)*Km*M*(N+1)*Km*MR;
110for i = 1:M
111 x(base + i) = 1 - gi(i,0);
112end
113end
114
115function idx = local_idx(N,M,j,nj,i,ni)
116MR = 1; Km = 1; k = 1; h = 1; m = 1;
117idx = (N+1)*Km*M*(N+1)*Km*MR*(j-1);
118idx = idx + Km*M*(N+1)*Km*MR*(nj-1);
119idx = idx + M*(N+1)*Km*MR*(k-1);
120idx = idx + (N+1)*Km*MR*(i-1);
121idx = idx + Km*MR*(ni-1);
122idx = idx + MR*(h-1);
123idx = idx + m;
124end
125
126function [rEq,rIn] = local_residuals(lp,x)
127rEq = 0; rIn = 0;
128if ~isempty(lp.Aeq)
129 rEq = max(abs(full(lp.Aeq*x - lp.beq(:))));
130end
131if ~isempty(lp.A) && size(lp.A,1) > 0
132 rIn = max([0; full(lp.A*x - lp.b(:))]);
133end
134end
Definition Station.m:245