1function dx = ode_pnorm(x, Phi, Mu, PH, M, K, enabled, q_indices, rt, Kic, nservers, w, sched_id, pstar)
2% DX = ODE_PNORM(X, PHI, MU, PH, M, K, ENABLED, Q_INDICES,
RT, KIC, NSERVERS, W, SCHED_ID, PSTAR)
4% ODE derivative function
using p-norm smoothing
for processor-share constraint.
5% Based on Ruuskanen et al., PEVA 151 (2021).
7% This provides a smoother approximation than softmin, improving ODE stability
10% @param pstar Smoothing parameter vector (one per station) or scalar
12% Copyright (c) 2012-2026, Imperial College London
17% If pstar
is scalar, expand to per-station
19 pstar = pstar * ones(M, 1);
23 p = pstar(i); % p-norm parameter
for this station
26 case SchedStrategy.INF
31 for kic = 1 : (Kic(i,c) - 1)
32 for kic_p = 1:Kic(i,c)
34 rate = PH{i}{c}{1}(kic,kic_p);
35 dx(xic+kic-1) = dx(xic+kic-1) - x(xic+kic-1)*rate;
36 dx(xic+kic_p-1) = dx(xic+kic_p-1) + x(xic+kic-1)*rate;
50 pie = map_pie(PH{j}{l});
51 if rt((i-1)*K+c,(j-1)*K+l) > 0
52 for kic = 1 : Kic(i,c)
53 for kjl = 1 : Kic(j,l)
55 rate = Phi{i}{c}(kic) * Mu{i}{c}(kic) * rt((i-1)*K+c,(j-1)*K+l) * pie(kjl);
56 dx(xic+kic-1) = dx(xic+kic-1) - x(xic+kic-1) * rate;
57 dx(xjl+kjl-1) = dx(xjl+kjl-1) + x(xic+kic-1) * rate;
68 case SchedStrategy.EXT
69 % Source node with external arrivals - p-norm smoothing not needed
70 % (arrivals are independent of queue state)
75 for kic = 1 : (Kic(i,c) - 1)
76 for kic_p = 1:Kic(i,c)
78 rate = PH{i}{c}{1}(kic,kic_p);
79 dx(xic+kic-1) = dx(xic+kic-1) - x(xic+kic-1)*rate;
80 dx(xic+kic_p-1) = dx(xic+kic_p-1) + x(xic+kic-1)*rate;
86 % Service completions (departures from source)
94 pie = map_pie(PH{j}{l});
95 if rt((i-1)*K+c,(j-1)*K+l) > 0
96 for kic = 1 : Kic(i,c)
97 for kjl = 1 : Kic(j,l)
99 rate = Phi{i}{c}(kic) * Mu{i}{c}(kic) * rt((i-1)*K+c,(j-1)*K+l) * pie(kjl);
100 dx(xic+kic-1) = dx(xic+kic-1) - x(xic+kic-1) * rate;
101 dx(xjl+kjl-1) = dx(xjl+kjl-1) + x(xic+kic-1) * rate;
112 case SchedStrategy.PS
113 idxIni = q_indices(i,1);
114 idxEnd = q_indices(i,K) + Kic(i,K) - 1;
115 ni = sum( x(idxIni:idxEnd) );
117 % Compute p-norm smooth factor: ghat = 1 / (1 + (ni/c)^p)^(1/p)
118 if ni > 0 && nservers(i) > 0
119 ghat = pnorm_smooth(ni, nservers(i), p);
127 xic = q_indices(i,c);
128 for kic = 1 : (Kic(i,c) - 1)
129 for kic_p = 1:Kic(i,c)
131 rate = PH{i}{c}{1}(kic,kic_p) * ghat;
132 dx(xic+kic-1) = dx(xic+kic-1) - x(xic+kic-1)*rate;
133 dx(xic+kic_p-1) = dx(xic+kic_p-1) + x(xic+kic-1)*rate;
139 % service completions
142 xic = q_indices(i,c);
145 xjl = q_indices(j,l);
147 pie = map_pie(PH{j}{l});
148 if rt((i-1)*K+c,(j-1)*K+l) > 0
149 for kic = 1 : Kic(i,c)
150 for kjl = 1 : Kic(j,l)
151 rate = Phi{i}{c}(kic) * Mu{i}{c}(kic) * rt((i-1)*K+c,(j-1)*K+l) * pie(kjl) * ghat;
152 dx(xic+kic-1) = dx(xic+kic-1) - x(xic+kic-1)*rate;
153 dx(xjl+kjl-1) = dx(xjl+kjl-1) + x(xic+kic-1)*rate;
163 case SchedStrategy.FCFS
164 idxIni = q_indices(i,1);
165 idxEnd = q_indices(i,K) + Kic(i,K) - 1;
166 ni = sum( x(idxIni:idxEnd) );
167 wni = GlobalConstants.FineTol;
169 for kic = 1 : Kic(i,c)
171 xic = q_indices(i,c);
172 w(c,kic) = -1/PH{i}{c}{1}(kic,kic);
173 wni = wni + w(c,kic)*x(xic + kic - 1);
178 % Compute p-norm smooth factor
179 if ni > 0 && nservers(i) > 0
180 ghat = pnorm_smooth(ni, nservers(i), p);
188 xic = q_indices(i,c);
189 for kic = 1 : (Kic(i,c) - 1)
190 for kic_p = 1:Kic(i,c)
192 rate = PH{i}{c}{1}(kic,kic_p) * ghat * w(c,kic) / wni;
193 dx(xic+kic-1) = dx(xic+kic-1) - x(xic+kic-1)*rate;
194 dx(xic+kic_p-1) = dx(xic+kic_p-1) + x(xic+kic-1)*rate;
200 % service completions
203 xic = q_indices(i,c);
206 xjl = q_indices(j,l);
208 pie = map_pie(PH{j}{l});
209 if rt((i-1)*K+c,(j-1)*K+l) > 0
210 for kic = 1 : Kic(i,c)
211 for kjl = 1 : Kic(j,l)
212 rate = Phi{i}{c}(kic) * Mu{i}{c}(kic) * rt((i-1)*K+c,(j-1)*K+l) * pie(kjl);
213 rate = rate * ghat * w(c,kic) / wni;
214 dx(xic+kic-1) = dx(xic+kic-1) - x(xic+kic-1)*rate;
215 dx(xjl+kjl-1) = dx(xjl+kjl-1) + x(xic+kic-1)*rate;
225 case SchedStrategy.DPS
226 w(i,:) = w(i,:)/sum(w(i,:));
227 % Compute weighted queue length
for rate normalization
228 wni = GlobalConstants.FineTol;
230 idxIni = q_indices(i,k);
231 idxEnd = q_indices(i,k) + Kic(i,k) - 1;
232 wni = wni + w(i,k) * sum(x(idxIni:idxEnd));
234 % Compute total queue length
for ghat
235 idxIni = q_indices(i,1);
236 idxEnd = q_indices(i,K) + Kic(i,K) - 1;
237 ni = sum( x(idxIni:idxEnd) );
239 % Compute p-norm smooth factor
using total queue length
240 if ni > 0 && nservers(i) > 0
241 ghat = pnorm_smooth(ni, nservers(i), p);
249 xic = q_indices(i,c);
250 for kic = 1 : (Kic(i,c) - 1)
251 for kic_p = 1:Kic(i,c)
253 rate = PH{i}{c}{1}(kic,kic_p) * ghat * w(i,c) / wni;
254 dx(xic+kic-1) = dx(xic+kic-1) - x(xic+kic-1)*rate;
255 dx(xic+kic_p-1) = dx(xic+kic_p-1) + x(xic+kic-1)*rate;
261 % service completions
264 xic = q_indices(i,c);
267 xjl = q_indices(j,l);
269 pie = map_pie(PH{j}{l});
270 if rt((i-1)*K+c,(j-1)*K+l) > 0
271 for kic = 1 : Kic(i,c)
272 for kjl = 1 : Kic(j,l)
273 rate = Phi{i}{c}(kic) * Mu{i}{c}(kic) * rt((i-1)*K+c,(j-1)*K+l) * pie(kjl);
274 rate = rate * ghat * w(i,c) / wni;
275 dx(xic+kic-1) = dx(xic+kic-1) - x(xic+kic-1)*rate;
276 dx(xjl+kjl-1) = dx(xjl+kjl-1) + x(xic+kic-1)*rate;