1function [Q,U,R,T,C,X,lG] = solver_mva(sn,options)
2% [Q,U,R,T,C,X,LG] = SOLVER_MVA(SN,OPTIONS)
4% Copyright (c) 2012-2026, Imperial College London
8 options = SolverMVA.defaultOptions;
11[Lchain,STchain,Vchain,alpha,Nchain,~,refstatchain] = sn_get_demands_chain(sn);
13nservers = sn.nservers;
18if ~sn_has_product_form(sn)
19 line_error(mfilename,
'Unsupported exact MVA analysis, the model does not have a product form');
22% Check
for special LCFS + LCFS-PR 2-station network
23lcfsStat = find(sched == SchedStrategy.LCFS);
24lcfsprStat = find(sched == SchedStrategy.LCFSPR);
25if ~isempty(lcfsStat) && ~isempty(lcfsprStat)
26 % Validate LCFS network topology
27 if length(lcfsStat) ~= 1 || length(lcfsprStat) ~= 1
28 line_error(mfilename,
'LCFS MVA requires exactly one LCFS and one LCFS-PR station.');
31 line_error(mfilename,
'LCFS MVA requires a closed queueing network.');
33 % Check
for self-loops in routing matrix
35 nclasses = sn.nclasses;
36 for ist = [lcfsStat, lcfsprStat]
38 if rt((ist-1)*nclasses+r, (ist-1)*nclasses+r) > 0
39 line_error(mfilename,
'LCFS MVA does not support self-loops at stations.');
43 % Call specialized LCFS MVA solver
44 [Q,U,R,T,C,X,lG] = solver_mva_lcfsqn(sn, options, lcfsStat, lcfsprStat);
46elseif ~isempty(lcfsStat)
47 % LCFS without LCFS-PR
is not supported
48 line_error(mfilename,
'LCFS scheduling requires a paired LCFS-PR station.');
51infSET =[]; % set of infinite server stations
52qSET =[]; % set of other product-form stations
55 case SchedStrategy.EXT
57 case SchedStrategy.INF
58 infSET(1,end+1) = ist;
59 case {SchedStrategy.PS, SchedStrategy.LCFSPR}
61 case {SchedStrategy.FCFS, SchedStrategy.SIRO}
64 line_error(mfilename, sprintf(
'Unsupported exact MVA analysis for %s scheduling.',SchedStrategy.toText(sched(ist))));
68Uchain = zeros(M,K); Tchain = zeros(M,K); C = zeros(1,K); Wchain = zeros(M,K); Qchain = zeros(M,K);
71ocl = find(isinf(Nchain));
74 lambda(r) = 1 ./ STchain(refstatchain(r),r);
75 Qchain(refstatchain(r),r) = Inf;
78rset = setdiff(1:K,find(Nchain==0));
80[Xchain,Qpf,Uchain,~,lG] = pfqn_mvams(lambda,STchain(qSET,:).*Vchain(qSET,:),Nchain,STchain(infSET,:).*Vchain(infSET,:),ones(length(qSET),1),nservers(qSET));
82Qchain(infSET,:) = repmat(Xchain,numel(infSET),1) .* STchain(infSET,:) .* Vchain(infSET,:);
84ccl = find(isfinite(Nchain));
87 Wchain(k,r) = STchain(k,r);
90 if isinf(nservers(k)) % infinite server
91 Wchain(k,r) = STchain(k,r);
93 if Vchain(k,r) == 0 || Xchain(r) == 0
96 Wchain(k,r) = Qchain(k,r) / (Xchain(r) * Vchain(k,r));
103 if sum(Wchain(:,r)) == 0
107 C(r) = Vchain(:,r)
'*Wchain(:,r);
108 % X(r) remains constant
113 C(r) = Vchain(:,r)'*Wchain(:,r);
114 Xchain(r) = Nchain(r) / C(r);
119 Qchain(k,r) = Xchain(r) * Vchain(k,r) * Wchain(k,r);
120 Tchain(k,r) = Xchain(r) * Vchain(k,r);
126 if isinf(nservers(k)) % infinite server
127 Uchain(k,r) = Vchain(k,r)*STchain(k,r)*Xchain(r);
129 Uchain(k,r) = Vchain(k,r)*STchain(k,r)*Xchain(r)/nservers(k);
136 if Vchain(k,r)*STchain(k,r) > options.tol
138 case {SchedStrategy.FCFS,SchedStrategy.PS}
139 if sum(Uchain(k,:))>1+options.tol
140 Uchain(k,r) = min(1,sum(Uchain(k,:))) * Vchain(k,r)*STchain(k,r)*Xchain(r) / ((Vchain(k,:).*STchain(k,:))*Xchain(:));
147%Vsink = cellsum(sn.nodevisits);
148%Vsink = Vsink(find(sn.nodetype==NodeType.Sink),:);
149%
for r=find(isinf(Nchain)) % open
classes
150 %Xchain(r) = Vsink(r) ./ STchain(refstatchain(r),r);
153Rchain = Qchain./Tchain;
154Xchain(~isfinite(Xchain))=0;
155Uchain(~isfinite(Uchain))=0;
156Qchain(~isfinite(Qchain))=0;
157Rchain(~isfinite(Rchain))=0;
160Uchain(:,Nchain==0)=0;
161Qchain(:,Nchain==0)=0;
162Rchain(:,Nchain==0)=0;
163Tchain(:,Nchain==0)=0;
164Wchain(:,Nchain==0)=0;
166[Q,U,R,T,C,X] = sn_deaggregate_chain_results(sn, Lchain, [], STchain, Vchain, alpha, [], [], Rchain, Tchain, [], Xchain);