85 const std::size_t R =
sn.nclasses;
89 for (std::size_t j = 0; j < st.
lldscaling.size(); ++j)
92 const auto rit =
sn.retrialparam.find(ist);
93 if (rit !=
sn.retrialparam.end())
94 for (std::size_t r = 0; r < rit->second.retrial_proc.size(); ++r)
95 if (!rit->second.retrial_proc[r].disabled) retrial =
true;
96 bool balk =
false, reneg =
false, immf =
false, reply =
false, par =
false, rr =
false,
98 for (std::size_t r = 0; r < st.
balking.size(); ++r)
100 for (std::size_t r = 0; r < st.
impatience.size(); ++r)
102 if (
sn.immfeed.size() >= ist)
103 for (std::size_t r = 0; r <
sn.immfeed[ist - 1].size(); ++r)
104 if (
sn.immfeed[ist - 1][r]) immf =
true;
105 if (
sn.replyblock.size() >= ind)
106 for (std::size_t r = 0; r <
sn.replyblock[ind - 1].size(); ++r)
107 if (
sn.replyblock[ind - 1][r]) reply =
true;
110 const std::vector<lang::RoutingStrategy>& rt =
sn.nodes[ind - 1].routing;
111 for (std::size_t r = 0; r < rt.size(); ++r)
114 for (std::size_t s = 0; s <
sn.issignal.size() && s < R && !sig; ++s) {
115 if (!
sn.issignal[s])
continue;
116 const std::size_t col = (ind - 1) * R + s;
117 for (std::size_t i = 0; i <
sn.rtnodes.rows() && col <
sn.rtnodes.cols(); ++i)
120 if (lld) why =
"load-dependent service";
121 else if (st.
cdscaling) why =
"class-dependent service";
122 else if (st.
jdscaling) why =
"joint-dependent service";
123 else if (
static_cast<bool>(
sn.gdscaling)) why =
"global dependence";
124 else if (
sn.breakdownparam.count(ist)) why =
"server breakdowns";
125 else if (retrial) why =
"retrial";
126 else if (balk) why =
"balking";
127 else if (reneg) why =
"reneging";
128 else if (
sn.isbasblocking.size() >= ind &&
sn.isbasblocking[ind - 1]) why =
"BAS blocking";
129 else if (immf) why =
"immediate feedback";
130 else if (reply) why =
"synchronous calls";
131 else if (par) why =
"server parallelism";
132 else if (rr) why =
"round-robin routing";
133 else if (sig) why =
"signals";
135 throw UnsupportedError(
ErrorKind{
"HeteroServers"},
"SolverCTMC does not combine heterogeneous server pools with " + why +
136 " (station '" +
sn.nodes[ind - 1].name +
"').");
142 const std::size_t R =
sn.nclasses;
144 const std::string& name =
sn.nodes[ind - 1].name;
155 "SolverCTMC supports heterogeneous server pools under FCFS, HOL, FCFSPRIO, LCFS, "
156 "LCFSPRIO and SIRO; station '" + name +
"' uses " +
160 if (
sn.nvars_of(ind) > 0)
162 "Station '" + name +
"' combines heterogeneous server pools with another feature that "
163 "owns a local variable (polling, BAS blocking, breakdown, a modulated process); "
164 "SolverCTMC cannot represent both.");
168 pool.count.assign(NT, 0.0);
169 pool.compat.assign(NT, std::vector<bool>(R,
false));
170 for (std::size_t t = 0; t < NT; ++t) {
172 const std::vector<bool>& c = st.
server_types[t].compatible;
173 for (std::size_t r = 0; r < R; ++r) pool.compat[t][r] = c.empty() || (r < c.size() && c[r]);
175 pool.pools.assign(R, std::vector<std::size_t>());
176 pool.off.assign(R, std::vector<std::size_t>());
177 pool.len.assign(R, std::vector<std::size_t>());
178 pool.alpha.assign(R, std::vector<std::vector<T>>());
179 pool.exit.assign(R, std::vector<std::vector<T>>());
180 pool.D0.assign(R, std::vector<
Matrix<T>>());
181 pool.fsfrate.assign(NT, std::vector<double>(R, 0.0));
183 for (std::size_t r = 0; r < R; ++r) {
186 bool hasPoolLaw =
false;
187 for (std::size_t t = 0; t < NT; ++t) {
188 const std::vector<lang::Distrib<T>>& sv = st.
server_types[t].service;
189 hasPoolLaw = hasPoolLaw || (pool.compat[t][r] && r < sv.size() && !sv[r].disabled);
191 if (!baseOk && !hasPoolLaw)
continue;
192 for (std::size_t t = 0; t < NT; ++t)
193 if (pool.compat[t][r]) pool.pools[r].push_back(t + 1);
194 const std::string& cname =
sn.classes[r].name;
195 if (pool.pools[r].empty())
197 "' declares no server pool compatible with class '" + cname +
198 "', so a job of that class would wait forever.");
202 require_ph(base, basemap, name, cname,
"its default service");
204 std::vector<mam::Map<T>> blocks;
205 std::size_t shift = 0;
206 for (std::size_t k = 0; k < pool.pools[r].size(); ++k) {
207 const std::size_t t = pool.pools[r][k];
208 const std::vector<lang::Distrib<T>>& sv = st.
server_types[t - 1].service;
210 if (r < sv.size() && !sv[r].disabled) {
216 "Server pool '" + st.
server_types[t - 1].name +
"' of station '" + name +
217 "' accepts class '" + cname +
"' but declares no law for it, and the "
218 "station's own service for the class is disabled.");
221 const std::size_t n = law.
D0.rows();
224 for (std::size_t j = 0; j < n; ++j) as += a[j];
225 for (std::size_t j = 0; j < n; ++j) a[j] = T(a[j] / as);
226 std::vector<T> ex(n, zero);
227 for (std::size_t i = 0; i < n; ++i)
228 for (std::size_t j = 0; j < n; ++j) ex[i] -= law.
D0(i, j);
229 pool.off[r].push_back(shift);
230 pool.len[r].push_back(n);
231 pool.alpha[r].push_back(a);
232 pool.exit[r].push_back(ex);
233 pool.D0[r].push_back(law.
D0);
235 blocks.push_back(law);
238 Matrix<T> D0x(shift, shift, zero), D1x(shift, shift, zero);
239 std::vector<T> exx(shift, zero);
240 for (std::size_t k = 0; k < blocks.size(); ++k) {
241 const std::size_t o = pool.off[r][k];
242 for (std::size_t i = 0; i < pool.len[r][k]; ++i) {
243 exx[o + i] = pool.exit[r][k][i];
244 for (std::size_t j = 0; j < pool.len[r][k]; ++j) D0x(o + i, o + j) = blocks[k].D0(i, j);
249 for (std::size_t i = 0; i < shift; ++i)
250 for (std::size_t j = 0; j < pool.len[r][0]; ++j) D1x(i, j) = T(exx[i] * pool.alpha[r][0][j]);
257 sn.service[ist - 1][r] = d;
258 if (
sn.disabled.size() >= ist &&
sn.disabled[ist - 1].size() > r)
sn.disabled[ist - 1][r] =
false;
260 std::vector<std::size_t> ncls(NT, 0);
261 for (std::size_t t = 0; t < NT; ++t)
262 for (std::size_t r = 0; r < R; ++r) ncls[t] += pool.compat[t][r] ? 1 : 0;
263 pool.alfsorder.resize(NT);
264 for (std::size_t t = 0; t < NT; ++t) pool.alfsorder[t] = t + 1;
265 std::stable_sort(pool.alfsorder.begin(), pool.alfsorder.end(),
266 [&](std::size_t a, std::size_t b) { return ncls[a - 1] < ncls[b - 1]; });
268 for (std::size_t r = 0; r < R; ++r) multi = multi || pool.pools[r].size() >= 2;
272 std::vector<std::size_t> p(NT);
273 for (std::size_t t = 0; t < NT; ++t) p[t] = t + 1;
275 pool.perms.push_back(p);
276 }
while (std::next_permutation(p.begin(), p.end()));
277 sn.nvars[ind - 1][2 * R] = 1;
280 for (std::size_t t = 0; t < NT; ++t) total += pool.count[t];
282 sn.ctmcpool[ind] = pool;