LINE Solver
MATLAB API documentation
Loading...
Searching...
No Matches
getProbMarg.m
1function [Pmarg, logPmarg] = getProbMarg(self, ist, jobclass, state_m)
2% [PMARG, LOGPMARG] = GETPROBMARG(IST, JOBCLASS, STATE_M)
3%
4% Probability distribution for queue length of a SINGLE class at a station.
5% Returns P(n jobs of class r) for n=0,1,...,N(r).
6%
7% Compare with getProbAggr: returns probability of a specific per-class
8% distribution, e.g., P(2 class-1, 1 class-2) as a scalar.
9%
10% Input:
11% ist - Station index
12% jobclass - Class index
13% state_m - (optional) Specific states to query, or [] for all
14%
15% Output:
16% Pmarg - Vector where Pmarg(n+1) = P(n jobs of this class)
17% logPmarg - Log probabilities for numerical stability
18
19if nargin < 3
20 line_error(mfilename,'getProbMarg requires station and job class parameters.');
21end
22if nargin < 4
23 state_m = [];
24end
25
26sn = self.getStruct;
27
28% Check if station index is valid
29if ist > sn.nstations
30 line_error(mfilename,'Station number exceeds the number of stations in the model.');
31end
32if jobclass > sn.nclasses
33 line_error(mfilename,'Job class index exceeds the number of classes in the model.');
34end
35
36% Check if this is a network (more than one queue station)
37queueStations = 0;
38for i=1:sn.nstations
39 if sn.nodetype(sn.stationToNode(i)) == NodeType.Queue
40 queueStations = queueStations + 1;
41 end
42end
43
44if queueStations > 1
45 line_error(mfilename,'getProbMarg is currently only supported for single queue models in SolverMAM.\nFor networks, this method is not yet implemented.');
46end
47
48% Check if the model has only one queue
49if queueStations == 0
50 line_error(mfilename,'Model does not contain any queue stations.');
51end
52
53% Ensure results are available
54if isempty(self.result)
55 self.run;
56end
57
58% Get model parameters needed for QBD solution
59K = sn.nclasses;
60N = sn.njobs';
61
62% Check if this is a closed model
63if all(isfinite(N))
64 % Closed model - compute probability distribution using QBD
65 maxLevel = sum(N(isfinite(N))) + 1;
66
67 % Build the arrival and service processes
68 PH = sn.proc;
69 pie = cell(1,K);
70 D0 = cell(1,K);
71
72 % Extract service process parameters
73 for k=1:K
74 PH{ist}{k} = map_scale(PH{ist}{k}, 1./sn.rates(ist,k)/sn.nservers(ist));
75 pie{k} = map_pie(PH{ist}{k});
76 D0{k} = PH{ist}{k}{1};
77 if any(isnan(D0{k}))
78 D0{k} = -GlobalConstants.Immediate;
79 pie{k} = 1;
80 end
81 end
82
83 % Build aggregate arrival process (approximation using throughput)
84 % This is a simplified approach - for closed networks we use the throughput
85 % to approximate the arrival process
86 T = self.result.Avg.T;
87 lambda_total = sum(T(ist,:));
88
89 if lambda_total < GlobalConstants.FineTol
90 % No traffic at this station
91 Pmarg = zeros(1, maxLevel);
92 Pmarg(1) = 1.0; % All probability at state 0
93 logPmarg = log(Pmarg);
94 logPmarg(Pmarg == 0) = -Inf;
95
96 if ~isempty(state_m)
97 if max(state_m) > length(Pmarg) - 1
98 line_error(mfilename,'Requested state exceeds maximum population.');
99 end
100 Pmarg = Pmarg(state_m + 1); % +1 for MATLAB indexing
101 logPmarg = logPmarg(state_m + 1);
102 end
103 return;
104 end
105
106 % Build a simple MMAP approximation based on class throughputs
107 D_approx = cell(1, K+1);
108 D_approx{1} = -lambda_total * eye(1); % D0
109 for k=1:K
110 D_approx{k+1} = T(ist,k) * ones(1,1); % Dk - arrivals of class k
111 end
112
113 try
114 % Compute the queue length distribution using MMAPPH1FCFS
115 [pdistr] = MMAPPH1FCFS(D_approx, {pie{:}}, {D0{:}}, 'ncDistr', maxLevel);
116
117 % Extract distribution for the specific class
118 % This is an approximation: we extract the portion corresponding to this class
119 if jobclass <= K && N(jobclass) > 0
120 % Normalize and extract portion for this class
121 pdistr = abs(pdistr);
122 pdistr = pdistr / sum(pdistr);
123
124 % For the specific class, we approximate the marginal
125 % by assuming independence and using the class's share
126 class_share = N(jobclass) / sum(N);
127 max_class_level = N(jobclass) + 1;
128
129 Pmarg = zeros(1, max_class_level);
130 for n=0:N(jobclass)
131 if n+1 <= length(pdistr)
132 Pmarg(n+1) = pdistr(n+1);
133 end
134 end
135
136 % Renormalize
137 Pmarg = Pmarg / sum(Pmarg);
138 logPmarg = log(Pmarg);
139 logPmarg(Pmarg == 0) = -Inf;
140 else
141 line_error(mfilename,'Invalid class index or zero population for class.');
142 end
143
144 % Filter based on state_m if provided
145 if ~isempty(state_m)
146 if max(state_m) > length(Pmarg) - 1
147 line_error(mfilename,'Requested state exceeds maximum population for this class.');
148 end
149 Pmarg = Pmarg(state_m + 1); % +1 for MATLAB indexing
150 logPmarg = logPmarg(state_m + 1);
151 end
152
153 catch ME
154 line_error(mfilename,'Failed to compute marginalized probabilities: %s', ME.message);
155 end
156
157else
158 % Open model - compute probability distribution using MAM (MMAPPH1FCFS)
159
160 % Get model parameters
161 PH = sn.proc;
162 pie = cell(1, K);
163 D0 = cell(1, K);
164
165 % Extract service process parameters for the queue station
166 for k = 1:K
167 PH{ist}{k} = map_scale(PH{ist}{k}, 1./sn.rates(ist,k)/sn.nservers(ist));
168 pie{k} = map_pie(PH{ist}{k});
169 D0{k} = PH{ist}{k}{1};
170 if any(isnan(D0{k}))
171 D0{k} = -GlobalConstants.Immediate;
172 pie{k} = 1;
173 end
174 end
175
176 % Build the arrival process from source
177 % Find the source station (reference station for open classes)
178 nChains = sn.nchains;
179 V = cellsum(sn.visits);
180
181 % Get arrival process from source and build aggregate MMAP
182 refstat = sn.refstat(1); % Source station
183 PH_src = sn.proc{refstat};
184
185 % Build arrival process cell array: {D0, D1, D2, ...} for K classes
186 D_arr = cell(1, K + 1);
187
188 % Check if all arrivals are from a single source with simple MAPs
189 totalLambda = 0;
190 for k = 1:K
191 if ~isnan(PH_src{k}{1})
192 totalLambda = totalLambda + map_lambda(PH_src{k});
193 end
194 end
195
196 if totalLambda < GlobalConstants.FineTol
197 % No arrivals at this station
198 Pmarg = zeros(1, 100);
199 Pmarg(1) = 1.0;
200 logPmarg = log(Pmarg);
201 logPmarg(Pmarg == 0) = -Inf;
202 else
203 % Build the aggregate arrival MMAP
204 % For simple exponential arrivals, construct directly
205 arrMaps = cell(1, K);
206 for k = 1:K
207 if ~isnan(PH_src{k}{1})
208 arrMaps{k} = PH_src{k};
209 else
210 arrMaps{k} = map_exponential(Inf); % No arrivals
211 end
212 end
213
214 % Superpose all arrival processes
215 if K == 1
216 % Single class - use the arrival process directly
217 arrProcess = arrMaps{1};
218 D_arr{1} = arrProcess{1}; % D0
219 D_arr{2} = arrProcess{2}; % D1
220 else
221 % Multiple classes - superpose MAPs
222 superMAP = arrMaps{1};
223 for k = 2:K
224 superMAP = map_super({superMAP, arrMaps{k}});
225 end
226 % Build MMAP with class marking based on arrival rates
227 D_arr{1} = superMAP{1}; % D0
228 for k = 1:K
229 lambdaK = map_lambda(arrMaps{k});
230 D_arr{k + 1} = (lambdaK / totalLambda) * superMAP{2};
231 end
232 end
233
234 % Compute queue length distribution using MMAPPH1FCFS
235 maxLevel = 100; % Maximum queue length to compute
236 if ~isempty(self.options.cutoff) && isfinite(self.options.cutoff) && self.options.cutoff > 0
237 maxLevel = self.options.cutoff;
238 end
239
240 % Check stability
241 aggrUtil = 0;
242 for k = 1:K
243 lambdaK = map_lambda(arrMaps{k});
244 if ~isnan(sn.rates(ist, k)) && sn.rates(ist, k) > 0
245 aggrUtil = aggrUtil + lambdaK / (sn.rates(ist, k) * sn.nservers(ist));
246 end
247 end
248
249 if aggrUtil >= 1 - GlobalConstants.FineTol
250 line_warning(mfilename, 'System utilization %.2f%% is too high, distribution may be inaccurate.', aggrUtil * 100);
251 end
252
253 try
254 [pdistr] = MMAPPH1FCFS(D_arr, {pie{:}}, {D0{:}}, 'ncDistr', maxLevel);
255 pdistr = abs(pdistr);
256 pdistr = pdistr / sum(pdistr);
257
258 Pmarg = pdistr(:)';
259 logPmarg = log(Pmarg);
260 logPmarg(Pmarg == 0) = -Inf;
261 catch ME
262 line_error(mfilename, sprintf('Failed to compute queue length distribution: %s', ME.message));
263 end
264 end
265
266 % Filter based on state_m if provided
267 if ~isempty(state_m)
268 if max(state_m) > length(Pmarg) - 1
269 line_error(mfilename, 'Requested state exceeds maximum queue length.');
270 end
271 Pmarg = Pmarg(state_m + 1);
272 logPmarg = logPmarg(state_m + 1);
273 end
274end
275
276end