LINE Solver
MATLAB API documentation
Loading...
Searching...
No Matches
me_oqn.m
1function [L, W, Ca, Cd, lambda, rho] = me_oqn(M, R, lambda0, Ca0, mu, Cs, P, options)
2%ME_OQN Maximum Entropy algorithm for Open Queueing Networks
3%
4% Implements the ME algorithm from Kouvatsos (1994) "Entropy Maximisation
5% and Queueing Network Models", Section 3.2.
6%
7% INPUTS:
8% M - Number of queues (stations)
9% R - Number of job classes
10% lambda0 - External arrival rates [M x R matrix], lambda0(i,r) = lambda_oi,r
11% Ca0 - External arrival scv [M x R matrix], Ca0(i,r) = Caoi,r
12% mu - Service rates [M x R matrix], mu(i,r) = μi,r
13% Cs - Service scv [M x R matrix], Cs(i,r) = Csi,r
14% P - Routing probability matrix [M x M x R], P(j,i,r) = pji,r
15% (probability class r goes from queue j to queue i)
16% options - (optional) struct with fields:
17% .tol - convergence tolerance (default: 1e-6)
18% .maxiter - maximum iterations (default: 1000)
19% .verbose - print iteration info (default: false)
20%
21% OUTPUTS:
22% L - Mean queue lengths [M x R matrix]
23% W - Mean waiting times [M x R matrix]
24% Ca - Arrival scv at each queue [M x R matrix]
25% Cd - Departure scv at each queue [M x R matrix]
26% lambda - Total arrival rates [M x R matrix]
27% rho - Utilizations [M x R matrix]
28%
29% Reference: Kouvatsos (1994), Equations 3.6 and 3.7
30
31% Handle optional arguments
32if nargin < 8
33 options = struct();
34end
35if ~isfield(options, 'tol')
36 options.tol = 1e-6;
37end
38if ~isfield(options, 'maxiter')
39 options.maxiter = 1000;
40end
41if ~isfield(options, 'verbose')
42 options.verbose = false;
43end
44
45% Step 1: Feedback correction
46% If pii,r > 0, apply feedback elimination transformation
47P_eff = P;
48mu_eff = mu;
49Cs_eff = Cs;
50for i = 1:M
51 for r = 1:R
52 pii = P(i, i, r);
53 if pii > 0
54 % Feedback correction: adjust service rate and scv
55 mu_eff(i, r) = mu(i, r) * (1 - pii);
56 % Adjusted service scv accounting for feedback
57 % Cs_eff = (Cs + pii*(1-pii)) / (1-pii)^2 simplified form
58 Cs_eff(i, r) = Cs(i, r) / (1 - pii) + pii / (1 - pii);
59 % Remove self-loop from routing
60 P_eff(i, i, r) = 0;
61 % Renormalize routing probabilities
62 row_sum = sum(P_eff(i, :, r));
63 if row_sum > 0
64 P_eff(i, :, r) = P_eff(i, :, r) / row_sum * (1 - pii);
65 end
66 end
67 end
68end
69
70% Step 2: Initialize arrival scv
71Ca = ones(M, R);
72
73% Step 3: Solve job flow balance equations using ORIGINAL P (including feedback)
74% lambda_i,r = lambda_oi,r + Σj lambda_j,r * pji,r
75% This is: lambda = lambda0 + P' * lambda (for each class)
76lambda = zeros(M, R);
77for r = 1:R
78 % Build the system (I - P') * lambda = lambda0
79 % where P' is the transpose of the routing matrix for class r
80 % Use ORIGINAL P to get correct effective arrival rates with feedback
81 Pr = squeeze(P(:, :, r))'; % P(j,i,r) -> need sum over j
82 A = eye(M) - Pr;
83 lambda(:, r) = A \ lambda0(:, r);
84end
85
86% Compute utilizations using ORIGINAL mu (not mu_eff)
87% mu_eff is only for variability calculations after feedback elimination
88rho = zeros(M, R);
89for i = 1:M
90 for r = 1:R
91 if mu(i, r) > 0
92 rho(i, r) = lambda(i, r) / mu(i, r);
93 end
94 end
95end
96
97% Check stability
98rho_total = sum(rho, 2);
99if any(rho_total >= 1)
100 warning('me_oqn:unstable', 'Network is unstable (utilization >= 1 at some queues)');
101end
102
103% Initialize outputs
104L = zeros(M, R);
105Cd = ones(M, R);
106
107% Step 4-5: Iterative computation of Ca, Cd, and L
108for iter = 1:options.maxiter
109 Ca_old = Ca;
110
111 % Step 4: Apply GE-type formulae for mean queue length
112 % For GE/GE/1 queue under ME principle:
113 % L = ρhat + ρhat^2(Ca + Cs) / (2(1 - ρhat))
114 for i = 1:M
115 rho_i = sum(rho(i, :)); % Total utilization at queue i
116 if rho_i > 0 && rho_i < 1
117 for r = 1:R
118 if rho(i, r) > 0
119 % Proportion of class r traffic
120 prop_r = rho(i, r) / rho_i;
121 % GE/GE/1 mean queue length formula (ME approximation)
122 % Aggregate Ca and Cs weighted by traffic
123 Ca_agg = Ca(i, r);
124 Cs_agg = Cs_eff(i, r);
125 L_total = rho_i + (rho_i^2 * (Ca_agg + Cs_agg)) / (2 * (1 - rho_i));
126 L(i, r) = prop_r * L_total;
127 end
128 end
129 end
130 end
131
132 % Step 5a: Compute departure scv using equation (3.6)
133 % Cdj,r = 2*Lj,r*(1 - ρhatj) + Caj,r*(1 - 2*ρhatj)
134 for j = 1:M
135 rho_j = sum(rho(j, :));
136 for r = 1:R
137 if lambda(j, r) > 0
138 Cd(j, r) = 2 * L(j, r) * (1 - rho_j) + Ca(j, r) * (1 - 2 * rho_j);
139 Cd(j, r) = max(0, Cd(j, r)); % Ensure non-negative
140 end
141 end
142 end
143
144 % Step 5b: Compute arrival scv using equation (3.7)
145 % Cai,r = -1 + {Σj (lambda_j,r*pji,r/lambda_i,r)*[Cdji,r + 1]^-1 + (lambda_oi,r/lambda_i,r)*[Caoi,r + 1]^-1}^-1
146 % where Cdji,r = 1 + pji,r*(Cdj,r - 1) (thinning)
147 for i = 1:M
148 for r = 1:R
149 if lambda(i, r) > 0
150 sum_inv = 0;
151
152 % Contribution from other queues
153 for j = 1:M
154 pji = P_eff(j, i, r);
155 if pji > 0 && lambda(j, r) > 0
156 % Thinning formula for departure scv after splitting
157 Cdji = 1 + pji * (Cd(j, r) - 1);
158 weight = (lambda(j, r) * pji) / lambda(i, r);
159 sum_inv = sum_inv + weight / (Cdji + 1);
160 end
161 end
162
163 % Contribution from external arrivals
164 if lambda0(i, r) > 0
165 weight0 = lambda0(i, r) / lambda(i, r);
166 sum_inv = sum_inv + weight0 / (Ca0(i, r) + 1);
167 end
168
169 % Compute new arrival scv
170 if sum_inv > 0
171 Ca(i, r) = -1 + 1 / sum_inv;
172 Ca(i, r) = max(0, Ca(i, r)); % Ensure non-negative
173 end
174 end
175 end
176 end
177
178 % Check convergence
179 delta = max(abs(Ca(:) - Ca_old(:)));
180 if options.verbose
181 fprintf('Iteration %d: max delta = %e\n', iter, delta);
182 end
183 if delta < options.tol
184 if options.verbose
185 fprintf('Converged after %d iterations\n', iter);
186 end
187 break;
188 end
189end
190
191if iter == options.maxiter && delta >= options.tol
192 warning('me_oqn:noconverge', 'Did not converge within %d iterations (delta=%e)', options.maxiter, delta);
193end
194
195% Step 6: Compute final statistics
196% Mean waiting time via Little's law: W = L / lambda_
197W = zeros(M, R);
198for i = 1:M
199 for r = 1:R
200 if lambda(i, r) > 0
201 W(i, r) = L(i, r) / lambda(i, r);
202 end
203 end
204end
205
206end