4 % @brief Normalizing constant
for load-dependent closed networks.
10 % @brief Normalizing constant
for load-dependent closed networks.
11 % @fn pfqn_ncld(L, N, Z, mu, varargin)
12 % @param L Service demand matrix.
13 % @param N Population vector.
14 % @param Z Think time vector.
15 % @param mu Load-dependent rate matrix.
16 % @param varargin Optional solver parameters.
17 % @
return lG Logarithm of normalizing constant.
18 % @
return G Normalizing constant.
19 % @
return method Method used
for computation.
22function [lG,G,method] = pfqn_ncld(L,N,Z,mu,varargin)
23% [LGN,G,METHOD] = PFQN_NCLD(L,N,Z,VARARGIN)
25options = Solver.parseOptions(varargin, SolverNC.defaultOptions);
28method = options.method;
30% backup initial parameters
33% first remove empty classes
39% then scale demands in [0,1], importat that stays before the other
40% simplications in
case both D and Z are all very small or very large in a
41% given
class, in which
case the may look to filter but not
if all of them
42% are at the same scale
46 scalevec(r) = max([L(:,r);Z(:,r)]);
48L = L ./ repmat(scalevec,size(L,1),1);
51% remove stations with no demand
54demStations = find((Lmax./Lsum)>GlobalConstants.FineTol);
56mu = mu(demStations,:);
58%
if there
is a
class with jobs but with L and Z all zero
59if any(N((sum(L,1) + sum(Z,1)) == 0)>0)
60 line_warning(mfilename,'The model has no positive demands in any class.\n');
61 if isempty(Z) || sum(Z(:))<options.tol
64 lG = - sum(factln(N)) + sum(N.*log(sum(Z,1))) + N*log(scalevec)';
74% return immediately if the model
is a degenerate case
75if isempty(L) || sum(L(:))<options.tol % all demands are zero
76 if isempty(Z) || sum(Z(:))<options.tol
79 lG = - sum(factln(N)) + sum(N.*log(sum(Z,1))) + N*log(scalevec)';
82elseif M==1 && (isempty(Z) || sum(Z(:))<options.tol) % single node and no think time
83 lG = factln(sum(N)) - sum(factln(N)) + sum(N.*log(sum(L,1))) + N*log(scalevec)' - sum(log(mu(1:sum(N))));
87% determine contribution from jobs that permanently loop at delay
88zeroDemandClasses = find(sum(L,1)<options.tol); % all jobs in delay
89nonzeroDemandClasses = setdiff(1:R, zeroDemandClasses);
91if isempty(sum(Z,1)) || all(sum(Z(:,zeroDemandClasses),1)<options.tol)
95 if isempty(zeroDemandClasses) % for old MATLAB release compatibility
99 Nz = N(zeroDemandClasses);
100 lGzdem = - sum(factln(Nz)) + sum(Nz.*log(sum(Z(:,zeroDemandClasses),1))) + Nz*log(scalevec(zeroDemandClasses))';
103L = L(:,nonzeroDemandClasses);
104N = N(nonzeroDemandClasses);
105Z = Z(:,nonzeroDemandClasses);
106scalevecz = scalevec(nonzeroDemandClasses);
107% compute G for classes No with non-zero demand
111 [lGnnzdem,method] = compute_norm_const_ld(L, N, Z, mu, options);
113% scale back to original demands
114lG = lGnnzdem + lGzdem + N*log(scalevecz)';
118function [lG,method] = compute_norm_const_ld(L,N,Z,mu,options)
119% LG = COMPUTE_NORM_CONST_LD(L,N,Z,OPTIONS)
121method = options.method;
123 case {
'default',
'exact'}
124 % see _kb/03-api-layer.md (pfqn/ family: scaling, log-domain switches, dispatch gates)
125 clwMaxClasses = 5; %
class-count gate (clw cost
is exponential in R)
126 clwMaxPop = 200; % total-population cap (numerical validity; NaN onset ~450)
127 clwMaxCost = 2e7; % contour-point budget (~2s at ~1e7 pts/s; profiler)
128 clwPredCost = prod(2 * clw_lattice(R) .* N(:).
');
129 if strcmp(options.method,'default
') && M > 1 && R >= 2 ...
130 && R <= clwMaxClasses && sum(N) <= clwMaxPop ...
131 && clwPredCost <= clwMaxCost
132 [~,lG] = pfqn_clw_lld(L, N, sum(Z,1), mu, options);
135 if sum(Z(:))<GlobalConstants.FineTol
139 D = size(Z,1); % number of delays
141 muz = [mu; repmat(1:size(mu,2),D,1)];
144 [lG] = pfqn_gldsingle(Lz, N, muz, options);
145 method = 'exact/gld
';
146 elseif M==1 && any(Z>0)
147 [~,lG]= pfqn_comomrm_ld(L, N, Z, mu, options);
148 method = 'exact/comomld
';
149 elseif M==1 && max(Z(:)) < GlobalConstants.FineTol
150 % see _kb/03-api-layer.md (pfqn/ family: scaling, log-domain switches, dispatch gates)
151 [~,lG] = pfqn_comomrm_ld(L, N, 0*N, mu, options);
152 method = 'exact/comomld
';
154 [~,lG] = pfqn_gld(Lz, N, muz, options);
155 method = 'exact/gld
';
159 % Importance sampling for a load-dependent closed network: the
160 % sample-an-ordering estimator of pfqn_ld_is (the LD counterpart of
161 % pfqn_is / pfqn_oi_is / pfqn_pas_is).
162 [~,lG] = pfqn_ld_is(L,N,sum(Z,1),mu,options);
165 % Choudhury-Leung-Whitt generating-function inversion extended to
166 % limited load-dependent stations (Bertozzi-McKenna transforms); the
167 % delay term is passed as the aggregate IS demand sum(Z,1).
168 [~,lG] = pfqn_clw_lld(L, N, sum(Z,1), mu, options);
171 [lG] = pfqn_rd(L, N, Z, mu, options);
173 [lG] = pfqn_nrp(L, N, Z, mu, options);
175 [lG] = pfqn_nrl(L, N, Z, mu, options);
177 if M<=1 || sum(Z) < GlobalConstants.Zero
178 [~,lG]= pfqn_comomrm_ld(L, N, Z, mu, options);
180 line_warning(mfilename,'Load-dependent CoMoM
is available only in models with a delay and m identical stations, running the
''rd
'' algorithm instead.\n
');
181 [lG] = pfqn_rd(L, N, Z, mu, options);
185 line_error(mfilename,sprintf('Unrecognized method for solving load-dependent models: %s
',options.method));
190function l = clw_lattice(p)
191% Default CLW inner lattice parameters l_j (roundoff control): l_1=1,
192% l_2=l_3=2, l_j>=4 = 3. Used to predict the clw_lld contour-point cost.
195if p >= 2, l(2) = 2; end
196if p >= 3, l(3) = 2; end