1function [Q,U,R,T,C,X,lG] = solver_mvac(sn,options)
2% [Q,U,R,T,C,X,LG] = SOLVER_MVAC(SN,OPTIONS)
4% Exact mean value analysis by chain (MVAC, Conway-de Souza e Silva-Lavenberg
5% 1989) via pfqn_mvac. Closed product-
form networks of single-server
6% fixed-rate (SSFR) queues and infinite-server centers only.
8% Copyright (c) 2012-2026, Imperial College London
12 options = SolverMVA.defaultOptions;
15[Lchain,STchain,Vchain,alpha,Nchain,~,refstatchain] = sn_get_demands_chain(sn);
17nservers = sn.nservers;
22if ~sn_has_product_form(sn)
23 line_error(mfilename,
'MVAC requires a product-form model.');
26 line_error(mfilename,
'MVAC supports closed models only; use method ''exact'' for open/mixed networks.');
29infSET =[]; % set of infinite server stations
30qSET =[]; % set of single-server fixed-rate stations
33 case SchedStrategy.EXT
35 case SchedStrategy.INF
36 infSET(1,end+1) = ist;
37 case {SchedStrategy.PS, SchedStrategy.LCFSPR, SchedStrategy.FCFS, SchedStrategy.SIRO}
40 line_error(mfilename, sprintf(
'MVAC does not support %s scheduling.',SchedStrategy.toText(sched(ist))));
43if any(nservers(qSET) ~= 1)
44 line_error(mfilename, 'MVAC supports single-server (SSFR) queues only; use method ''exact'' for multiserver stations.');
47Uchain = zeros(M,K); Tchain = zeros(M,K); C = zeros(1,K); Wchain = zeros(M,K); Qchain = zeros(M,K);
49% Zero-population chains carry no work; solve on the active set and re-expand.
50rset = setdiff(1:K,find(Nchain==0));
52Lq = STchain(qSET,:).*Vchain(qSET,:);
53Zq = STchain(infSET,:).*Vchain(infSET,:);
54[Xr,Qr] = pfqn_mvac(Lq(:,rset), Nchain(rset), sum(Zq(:,rset),1));
55Xchain = zeros(1,K); Xchain(rset) = Xr;
56Qchain(qSET,rset) = Qr;
57Qchain(infSET,:) = repmat(Xchain,numel(infSET),1) .* STchain(infSET,:) .* Vchain(infSET,:);
58lG = NaN; % MVAC forms no normalizing constant
60ccl = find(isfinite(Nchain));
63 Wchain(k,r) = STchain(k,r);
66 if isinf(nservers(k)) % infinite server
67 Wchain(k,r) = STchain(k,r);
69 if Vchain(k,r) == 0 || Xchain(r) == 0
72 Wchain(k,r) = Qchain(k,r) / (Xchain(r) * Vchain(k,r));
79 if sum(Wchain(:,r)) == 0
83 C(r) = Vchain(:,r)'*Wchain(:,r);
84 % X(r) remains constant
89 C(r) = Vchain(:,r)'*Wchain(:,r);
90 Xchain(r) = Nchain(r) / C(r);
95 Qchain(k,r) = Xchain(r) * Vchain(k,r) * Wchain(k,r);
96 Tchain(k,r) = Xchain(r) * Vchain(k,r);
102 if isinf(nservers(k)) % infinite server
103 Uchain(k,r) = Vchain(k,r)*STchain(k,r)*Xchain(r);
105 Uchain(k,r) = Vchain(k,r)*STchain(k,r)*Xchain(r)/nservers(k);
112 if Vchain(k,r)*STchain(k,r) > options.tol
114 case {SchedStrategy.FCFS,SchedStrategy.PS}
115 if sum(Uchain(k,:))>1+options.tol
116 Uchain(k,r) = min(1,sum(Uchain(k,:))) * Vchain(k,r)*STchain(k,r)*Xchain(r) / ((Vchain(k,:).*STchain(k,:))*Xchain(:));
123%Vsink = cellsum(sn.nodevisits);
124%Vsink = Vsink(find(sn.nodetype==NodeType.Sink),:);
125%
for r=find(isinf(Nchain)) % open classes
126 %Xchain(r) = Vsink(r) ./ STchain(refstatchain(r),r);
129Rchain = Qchain./Tchain;
130Xchain(~isfinite(Xchain))=0;
131Uchain(~isfinite(Uchain))=0;
132Qchain(~isfinite(Qchain))=0;
133Rchain(~isfinite(Rchain))=0;
136Uchain(:,Nchain==0)=0;
137Qchain(:,Nchain==0)=0;
138Rchain(:,Nchain==0)=0;
139Tchain(:,Nchain==0)=0;
140Wchain(:,Nchain==0)=0;
142[Q,U,R,T,C,X] = sn_deaggregate_chain_results(sn, Lchain, [], STchain, Vchain, alpha, [], [], Rchain, Tchain, [], Xchain);