125 const std::vector<std::size_t>& subsetIndices,
130 const std::size_t M =
sn.nstations, K =
sn.nclasses;
135 std::vector<std::size_t> complementIndices;
136 for (std::size_t i = 1; i <= M; ++i) {
137 bool inSubset =
false;
138 for (std::size_t a = 0; a < subsetIndices.size(); ++a)
139 if (subsetIndices[a] == i) inSubset =
true;
140 if (!inSubset) complementIndices.push_back(i);
143 const std::vector<double> N =
sn.njobs();
144 std::vector<int> cutoffs = options.cutoffs;
146 for (std::size_t r = 0; r < K; ++r) cutoffs.push_back(
static_cast<int>(N[r]));
147 if (cutoffs.size() != K)
148 throw InputError(
"aggregateFES: cutoffs must carry one entry per class");
153 std::vector<std::size_t> subsetRt, complementRt;
154 for (std::size_t a = 0; a < subsetIndices.size(); ++a) {
155 const std::size_t isf =
sn.stateful_of_station(subsetIndices[a]);
156 for (std::size_t r = 0; r < K; ++r) subsetRt.push_back((isf - 1) * K + r);
158 for (std::size_t a = 0; a < complementIndices.size(); ++a) {
159 const std::size_t isf =
sn.stateful_of_station(complementIndices[a]);
160 for (std::size_t r = 0; r < K; ++r) complementRt.push_back((isf - 1) * K + r);
166 const std::size_t nSub = subsetIndices.size();
168 std::vector<int> mi(nSub, 1);
169 std::vector<bool> isDelay(nSub,
false);
170 for (std::size_t a = 0; a < nSub; ++a) {
172 for (std::size_t r = 0; r < K; ++r) subRates(a, r) =
sn.rates(subsetIndices[a] - 1, r);
173 isDelay[a] = (st.
nodetype == qn::NodeType::Delay || st.
sched == SchedStrategy::INF);
177 std::vector<std::vector<T>> scalingTable =
184 std::vector<T> escape(K, zero);
185 for (std::size_t r = 0; r < K; ++r) {
186 for (std::size_t a = 0; a < nSub; ++a) {
187 const std::size_t j = subsetIndices[a];
188 const T Vjr = T(iso.
L(a, r) *
sn.rates(j - 1, r));
189 const std::size_t isf_j =
sn.stateful_of_station(j);
191 for (std::size_t b = 0; b < complementIndices.size(); ++b) {
192 const std::size_t isf_i =
sn.stateful_of_station(complementIndices[b]);
193 pexit +=
sn.rt((isf_j - 1) * K + r, (isf_i - 1) * K + r);
198 for (std::size_t idx = 0; idx < scalingTable[r].size(); ++idx)
199 scalingTable[r][idx] *= escape[r];
206 std::vector<std::size_t> complementNode(M + 1, 0);
207 for (std::size_t b = 0; b < complementIndices.size(); ++b) {
208 const std::size_t i = complementIndices[b];
211 if (st.
nodetype == qn::NodeType::Delay) {
213 }
else if (st.
nodetype == qn::NodeType::Queue) {
216 if (st.
cap > 0.0 && std::isfinite(st.
cap))
219 throw InputError(
"aggregateFES: unsupported station type in the complement");
221 complementNode[i] = nd;
223 const std::size_t fesNode = fesModel.
add_queue(
"FES", SchedStrategy::PS);
229 const std::size_t refNode =
230 complementIndices.empty() ? fesNode : complementNode[complementIndices[0]];
231 std::vector<std::size_t> newClass(K, 0);
232 for (std::size_t r = 0; r < K; ++r)
237 for (std::size_t b = 0; b < complementIndices.size(); ++b) {
238 const std::size_t i = complementIndices[b];
239 for (std::size_t r = 0; r < K; ++r)
240 fesModel.
set_service(complementNode[i], newClass[r],
sn.service[i - 1][r]);
244 for (std::size_t r = 0; r < K; ++r)
250 for (std::size_t r = 0; r < K; ++r)
251 for (std::size_t idx = 0; idx < scalingTable[r].size(); ++idx)
253 scalingTable[r][idx] = floorVal;
261 const CdScaling<T> cd = [beta](
const std::vector<T>& n) {
262 std::vector<int> ni(n.size(), 0);
263 for (std::size_t r = 0; r < n.size(); ++r)
271 for (std::size_t r = 0; r < K; ++r) {
272 const std::size_t I = complementIndices.size() + 1;
273 std::vector<std::vector<T>> Pk(I + 1, std::vector<T>(I + 1, zero));
275 for (std::size_t b = 0; b < complementIndices.size(); ++b) {
276 const std::size_t i = complementIndices[b];
277 const std::size_t iNode = complementNode[i];
278 const std::size_t isf_i =
sn.stateful_of_station(i);
282 for (std::size_t c = 0; c < complementIndices.size(); ++c) {
283 const std::size_t j = complementIndices[c];
284 const std::size_t isf_j =
sn.stateful_of_station(j);
285 const T p =
sn.rt((isf_i - 1) * K + r, (isf_j - 1) * K + r);
289 for (std::size_t a = 0; a < nSub; ++a) {
290 const std::size_t isf_j =
sn.stateful_of_station(subsetIndices[a]);
291 const T p =
sn.rt((isf_i - 1) * K + r, (isf_j - 1) * K + r);
299 for (std::size_t c = 0; c < complementIndices.size(); ++c) {
300 const std::size_t j = complementIndices[c];
301 const std::size_t isf_j =
sn.stateful_of_station(j);
303 for (std::size_t a = 0; a < nSub; ++a) {
304 const std::size_t isf_i =
sn.stateful_of_station(subsetIndices[a]);
305 probSum += T(iso.
visits(a, r) *
sn.rt((isf_i - 1) * K + r, (isf_j - 1) * K + r));
308 Pk[fesNode][complementNode[j]] = probSum;
313 for (std::size_t nd = 1; nd <= I; ++nd) {
315 for (std::size_t md = 1; md <= I; ++md) rowSum += Pk[nd][md];
317 for (std::size_t md = 1; md <= I; ++md) Pk[nd][md] /= rowSum;
319 for (std::size_t nd = 1; nd <= I; ++nd)
320 for (std::size_t md = 1; md <= I; ++md)
322 P.
set(newClass[r], newClass[r], nd, md, Pk[nd][md]);
328 out.
deagg.subsetIndices = subsetIndices;
329 out.
deagg.complementIndices = complementIndices;
330 out.
deagg.throughputTable = scalingTable;
331 out.
deagg.cutoffs = cutoffs;
332 out.
deagg.stochCompSubset = stochCompSubset;
333 out.
deagg.stochCompComplement = stochCompComplement;
334 out.
deagg.isolatedDemands = iso.
L;
336 out.
deagg.isolatedServers = mi;
337 out.
deagg.isolatedIsDelay = isDelay;
338 out.
deagg.escape = escape;
339 out.
deagg.fesNode = fesNode;