1function test_lossn_mci()
2% TEST_LOSSN_MCI Validate Monte Carlo summation
for loss networks
3% against exact enumeration, Erlang-B, and
the Erlang fixed point.
5fprintf(
'=== test_lossn_mci ===\n');
9% ---------------------------------------------------------------
10% Test 1: single-link Erlang-B (J=1, one
class, unit demand)
11% Exact blocking = ErlangB(rho, C).
12% ---------------------------------------------------------------
14[~, Loss, lG, ci] = lossn_mci(rho, 1, Ccap,
struct(
'samples',2e5,
'seed',1));
15exactB = erlangB_ref(rho, Ccap);
16[gExact, ~] = lossn_exact(rho, 1, Ccap);
17fprintf(
'\n[T1] M/M/C/C Erlang-B rho=%g C=%d\n', rho, Ccap);
18fprintf(
' blocking exact=%.6f mci=%.6f CI=[%.6f,%.6f]\n', ...
19 exactB, Loss, ci.loss(1,1), ci.loss(1,2));
20fprintf(
' lG exact=%.6f mci=%.6f\n', log(gExact), lG);
21[npass,nfail] = check(npass, nfail, ci.loss(1,1) <= exactB && exactB <= ci.loss(1,2),
'T1 blocking in CI');
22[npass,nfail] = check(npass, nfail, abs(lG-log(gExact)) < 0.05,
'T1 lG matches exact');
24% ---------------------------------------------------------------
25% Test 2: two-link multirate network, exact enumeration
26% Link1 shared by both classes, class2 needs 2 circuits on link2.
27% ---------------------------------------------------------------
29A = [1 1; 1 2]; % 2 links x 2 classes
31[gEx, betaEx] = lossn_exact(nu, A, Cv);
32[QLen, Loss, lG, ci] = lossn_mci(nu, A, Cv,
struct(
'samples',3e5,
'seed',2));
33fprintf(
'\n[T2] two-link multirate, exact enumeration\n');
34fprintf(
' lG exact=%.6f mci=%.6f\n', log(gEx), lG);
36 fprintf(
' class %d: beta exact=%.6f mci=%.6f CI=[%.6f,%.6f]\n', ...
37 r, betaEx(r), Loss(r), ci.loss(r,1), ci.loss(r,2));
38 [npass,nfail] = check(npass, nfail, ...
39 ci.loss(r,1) <= betaEx(r) && betaEx(r) <= ci.loss(r,2), ...
40 sprintf(
'T2 class %d blocking in CI', r));
42[npass,nfail] = check(npass, nfail, abs(lG-log(gEx)) < 0.05,
'T2 lG matches exact');
43% carried load consistency: QLen = nu*(1-beta)
44[npass,nfail] = check(npass, nfail, max(abs(QLen - nu.*(1-Loss))) < 1e-9,
'T2 QLen=nu*(1-beta)');
46% ---------------------------------------------------------------
47% Test 3: reproducibility with fixed seed
48% ---------------------------------------------------------------
49[~, L1] = lossn_mci(nu, A, Cv,
struct(
'samples',5e4,
'seed',7));
50[~, L2] = lossn_mci(nu, A, Cv,
struct(
'samples',5e4,
'seed',7));
51fprintf(
'\n[T3] reproducibility: max|L1-L2|=%.2e\n', max(abs(L1-L2)));
52[npass,nfail] = check(npass, nfail, isequal(L1,L2),
'T3 fixed seed reproducible');
54% ---------------------------------------------------------------
55% Test 4: paper star network (Figure 1, Table 1) light traffic.
56% 4 links, 12 classes. Compare against exact enumeration
is
57% infeasible (>1e12 states); cross-check against Erlang FP order
58% of magnitude and that
class-blocking CIs bracket
the FP estimate
59% loosely (FP
is an approximation, so only sanity, not equality).
60% ---------------------------------------------------------------
61[nu4, A4, C4] = star_network(
'light');
62% lossn_erlangfp returns blocking probability; convert to acceptance.
63% Blocking here
is a deep-tail event (well below 1%), so cross-check
the
64% well-conditioned acceptance probabilities of
the two methods.
65[~, LossFP] = lossn_erlangfp(nu4, A4, C4);
67[~, LossMC, lG4, ci4] = lossn_mci(nu4, A4, C4,
struct(
'samples',2e5,
'seed',3));
69fprintf(
'\n[T4] star network (light traffic), lG=%.4f\n', lG4);
70fprintf(
' class FP-accept MCI-accept MCI-beta%% MCI-CI%%\n');
72 fprintf(
' %5d %.6f %.6f %.4f [%.4f,%.4f]\n', r, accFP(r), accMC(r), ...
73 100*LossMC(r), 100*ci4.loss(r,1), 100*ci4.loss(r,2));
75% All blocking probabilities must be valid probabilities.
76[npass,nfail] = check(npass, nfail, all(LossMC>=0 & LossMC<=1),
'T4 valid probabilities');
77% Two independent methods (Erlang FP vs Monte Carlo) must agree on
the
78% well-conditioned acceptance probabilities.
79[npass,nfail] = check(npass, nfail, ...
80 max(abs(accMC - accFP)) < 0.02,
'T4 MCI vs FP acceptance agree');
82% ---------------------------------------------------------------
83% Test 5: variance reduction -- heuristic gamma vs gamma=nu (rho)
84% Section 3.2: importance sampling narrows CI in heavy traffic.
85% ---------------------------------------------------------------
86[nuH, AH, CH] = star_network(
'heavy');
87[~, ~, ~, ciIS] = lossn_mci(nuH, AH, CH,
struct(
'samples',1e5,
'seed',4));
88[~, ~, ~, ciRho] = lossn_mci(nuH, AH, CH,
struct(
'samples',1e5,
'seed',4,
'gamma',nuH));
89wIS = mean(ciIS.accept(:,2) - ciIS.accept(:,1));
90wRho = mean(ciRho.accept(:,2) - ciRho.accept(:,1));
91fprintf(
'\n[T5] heavy traffic mean CI width: gamma=heuristic %.5f, gamma=rho %.5f (imp=%.2fx)\n', ...
93[npass,nfail] = check(npass, nfail, wIS <= wRho*1.02,
'T5 heuristic gamma not worse than rho');
95fprintf(
'\n=== RESULT: %d passed, %d failed ===\n', npass, nfail);
97 error(
'test_lossn_mci: %d checks failed', nfail);
101% ---------------------------------------------------------------
102function [np, nf] = check(np, nf, cond, name)
104 np = np + 1; fprintf(
' PASS: %s\n', name);
106 nf = nf + 1; fprintf(
' FAIL: %s\n', name);
110function [g, beta] = lossn_exact(nu, A, C)
111% Exact normalization constant and
class blocking by box enumeration.
112nu = nu(:)
'; C = C(:);
113R = numel(nu); J = numel(C);
117 N(k) = floor(min(C(pos)./A(pos,k)));
119% enumerate all n in box {0..N_k}
121for k = 1:R, grids{k} = 0:N(k); end
122[out{1:R}] = ndgrid(grids{:});
123States = zeros(numel(out{1}), R);
124for k = 1:R, States(:,k) = out{k}(:); end
125% product-form weight q(n) = prod nu^n / n!
126logq = States * log(nu(:)) - sum(gammaln(States+1), 2);
128feas = all(AV <= C(:)
', 2);
130g = exp(mq) * sum(exp(logq(feas) - mq));
134 feasR = all(AV <= Cr, 2);
135 gr = exp(mq) * sum(exp(logq(feasR) - mq));
140function b = erlangB_ref(rho, C)
141% Reference Erlang-B via stable recursion.
144 inv = 1 + inv * k / rho;
149function [nu, A, C] = star_network(regime)
150% Four-leaf star network of Ross-Wang Table 1 / Figure 1.
151% Links C1=90,C2=100,C3=110,C4=120. Six leaf pairs, two classes each
152% (1 circuit and 5 circuits) -> 12 classes. Routes as in Table 1.
153C = [90; 100; 110; 120];
154routes = [1 2; 1 3; 1 4; 2 3; 2 4; 3 4]; % 6 pairs
156 case 'light', base = 9.0; hi = 1.6;
157 case 'moderate', base = 10.0; hi = 2.0;
158 case 'heavy', base = 15.0; hi = 3.0;
159 otherwise, error(
'unknown regime');
166 A(routes(p,1), p) = 1; A(routes(p,2), p) = 1; nu(p) = base;
168 A(routes(p,1), 6+p) = 5; A(routes(p,2), 6+p) = 5; nu(6+p) = hi;