1function [Q,U,R,T,C,X,lG,runtime,iter,method] = solver_mva_analyzer(sn, options)
2% [Q,U,R,T,C,X,LG,RUNTIME] = SOLVER_MVA_ANALYZER(QN, OPTIONS)
4% Copyright (c) 2012-2026, Imperial College London
9method = options.method;
10method = regexprep(method,
'^amva\.',
'');
12line_debug(options,
'MVA analyzer starting: method=%s, nclasses=%d, njobs=%s, nchains=%d', method, sn.nclasses, mat2str(sn.njobs), sn.nchains);
16 line_debug(options,
'Using exact MVA method, calling solver_mva');
17 [Q,U,R,T,C,X,lG] = solver_mva(sn, options);
19 line_debug(options,
'Using BAS method, calling solver_sqd');
20 [Q,U,R,T,C,X,lG,iter] = solver_sqd(sn, options);
22 line_debug(options,
'Using QNA method, calling solver_qna');
23 [Q,U,R,T,C,X] = solver_qna(sn, options);
26 line_debug(options,
'Using summation method, calling solver_mva_sum');
27 [Q,U,R,T,C,X,lG,iter] = solver_mva_sum(sn, options);
29 line_debug(options,
'Using RQNA method, calling solver_rqna');
30 [Q,U,R,T,C,X] = solver_rqna(sn, options);
33 %
for non-exponential open queueing networks, use qna
34 % (commented as not ready yet, it fails on example_cacheModel_3.m)
35 %
if all(isinf(sn.njobs)) && any(any(sn.scv ~= 1.0))
36 % line_warning(mfilename,
'QNA implementation is still in beta version.')
37 % [Q,U,R,T,C,X] = solver_qna(sn, options);
40 % Bursty single-
class open network:
the arrival process
is non-renewal
41 % (MMPP/MAP), whose autocorrelation a two-moment method cannot capture.
42 % Dispatch
the robust queueing network analyzer (RQNA), which
43 % characterizes each flow by its index of dispersion for counts.
44 if sn.nclasses == 1 && all(isinf(sn.njobs)) && sn_has_bursty_arrival(sn)
45 line_debug('Default method: bursty single-class open network, using RQNA\n');
46 line_debug(options, 'Non-renewal arrivals detected, calling solver_rqna');
47 [Q,U,R,T,C,X] = solver_rqna(sn, options);
50 % Closed single-chain Blocking-After-Service network (finite buffers)
52 line_debug('Default method: using BAS for blocking-after-service model\n');
53 line_debug(options, 'Model has Blocking-After-Service finite buffers, calling solver_sqd');
54 [Q,U,R,T,C,X,lG,iter] = solver_sqd(sn, options);
56 % Force AMVA for class-dependent models - exact MVA doesn't support them
57 elseif ~isempty(sn.cdscaling)
58 line_debug('Default method: using AMVA for class-dependent model\n');
59 line_debug(options, 'Model has class dependence, calling solver_amva');
60 [Q,U,R,T,C,X,lG,iter,method] = solver_amva(sn, options);
61 elseif any(isinf(sn.njobs)) && any(isfinite(sn.njobs) & sn.njobs > 0) && max(sn.nservers(isfinite(sn.nservers))) == 1 && sn_has_product_form(sn) && all(sn.njobs(isfinite(sn.njobs)) == floor(sn.njobs(isfinite(sn.njobs))))
62 % Mixed open+closed product-form single-server model: exact BCMP
63 % mixed MVA (pfqn_mvamx via solver_mva). The AMVA linearizer inflates
64 %
the closed-class response time by double-counting
the open-class
65 % interference. Only
the finite (closed) populations need to be
66 % integral (isinf fails the fractional-population test spuriously).
67 line_debug('Default method: using exact mixed MVA\n');
68 [Q,U,R,T,C,X,lG] = solver_mva(sn, options);
70 elseif sn.nchains <= 4 && sum(sn.njobs) <= 20 && sn_has_product_form(sn) && ~sn_has_fractional_populations(sn)
71 line_debug('Default method: using exact MVA\n');
72 % The parameters above take in the worst case a handful of ms
73 line_debug(options, 'Model qualifies for exact MVA (nchains=%d, njobs=%d, product-form=%d), calling solver_mva', sn.nchains, sum(sn.njobs), sn_has_product_form(sn));
74 [Q,U,R,T,C,X,lG] = solver_mva(sn, options);
77 line_debug('Default method: using approximate MVA\n');
78 line_debug(options, 'Model requires approximation (nchains=%d, njobs=%d, product-form=%d), calling solver_amva', sn.nchains, sum(sn.njobs), sn_has_product_form(sn));
79 [Q,U,R,T,C,X,lG,iter,method] = solver_amva(sn, options);
82 case {'amva','bs','qd','qli','fli','lin','qdlin','sqni','egflin','gflin','ab','schmidt','schmidt-ext'} %,'aql','qdaql'
83 line_debug(options, 'Using approximate MVA method: %s, calling solver_amva', method);
84 [Q,U,R,T,C,X,lG,iter] = solver_amva(sn, options);
95 line_warning(mfilename,'Unsupported SolverMVA method.');
101 %line_printf('\nMVA analysis completed. Runtime: %f seconds.\n',runtime);
106function tf = isBasModel(sn)
107% Detect a closed single-chain network with Blocking-After-Service (BAS) finite-buffer
108% blocking, which solver_sqd handles but exact/AMVA MVA does not.
110if sn.nchains ~= 1 || sn.nclosedjobs <= 0 || isempty(sn.droprule)
113if any(isinf(sn.njobs))
114 return; % open class present
116tf = any(sn.droprule(:) == DropStrategy.BAS);