1function [QN,UN,RN,TN,CN,XN,totiter,method,runtime] = solver_mam(sn, options)
2%[Q,U,R,T,C,X,totiter] = SOLVER_MAM(QN, PH, OPTIONS)
4%Copyright (c) 2012-2026, Imperial College London
7method = options.method;
8config = options.config;
16V = cellsum(sn.visits);
27 inchain = sn.inchain{c};
28 lambdas_inchain = sn.rates(sn.refstat(inchain(1)),inchain);
29 lambdas_inchain = lambdas_inchain(isfinite(lambdas_inchain));
30 lambda(inchain) = sum(lambdas_inchain);
35 chain(k) = find(sn.chains(:,k));
40 case SchedStrategy.EXT
42 case {SchedStrategy.FCFS, SchedStrategy.HOL, SchedStrategy.FCFSPRPRIO, SchedStrategy.PS}
46 line_warning(mfilename,'The dec.mmap method does not support
this scheduling strategy.\n
');
48 [QN,UN,RN,TN,CN,XN] = deal([],[],[],[],[],[]);
51 runtime = toc(Tstart);
56if all(isinf(sn.njobs)) % is open
57 % open queueing system (one node is the external world)
62 case SchedStrategy.EXT
63 TN(ist,:) = sn.rates(ist,:);
64 TN(ist,isnan(TN(ist,:)))=0;
65 case {SchedStrategy.FCFS, SchedStrategy.HOL, SchedStrategy.FCFSPRPRIO, SchedStrategy.PS}
67 % divide service time by number of servers and put
68 % later a surrogate delay server in tandem to compensate
69 PH{ist}{k} = map_scale(PH{ist}{k}, map_mean(PH{ist}{k})/sn.nservers(ist));
70 pie{ist}{k} = map_pie(PH{ist}{k});
71 D0{ist,k} = PH{ist}{k}{1};
72 if any(isnan(D0{ist,k}))
73 D0{ist,k} = -GlobalConstants.Immediate;
75 PH{ist}{k} = map_exponential(GlobalConstants.Immediate);
81 it_max = options.iter_max;
84 % now estimate arrival processes
86 % initially form departure processes using scaled service
90 ist = sn.nodeToStation(ind);
91 DEP{ind,r} = map_scale(PH{ist}{r}, 1 / (lambda(r) * V(ind,r)) );
96 ARV = solver_mam_traffic(sn, DEP, config);
100 ind = sn.stationToNode(ist);
101 finiteCapUsed = false;
102 switch sn.nodetype(ind)
104 if length(ARV{ind}{1}) > config.space_max
105 line_printf('\nArrival process at node %d
is now at %d states. Compressing.
',ind,length(ARV{ind}{1}));
106 ARV{ind} = mmap_compress(ARV{ind});
108 TN(ist,:) = mmap_lambda(ARV{ind});
110 case {SchedStrategy.FCFS, SchedStrategy.HOL, SchedStrategy.FCFSPRPRIO}
111 isFiniteCap = isfinite(sn.cap(ist));
114 [isMmck, muMmck] = mam_detect_mmck(sn, ist, K, ARV{ind});
116 aggrLambda_ist = sum(TN(ist,:), 'omitnan
');
117 exactRes = qsys_mmck(aggrLambda_ist, muMmck, sn.nservers(ist), capK);
118 meanQ_fc = exactRes.meanQueueLength;
119 lossProb_fc = exactRes.lossProbability;
121 [meanQ_fc, lossProb_fc, ~] = mam_truncate_renorm( ...
122 {ARV{ind}{[1,3:end]}}, {pie{ist}{:}}, {D0{ist,:}}, capK);
124 lambdaInflow = TN(ist,:); % per-class rates from mmap_lambda
125 lambdaInflow(isnan(lambdaInflow)) = 0;
126 TN_eff = lambdaInflow * (1 - lossProb_fc);
128 % Actual per-class service mean (PH was scaled by 1/c)
129 S_actual = zeros(1, K);
131 S_actual(k) = map_mean(PH{ist}{k}) * sn.nservers(ist);
134 Savg_eff = sum(TN_eff .* S_actual, 'omitnan
') / sumTN;
135 Wq = max(0, meanQ_fc / sumTN - Savg_eff);
140 TN(ist,k) = TN_eff(k);
141 UN(ist,k) = TN(ist,k) * map_mean(PH{ist}{k});
143 RN(ist,k) = Wq + S_actual(k);
144 QN(ist,k) = TN(ist,k) * RN(ist,k);
150 finiteCapUsed = true;
152 [Qret{1:K}, ~] = MMAPPH1FCFS({ARV{ind}{[1,3:end]}}, {pie{ist}{:}}, {D0{ist,:}}, 'ncMoms
', 1, 'ncDistr
',2);
154 QN(ist,k) = sum(Qret{k});
157 case SchedStrategy.PS
159 UN(ist,k) = TN(ist,k) * map_mean(PH{ist}{k});
161 Uden = min([1-GlobalConstants.FineTol, sum(UN(ist,:))]);
163 QN(ist,k) = UN(ist,k)/(1-Uden);
169 UN(ist,k) = TN(ist,k) * map_mean(PH{ist}{k});
170 %add number of jobs at the surrogate delay server
171 QN(ist,k) = QN(ist,k) + TN(ist,k)*(map_mean(PH{ist}{k})*sn.nservers(ist)) * (sn.nservers(ist)-1)/sn.nservers(ist);
172 RN(ist,k) = QN(ist,k) ./ TN(ist,k);
177 if it >=3 && max(abs(QN(:)-QN_1(:))./QN_1(:)) < options.iter_tol
182 ind = sn.stationToNode(ist);
183 switch sn.nodetype(ind)
186 % extract class-r arrival MAP
187 A = mmap_hide(ARV{ind},setdiff(1:K,r));
191 etaqa_n = config.etaqa_trunc;
192 etaqa_sz = (etaqa_n+1)*na*ns;
193 rho = sum(UN(ist,:));
194 % use ETAQA if state space is manageable and queue is stable
195 if etaqa_sz <= config.space_max && rho < 1-GlobalConstants.FineTol
198 case {SchedStrategy.FCFS, SchedStrategy.HOL, SchedStrategy.FCFSPRPRIO}
199 DEP{ind,r} = qbd_depproc_etaqa(A, S, etaqa_n);
200 case SchedStrategy.PS
201 DEP{ind,r} = qbd_depproc_etaqa_ps(A, S, etaqa_n);
203 DEP{ind,r} = map_normalize(DEP{ind,r});
205 % fall back to scaled service on ETAQA failure
206 DEP{ind,r} = PH{ist}{r};
209 DEP{ind,r} = PH{ist}{r};
211 DEP{ind,r} = map_scale(DEP{ind,r}, 1 / (lambda(r) * V(ind,r)) );
212 SCVd(ind,r) = map_scv(DEP{ind,r});
213 IDCd(ind,r) = map_idc(DEP{ind,r});
220 line_printf('\nMAM parametric decomposition completed in %d iterations.
',it);
224 line_warning(mfilename,'This model
is not supported by SolverMAM yet. Returning with no result.\n
');
227runtime = toc(Tstart);