LINE Solver
MATLAB API documentation
Loading...
Searching...
No Matches
test_etaqa_depproc_ps.m
1% Test ETAQA departure process for PS queues in SolverMAM dec.mmap
2%
3% Creates a 2-queue tandem with Erlang arrivals and PS scheduling, solved
4% with dec.mmap (ETAQA-PS-based departures). Validates that:
5% 1. dec.mmap now accepts PS queues (previously unsupported)
6% 2. Results are finite and consistent with MVA (exact for PS mean values)
7% 3. The PS departure process captures queueing effects beyond scaled service
8
9%% Model: Erl(3)/M/1-PS -> M/1-PS tandem
10model = Network('ETAQA-PS-Tandem');
11
12source = Source(model, 'Source');
13queue1 = Queue(model, 'Queue1', SchedStrategy.PS);
14queue2 = Queue(model, 'Queue2', SchedStrategy.PS);
15sink = Sink(model, 'Sink');
16
17oclass = OpenClass(model, 'Class1');
18source.setArrival(oclass, Erlang.fitMeanAndOrder(2, 3)); % mean=2, SCV=1/3
19queue1.setService(oclass, Exp(2)); % rho1=0.5
20queue2.setService(oclass, Exp(1.5)); % rho2=0.667
21
22model.link(Network.serialRouting(source, queue1, queue2, sink));
23
24%% Solve with dec.mmap (uses ETAQA PS departure process)
25solverMMAP = SolverMAM(model, 'method', 'dec.mmap');
26T_mmap = solverMMAP.getAvgTable();
27
28%% Solve with MVA (exact mean values for PS)
29solverMVA = SolverMVA(model);
30T_mva = solverMVA.getAvgTable();
31
32%% Display results
33fprintf('\n=== ETAQA PS Departure Process Test ===\n');
34fprintf('%-10s %10s %10s\n', 'Station', 'MVA', 'dec.mmap');
35fprintf('--- Queue Lengths ---\n');
36for i = 1:height(T_mva)
37 stn = string(T_mva.Station(i));
38 if contains(stn, 'Queue')
39 fprintf('%-10s %10.4f %10.4f\n', stn, T_mva.QLen(i), T_mmap.QLen(i));
40 end
41end
42fprintf('--- Utilizations ---\n');
43for i = 1:height(T_mva)
44 stn = string(T_mva.Station(i));
45 if contains(stn, 'Queue')
46 fprintf('%-10s %10.4f %10.4f\n', stn, T_mva.Util(i), T_mmap.Util(i));
47 end
48end
49
50%% Validate: dec.mmap results should be finite
51Q_mmap = T_mmap.QLen(contains(string(T_mmap.Station), 'Queue'));
52Q_mva = T_mva.QLen(contains(string(T_mva.Station), 'Queue'));
53U_mmap = T_mmap.Util(contains(string(T_mmap.Station), 'Queue'));
54U_mva = T_mva.Util(contains(string(T_mva.Station), 'Queue'));
55
56assert(all(isfinite(Q_mmap)), 'ETAQA PS: dec.mmap returned non-finite queue lengths');
57assert(all(Q_mmap >= 0), 'ETAQA PS: dec.mmap returned negative queue lengths');
58
59%% Validate utilization (should match exactly since throughput = arrival rate)
60relErrU = abs(U_mmap - U_mva) ./ max(U_mva, 1e-6);
61fprintf('\nUtilization error vs MVA: %.4f%%, %.4f%%\n', relErrU*100);
62assert(all(relErrU < 0.01), ...
63 sprintf('ETAQA PS: utilizations deviate >1%% from MVA (err=%.4f%%)', max(relErrU)*100));
64
65%% Validate queue lengths (PS mean QLen = rho/(1-rho), independent of arrival process)
66% For a single-class open M/G/1-PS, E[Q] = rho/(1-rho) regardless of
67% arrival SCV. The dec.mmap Q approximation uses U/(1-U) so should match.
68relErrQ = abs(Q_mmap - Q_mva) ./ max(Q_mva, 1e-6);
69fprintf('Queue length error vs MVA: %.2f%%, %.2f%%\n', relErrQ*100);
70assert(all(relErrQ < 0.20), ...
71 sprintf('ETAQA PS: queue lengths deviate >20%% from MVA (err=%.2f%%)', max(relErrQ)*100));
72
73%% Test: single PS queue (simplest case)
74model2 = Network('ETAQA-PS-Single');
75src2 = Source(model2, 'Source');
76q2 = Queue(model2, 'Queue1', SchedStrategy.PS);
77snk2 = Sink(model2, 'Sink');
78oc2 = OpenClass(model2, 'Class1');
79src2.setArrival(oc2, APH.fitMeanAndSCV(2, 4)); % high-variability arrival
80q2.setService(oc2, Exp(1)); % rho=0.5
81model2.link(Network.serialRouting(src2, q2, snk2));
82
83solverMMAP2 = SolverMAM(model2, 'method', 'dec.mmap');
84T2 = solverMMAP2.getAvgTable();
85Q2 = T2.QLen(contains(string(T2.Station), 'Queue'));
86assert(all(isfinite(Q2)), 'ETAQA PS single queue: returned non-finite results');
87assert(all(Q2 >= 0), 'ETAQA PS single queue: returned negative queue lengths');
88fprintf('Single PS queue Q=%.4f (expected ~1.0)\n', Q2);
89
90fprintf('\nETAQA PS departure process test PASSED.\n');