LINE Solver
MATLAB API documentation
Loading...
Searching...
No Matches
getProbMarg.m
1function [Pmarg, logPmarg] = getProbMarg(self, node)
2% [PMARG, LOGPMARG] = GETPROBMARG(NODE)
3%
4% Probability distribution for TOTAL queue length at a station.
5% Returns P(n total jobs) for n=0,1,...,N, summing over all class combinations.
6%
7% Compare with getProbAggr: returns probability of a specific per-class
8% distribution, e.g., P(2 class-1, 1 class-2).
9%
10% Input:
11% node - Queue or node object
12%
13% Output:
14% Pmarg - Vector where Pmarg(n+1) = P(n total jobs at node)
15% logPmarg - Log probabilities for numerical stability
16
17if GlobalConstants.DummyMode
18 Pmarg = NaN;
19 logPmarg = NaN;
20 return
21end
22
23% Get network structure
24sn = self.getStruct;
25
26% Store original node parameter and convert to station index
27if isa(node, 'Node')
28 node_obj = node;
29 ist = sn.nodeToStation(node.index);
30else
31 % If given station index, need to find corresponding node
32 ist = node;
33 % Find node with this station index
34 for i = 1:length(sn.nodetype)
35 if sn.nodeToStation(i) == ist
36 node_obj = sn.nodes{i};
37 break;
38 end
39 end
40end
41
42% Get population and class information
43N = sn.njobs;
44if ~all(isfinite(N))
45 line_error(mfilename, 'getProbMarg not yet implemented for models with open classes.');
46end
47
48R = sn.nclasses; % Number of classes
49Ntotal = sum(N); % Total population
50
51% Fast path: comom method uses pfqn_procomom directly
52if strcmpi(self.options.method, 'comom')
53 M = sn.nstations;
54 C = sn.nchains;
55 nservers = sn.nservers;
56 [Lchain, ~, ~, ~, Nchain] = sn_get_demands_chain(sn);
57 Lchain(~isfinite(Lchain)) = 0;
58
59 % Separate queue vs delay stations (matching solver_nc.m lines 97-119)
60 Lms = zeros(M, C);
61 Ztotal = zeros(1, C);
62 Zms = zeros(1, C);
63 queueStations = [];
64 for i = 1:M
65 if isinf(nservers(i))
66 Ztotal = Ztotal + Lchain(i, :);
67 else
68 queueStations(end+1) = i; %#ok<AGROW>
69 Lms(i, :) = Lchain(i, :) / nservers(i);
70 Zms = Zms + Lchain(i, :) * (nservers(i)-1) / nservers(i);
71 end
72 end
73
74 L_queues = Lms(queueStations, :);
75 Z_total = Ztotal + Zms;
76
77 [Pr, ~] = pfqn_procomom(L_queues, Nchain, Z_total);
78
79 % Find which queue index corresponds to the requested station
80 queue_idx = find(queueStations == ist, 1);
81 if ~isempty(queue_idx)
82 sumNchain = sum(Nchain);
83 Pmarg = zeros(1, Ntotal + 1);
84 logPmarg = -Inf * ones(1, Ntotal + 1);
85 % Pr is (M_queues x sumNchain+1), map to output size
86 len = min(sumNchain + 1, Ntotal + 1);
87 Pmarg(1:len) = Pr(queue_idx, 1:len);
88 logPmarg(Pmarg > 0) = log(Pmarg(Pmarg > 0));
89 else
90 % Delay station: fall through to enumeration
91 line_warning(mfilename, 'comom method does not directly support delay stations, using enumeration.');
92 savedMethod = self.options.method;
93 self.options.method = 'default';
94 [Pmarg, logPmarg] = self.getProbMarg(node_obj);
95 self.options.method = savedMethod;
96 return
97 end
98 return
99end
100
101% Initialize output vectors
102Pmarg = zeros(1, Ntotal + 1);
103logPmarg = -Inf * ones(1, Ntotal + 1);
104
105% For each possible total queue length
106for n = 0:Ntotal
107 % Enumerate all ways to partition n jobs across R classes
108 % subject to constraint: n_r <= N(r) for each class
109 partitions = generate_partitions(n, R, N);
110
111 % Sum probabilities over all partitions
112 log_prob_n = -Inf;
113 for p = 1:size(partitions, 1)
114 state_vec = partitions(p, :);
115
116 % Get probability for this specific class distribution
117 % Note: getProbAggr already supports LD models via pfqn_ncld
118 % Gets unnormalized values (we normalize at the end)
119 prob = self.getProbAggr(node_obj, state_vec);
120
121 if prob > 0
122 log_p = log(prob);
123 % Log-sum-exp trick for numerical stability
124 if isinf(log_prob_n)
125 log_prob_n = log_p;
126 else
127 log_prob_n = log_prob_n + log(1 + exp(log_p - log_prob_n));
128 end
129 end
130 end
131
132 % Store results
133 if isfinite(log_prob_n)
134 Pmarg(n + 1) = exp(log_prob_n);
135 logPmarg(n + 1) = log_prob_n;
136 else
137 Pmarg(n + 1) = 0;
138 logPmarg(n + 1) = -Inf;
139 end
140end
141
142% Normalize to ensure probabilities sum to 1
143total_prob = sum(Pmarg);
144if total_prob > 0 && abs(total_prob - 1.0) > 1e-10
145 Pmarg = Pmarg / total_prob;
146 logPmarg = logPmarg - log(total_prob);
147end
148
149end
150
151function partitions = generate_partitions(n, R, N_max)
152% GENERATE_PARTITIONS Enumerate all ways to partition n into R non-negative integers
153%
154% @param n Total to partition
155% @param R Number of parts
156% @param N_max Maximum value for each part (vector of length R)
157% @return partitions Matrix where each row is a valid partition
158
159if R == 1
160 % Base case: single class
161 if n <= N_max(1)
162 partitions = n;
163 else
164 partitions = zeros(0, 1);
165 end
166 return
167end
168
169% Recursive case: try all possible values for first class
170partitions = [];
171for n1 = 0:min(n, N_max(1))
172 % Recursively partition remaining jobs across remaining classes
173 sub_partitions = generate_partitions(n - n1, R - 1, N_max(2:end));
174
175 if ~isempty(sub_partitions)
176 % Prepend n1 to each sub-partition
177 partitions = [partitions; n1 * ones(size(sub_partitions, 1), 1), sub_partitions];
178 end
179end
180
181end
Definition mmt.m:93