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;
27if ist > sn.nstations
28 line_error(mfilename,'Station number exceeds the number of stations in the model.');
29end
30if jobclass > sn.nclasses
31 line_error(mfilename,'Job class index exceeds the number of classes in the model.');
32end
33
34if isempty(self.result)
35 self.run;
36end
37
38N = sn.njobs;
39if all(isfinite(N))
40 switch self.options.method
41 case 'exact'
42 % Use MVALDMX to get exact marginalized probabilities
43 if ~all(sn.nservers == 1)
44 line_error(mfilename,'MVALDMX exact marginalized probabilities require single-server stations.');
45 end
46
47 lambda = sn.lambda;
48 D = sn.demands;
49 Z = diag(sn.think);
50 mu = sn.mu;
51 S = ones(sn.nstations, 1);
52
53 try
54 [~, ~, ~, ~, ~, Pc] = pfqn_mvaldmx(lambda, D, N, Z, mu, S);
55
56 % Extract marginal probabilities for the specific station and class
57 % Use the station probabilities from MVALDMX and marginalize for the specific class
58 Q = self.result.Avg.Q;
59 qVal = Q(ist, jobclass);
60 nVal = N(jobclass);
61
62 % Create probability vector for this class at this station using binomial approximation
63 Pmarg = zeros(1, nVal + 1);
64 logPmarg = zeros(1, nVal + 1);
65
66 for k = 0:nVal
67 % Binomial probability with mean qVal
68 logPk = nchoosekln(nVal, k) + k * log(qVal / nVal) + (nVal - k) * log(1 - qVal / nVal);
69 Pmarg(k + 1) = exp(logPk);
70 logPmarg(k + 1) = logPk;
71 end
72
73 % Filter based on state_m if provided
74 if ~isempty(state_m)
75 if max(state_m) > length(Pmarg) - 1
76 line_error(mfilename,'Requested state exceeds maximum population for this class.');
77 end
78 Pmarg = Pmarg(state_m + 1); % +1 for MATLAB indexing
79 logPmarg = logPmarg(state_m + 1);
80 end
81
82 catch ME
83 line_error(mfilename,'Failed to compute marginalized probabilities using MVALDMX: %s', ME.message);
84 end
85
86 otherwise
87 % Use binomial approximation similar to getProbAggr but for single class
88 Q = self.result.Avg.Q;
89 qVal = Q(ist, jobclass);
90 nVal = N(jobclass);
91
92 % Create probability vector for this class at this station
93 Pmarg = zeros(1, nVal + 1);
94 logPmarg = zeros(1, nVal + 1);
95
96 for k = 0:nVal
97 % Binomial probability with mean qVal
98 % Rainer Schmidt, "An approximate MVA ...", PEVA 29:245-254, 1997
99 logPk = nchoosekln(nVal, k) + k * log(qVal / nVal) + (nVal - k) * log(1 - qVal / nVal);
100 Pmarg(k + 1) = real(exp(logPk));
101 logPmarg(k + 1) = logPk;
102 end
103
104 % Filter based on state_m if provided
105 if ~isempty(state_m)
106 if max(state_m) > length(Pmarg) - 1
107 line_error(mfilename,'Requested state exceeds maximum population for this class.');
108 end
109 Pmarg = Pmarg(state_m + 1); % +1 for MATLAB indexing
110 logPmarg = logPmarg(state_m + 1);
111 end
112 end
113else
114 % Open class marginal probability
115 if isempty(self.result)
116 self.run;
117 end
118 U = self.result.Avg.U;
119 Q = self.result.Avg.Q;
120
121 if sn.sched(ist) == SchedStrategy.INF
122 % Delay (infinite server): Poisson distribution per class
123 % P(n) = exp(-Q) * Q^n / n!
124 lambda_mean = Q(ist, jobclass);
125 if isempty(state_m)
126 n_max = max(1, ceil(lambda_mean + 5*sqrt(max(lambda_mean, 1))));
127 state_m = 0:n_max;
128 end
129 Pmarg = zeros(1, length(state_m));
130 logPmarg = zeros(1, length(state_m));
131 for idx = 1:length(state_m)
132 n = state_m(idx);
133 if lambda_mean > 0
134 logP = n * log(lambda_mean) - lambda_mean - gammaln(n+1);
135 else
136 if n == 0
137 logP = 0;
138 else
139 logP = -Inf;
140 end
141 end
142 logPmarg(idx) = logP;
143 Pmarg(idx) = real(exp(logP));
144 end
145 elseif sn.sched(ist) ~= SchedStrategy.EXT
146 % Queue station: geometric-like marginal distribution
147 % For multiclass open product-form networks:
148 % P(n_r = k) = (1-rho) * rho_r^k / (1-rho+rho_r)^{k+1}
149 % where rho = sum_r U(ist,r), rho_r = U(ist,r)
150 rho_r = U(ist, jobclass);
151 rho_total = min(sum(U(ist, :), 'omitnan'), 1 - GlobalConstants.FineTol);
152 if isempty(state_m)
153 if rho_r > 0 && rho_total < 1
154 denom = 1 - rho_total + rho_r;
155 ratio = rho_r / denom;
156 if ratio > 0 && ratio < 1
157 n_max = max(1, ceil(-log(1e-10) / (-log(ratio))));
158 else
159 n_max = 0;
160 end
161 n_max = min(n_max, 1000);
162 else
163 n_max = 0;
164 end
165 state_m = 0:n_max;
166 end
167 Pmarg = zeros(1, length(state_m));
168 logPmarg = zeros(1, length(state_m));
169 if rho_total < 1 - GlobalConstants.FineTol
170 denom = 1 - rho_total + rho_r;
171 for idx = 1:length(state_m)
172 n = state_m(idx);
173 if rho_r > 0
174 logP = log(1 - rho_total) + n * log(rho_r) - (n+1) * log(denom);
175 else
176 if n == 0
177 logP = log(1 - rho_total) - log(denom);
178 else
179 logP = -Inf;
180 end
181 end
182 logPmarg(idx) = logP;
183 Pmarg(idx) = real(exp(logP));
184 end
185 else
186 logPmarg = -Inf * ones(1, length(state_m));
187 Pmarg = zeros(1, length(state_m));
188 end
189 else
190 % Source/External node: no probability distribution
191 Pmarg = 1;
192 logPmarg = 0;
193 end
194end
195end