79 const std::size_t M =
sn.nstations, K =
sn.nclasses;
80 for (std::size_t r = 0; r < K; ++r)
81 if (!std::isfinite(
sn.classes[r].population))
83 "fluid diffusion: the method supports closed networks only; class '" +
84 sn.classes[r].name +
"' is open");
85 for (std::size_t i = 0; i < M; ++i) {
89 sn.stations[i].name +
"'); the method is for closed networks");
93 "fluid diffusion: scheduling at station '" +
sn.stations[i].name +
94 "' is outside the supported set {PS, FCFS, INF, SIRO}");
95 const double c =
sn.stations[i].nservers;
96 if (std::isfinite(c) && c > 1.0)
98 "fluid diffusion: only single-server or infinite-server stations are supported; "
99 "station '" +
sn.stations[i].name +
"' has more than one server");
104 std::vector<bool> inf_server(M,
false);
105 for (std::size_t i = 0; i < M; ++i) {
106 inf_server[i] = !std::isfinite(
sn.stations[i].nservers);
107 for (std::size_t r = 0; r < K; ++r) {
108 if (
sn.disabled[i][r] ||
sn.service[i][r].D0.rows() == 0)
continue;
110 if (rate > 0.0 && std::isfinite(rate)) mu(i, r) = rate;
115 const std::size_t S =
sn.nof_stateful();
116 std::vector<std::size_t> keep;
118 for (std::size_t i = 0; i < M; ++i) {
119 const std::size_t isf =
sn.stateful_of_station(i + 1) - 1;
120 for (std::size_t r = 0; r < K; ++r) keep.push_back(isf * K + r);
123 if (
sn.rt.rows() == S * K)
124 for (std::size_t a = 0; a < S * K; ++a)
125 for (std::size_t b = 0; b < S * K; ++b)
130 const std::size_t MK = M * K;
131 std::vector<std::size_t> asrc, adst;
132 std::vector<double> aprob;
133 for (std::size_t a = 0; a < MK; ++a)
134 for (std::size_t b = 0; b < MK; ++b)
135 if (a != b && P(a, b) > 0.0) {
138 aprob.push_back(P(a, b));
140 const std::size_t narc = asrc.size();
142 auto phi = [&](
const std::vector<double>& x, std::vector<double>& f) {
143 for (std::size_t i = 0; i < M; ++i) {
145 for (std::size_t r = 0; r < K; ++r) n += x[i * K + r];
146 const double den = inf_server[i] ? 1.0 : std::max(1.0, n);
147 for (std::size_t r = 0; r < K; ++r) f[i * K + r] = mu(i, r) * x[i * K + r] / den;
151 const double dt =
opt.dt > 0.0 ?
opt.dt : 0.01;
152 const std::size_t steps = std::max<std::size_t>(2,
opt.steps);
153 std::mt19937_64
rng(
opt.seed);
154 std::normal_distribution<double> gauss(0.0, 1.0);
157 std::vector<double> x(MK, 0.0), f(MK, 0.0);
158 for (std::size_t r = 0; r < K; ++r) {
160 for (std::size_t i = 0; i < M; ++i)
161 if (mu(i, r) > 0.0) ++nsv;
162 for (std::size_t i = 0; i < M; ++i)
163 if (mu(i, r) > 0.0) x[i * K + r] =
sn.classes[r].population /
static_cast<double>(nsv);
167 const std::size_t burn = steps / 2;
168 std::vector<double> qsum(MK, 0.0), fsum(MK, 0.0), gain(MK), loss(MK), xn(MK), theta(MK);
169 std::vector<std::size_t> loser(narc), gainer(narc);
170 std::vector<double> amt(narc);
171 for (std::size_t step = 1; step < steps; ++step) {
172 for (std::size_t e = 0; e < narc; ++e) {
173 const double fl = f[asrc[e]] * aprob[e] * dt;
174 const double inc = fl + std::sqrt(fl) * gauss(
rng);
176 loser[e] = inc > 0.0 ? asrc[e] : adst[e];
177 gainer[e] = inc > 0.0 ? adst[e] : asrc[e];
178 amt[e] = std::fabs(inc);
180 for (
int it = 0; it < 100; ++it) {
181 std::fill(gain.begin(), gain.end(), 0.0);
182 std::fill(loss.begin(), loss.end(), 0.0);
183 for (std::size_t e = 0; e < narc; ++e) {
184 gain[gainer[e]] += amt[e];
185 loss[loser[e]] += amt[e];
188 for (std::size_t a = 0; a < MK; ++a) {
189 xn[a] = x[a] + gain[a] - loss[a];
192 theta[a] = (x[a] + gain[a]) / loss[a];
197 for (std::size_t e = 0; e < narc; ++e) amt[e] *= theta[loser[e]];
199 for (std::size_t a = 0; a < MK; ++a) x[a] = std::max(xn[a], 0.0);
202 for (std::size_t a = 0; a < MK; ++a) {
207 const double navg =
static_cast<double>(steps - std::max<std::size_t>(burn, 1));
214 for (std::size_t a = 0; a < MK; ++a) out.
QN(a / K, a % K) = qsum[a] / navg;
217 for (std::size_t c = 0; c <
sn.nchains; ++c) {
219 auto vis = [&](std::size_t i, std::size_t r) {
222 bool found =
false, bfin =
false;
223 std::size_t bi = 0, br = 0;
225 for (std::size_t i = 0; i < M; ++i)
226 for (std::size_t r = 0; r < K; ++r) {
227 if (!
sn.chains[c][r] || mu(i, r) <= 0.0)
continue;
228 const double v = vis(i, r);
229 if (!(v > 0.0))
continue;
232 const bool fin = !inf_server[i];
233 const double D = v / mu(i, r);
234 if (!found || (fin && !bfin) || (fin == bfin && D > bD)) {
242 if (!found)
continue;
243 const double Xc = (fsum[bi * K + br] / navg) / vis(bi, br);
244 for (std::size_t i = 0; i < M; ++i)
245 for (std::size_t r = 0; r < K; ++r)
246 if (
sn.chains[c][r] && mu(i, r) > 0.0) out.
TN(i, r) = Xc * vis(i, r);
248 for (std::size_t i = 0; i < M; ++i)
249 for (std::size_t r = 0; r < K; ++r) {
250 out.
UN(i, r) = inf_server[i] ? out.
QN(i, r) : (mu(i, r) > 0.0 ? out.
TN(i, r) / mu(i, r) : 0.0);