5#ifndef LINE_API_SN_SN_AGGREGATE_CHAINS_H
6#define LINE_API_SN_SN_AGGREGATE_CHAINS_H
119 std::vector<std::vector<std::size_t> >
inchain;
149 const std::string& suffix = std::string()) {
153 const std::size_t M =
sn.nstations, K =
sn.nclasses, C =
sn.nchains;
155 if (M == 0 || K == 0)
156 throw InputError(
"sn_aggregate_chains: the model has no stations or no classes");
157 if (C == 0 ||
sn.inchain.size() != C)
159 "sn_aggregate_chains: the model is not refreshed (it declares no chains); call "
160 "refresh_struct() or get_struct() first");
178 for (std::size_t i = 0; i < M && i < K; ++i) out.
alpha(i, i) = one;
180 out.
deagg.inchain =
sn.inchain;
181 out.
deagg.isaggregated =
false;
182 out.
deagg.nclasses = K;
183 out.
deagg.nchains = C;
185 for (std::size_t c = 0; c < C; ++c) out.
chainclass[c] = c + 1;
187 for (std::size_t i = 0; i < M; ++i) out.
stationnode[i] =
sn.station_to_node[i];
194 std::vector<bool> isOpenChain(C,
false);
195 std::vector<T> lambdaChain(C, zero);
196 for (std::size_t c = 0; c < C; ++c) {
197 const std::vector<std::size_t>& ic =
sn.inchain[c];
198 for (std::size_t a = 0; a < ic.size(); ++a)
199 if (!std::isfinite(
sn.classes[ic[a] - 1].population)) isOpenChain[c] =
true;
200 if (!isOpenChain[c] ||
sn.sourceIdx == 0)
continue;
203 for (std::size_t a = 0; a < ic.size(); ++a) {
204 const std::size_t rr = ic[a];
205 if (
sn.disabled[
sn.sourceIdx - 1][rr - 1])
continue;
207 if (std::isfinite(v)) lambdaChain[c] +=
sn.rates(
sn.sourceIdx - 1, rr - 1);
213 :
sn.name +
"_aggregated");
214 std::vector<std::size_t> nodeMap(
sn.nodes.size() + 1, 0);
215 std::size_t sourceNode = 0;
216 for (std::size_t i = 1; i <=
sn.nodes.size(); ++i) {
219 case qn::NodeType::Source:
221 sourceNode = nodeMap[i];
223 case qn::NodeType::Sink: nodeMap[i] = chainModel.
add_sink(nd.
name);
break;
224 case qn::NodeType::Delay: nodeMap[i] = chainModel.
add_delay(nd.
name);
break;
225 case qn::NodeType::Router: nodeMap[i] = chainModel.
add_router(nd.
name);
break;
226 case qn::NodeType::Queue: {
231 if (st.
cap > 0.0 && std::isfinite(st.
cap))
235 case qn::NodeType::ClassSwitch:
243 std::string(
"sn_aggregate_chains: node '") + nd.
name +
"' is a " +
245 ", which the chain aggregate cannot carry; the transform keeps Source, Sink, "
246 "Queue, Delay and Router and drops ClassSwitch");
250 std::vector<std::size_t> stationNode(M + 1, 0);
251 for (std::size_t i = 1; i <= M; ++i) stationNode[i] = nodeMap[
sn.station_to_node[i - 1]];
254 std::vector<std::size_t> chainClass(C, 0);
255 for (std::size_t c = 0; c < C; ++c) {
256 const std::vector<std::size_t>& ic =
sn.inchain[c];
257 std::string nm = (ic.size() == 1) ?
sn.classes[ic[0] - 1].name
258 : (std::string(
"Chain") + std::to_string(c + 1));
259 if (!suffix.empty()) nm += suffix;
260 if (isOpenChain[c]) {
264 if (refst == 0 || refst > M || stationNode[refst] == 0)
265 throw InputError(
"sn_aggregate_chains: the reference station of chain " +
266 std::to_string(c + 1) +
" is not carried by the aggregate");
272 for (std::size_t c = 0; c < C; ++c) {
273 if (!isOpenChain[c])
continue;
276 "sn_aggregate_chains: chain " + std::to_string(c + 1) +
277 " is open but the model carries no Source to attach its arrivals to");
284 for (std::size_t i = 1; i <= M; ++i) {
285 if (stationNode[i] == 0)
continue;
287 if (ty == qn::NodeType::Source || ty == qn::NodeType::Sink)
continue;
288 for (std::size_t c = 0; c < C; ++c) {
290 if (!(st > 0.0) || !std::isfinite(st)) {
293 chainModel.
set_service(stationNode[i], chainClass[c],
298 if (!std::isfinite(scv) || scv <= 0.0) scv = 1.0;
299 const T mean = dem.
STchain(i - 1, c);
301 if (std::fabs(scv - 1.0) < fineTol) {
303 }
else if (scv < 1.0) {
309 long k = std::lround(1.0 / scv);
345 chainModel.
set_service(stationNode[i], chainClass[c], d);
355 for (std::size_t c = 0; c < C; ++c) {
356 const std::vector<std::size_t>& ic =
sn.inchain[c];
358 chainModel.
raw_struct().nodes.size() + 1, zero);
359 for (std::size_t i = 1; i <= M; ++i) {
360 if (stationNode[i] == 0)
continue;
364 if (!isOpenChain[c] &&
365 (tyi == qn::NodeType::Source || tyi == qn::NodeType::Sink))
367 const std::size_t isf_i =
sn.stateful_of_station(i);
368 for (std::size_t j = 1; j <= M; ++j) {
369 if (stationNode[j] == 0)
continue;
370 const std::size_t isf_j =
sn.stateful_of_station(j);
372 for (std::size_t a = 0; a < ic.size(); ++a) {
373 const std::size_t k = ic[a];
375 for (std::size_t b = 0; b < ic.size(); ++b) {
376 const std::size_t s = ic[b];
377 const std::size_t from = (isf_i - 1) * K + k - 1;
378 const std::size_t to = (isf_j - 1) * K + s - 1;
379 if (from >=
sn.rt.rows() || to >=
sn.rt.cols())
continue;
380 const T p_ks =
sn.rt(from, to);
382 pij += T(dem.
alpha(i - 1, k - 1) * p_ks);
386 Pc(stationNode[i], stationNode[j]) = pij;
393 for (std::size_t a = 1; a < Pc.
rows(); ++a) {
395 for (std::size_t b = 1; b < Pc.
cols(); ++b) rowSum += Pc(a, b);
397 for (std::size_t b = 1; b < Pc.
cols(); ++b)
399 Pc(a, b) = T(Pc(a, b) / rowSum);
400 P.
set(chainClass[c], chainClass[c], a, b, Pc(a, b));
411 for (std::size_t i = 1; i <= M; ++i) out.
stationnode[i - 1] = stationNode[i];
418 out.
deagg.lambdachain = lambdaChain;
419 out.
deagg.isopenchain = isOpenChain;
420 out.
deagg.inchain =
sn.inchain;
421 out.
deagg.refstat.assign(K, 0);
422 for (std::size_t r = 0; r < K; ++r) out.
deagg.refstat[r] =
sn.classes[r].refstat;
424 out.
deagg.isaggregated =
true;
425 out.
deagg.nclasses = K;
426 out.
deagg.nchains = C;
UnsupportedError(const std::string &what)
A network plus its refreshed NetworkStruct.
A queueing network under construction.
std::size_t add_source(const std::string &nm)
The external arrival station.
std::size_t add_open_class(const std::string &nm, int prio=0)
An open class.
std::size_t add_delay(const std::string &nm)
An infinite-server station (a Delay, MATLAB's Delay / DelayStation).
std::size_t add_router(const std::string &nm)
A stateless routing node.
void set_number_of_servers(std::size_t node, double n)
queue.setNumberOfServers(n).
std::size_t add_queue(const std::string &nm, SchedStrategy sched=SchedStrategy::FCFS)
A queueing station.
std::size_t add_closed_class(const std::string &nm, double njobs, std::size_t refstat_node, int prio=0)
A closed class of the given population, referencing a station node.
std::size_t add_sink(const std::string &nm)
The external departure node.
void set_capacity(std::size_t node, double k)
station.setCapacity(k), the K of Kendall's notation.
NetworkStruct< T > & raw_struct()
The struct WITHOUT refreshing it, for a caller that is still building.
void link(const RoutingMatrix< T > &Pm)
model.link(P): install the routing.
void set_service(std::size_t node, std::size_t cls, const Distrib< T > &d)
station.setService(class, dist).
void set_arrival(std::size_t node, std::size_t cls, const Distrib< T > &d)
source.setArrival(class, dist): the same table, at the Source.
The routing matrix a model script fills in, MATLAB's P cell array.
void set(std::size_t r, std::size_t s, std::size_t i, std::size_t j, const T &p)
The moment fitters the reference distributions carry as STATIC FACTORIES: Erlang.fitMeanAndOrder,...
The exception types the port throws.
Enumerations and the minimal distribution descriptor shared by the model layer of the C++ port.
Dense matrix and non-owning view.
ChainAggregationResult< T > sn_aggregate_chains(const qn::NetworkStruct< T > &sn, const std::string &suffix=std::string())
Collapse every chain onto one class, port of ModelAdapter.aggregateChains.
const char * node_type_to_text(NodeType t)
Name of a node kind, for diagnostics.
Distrib< T > hyperexp_fit_mean_scv(const T &mean, const T &scv)
HyperExp.fitMeanAndSCV(MEAN, SCV), which is map_hyperexp at p = 0.99 read back as (p,...
NodeType
Node kinds, with the values of MATLAB NodeType.
ChainDemands< T > sn_get_demands_chain(const qn::NetworkStruct< T > &L)
Port of sn_get_demands_chain.
The Network constructor API: Queue, Delay, Source, Sink, Router, ClassSwitch, Cache,...
A queueing network and its refreshed NetworkStruct.
Number-type abstraction for the templated API port.
Chain aggregation and de-aggregation.
Everything needed to map a chain-level result back onto the classes.
Matrix< T > SCVchain
(M x C)
std::vector< double > Nchain
(C) population, infinite for an open chain
std::vector< std::vector< std::size_t > > inchain
(C) 1-based class indices
Matrix< T > Vchain
(M x C) chain visits
std::vector< std::size_t > refstat
(K) 1-based reference station
bool isaggregated
false when C == K and the model was merely copied
std::size_t nclasses
K of the ORIGINAL model.
std::vector< T > lambdachain
(C) aggregate arrival rate, 0 for a closed chain
Matrix< T > STchain
(M x C) chain mean service time
Matrix< T > alpha
(M x K) class share of its chain's visits at a station
std::vector< std::size_t > refstatchain
(C) 1-based reference station
Matrix< T > Lchain
(M x C) chain demand
std::size_t nchains
C, the class count of the aggregate.
std::vector< bool > isopenchain
(C)
What sn_aggregate_chains returns.
ChainAggregationDeagg< T > deagg
Matrix< T > alpha
(M x K), the same matrix as deagg.alpha
std::vector< std::size_t > stationnode
stationnode[i] is the aggregate's 1-based node for original station i+1, 0 if dropped.
ChainAggregationResult(const qn::Network< T > &m)
qn::Network< T > model
the aggregate, one class per chain
std::vector< std::size_t > chainclass
chainclass[c] is the 1-based class index of chain c+1 in model.
static Distrib exp_rate(const T &r)
static Distrib disabled_dist()
std::vector< T > params
Constructor arguments, in MATLAB getParam order.
static Distrib det(const T &m)
static Distrib hyperexp(const T &p, const T &lambda1, const T &lambda2)
static Distrib erlang(const T &phase_rate, std::size_t r)
Erlang(alpha, r): r phases of rate alpha, as MATLAB's Erlang(phaseRate, nphases).
static Distrib exp_mean(const T &m)
static constexpr double FineTol
The chain-level view of a layer, as sn_get_demands_chain returns it.
std::vector< std::size_t > refstatchain
(C) 1-based reference station
std::vector< double > Nchain
(C) population, infinite for an open chain
Matrix< T > alpha
(M x K) class share of its chain's visits at a station
Matrix< T > STchain
(M x C) mean service time
Matrix< T > Lchain
(M x C) demand
Matrix< T > Vchain
(M x C) visits
Matrix< T > SCVchain
(M x C)
One station of the network.
double cap
Station capacity in Kendall's K, as setCapacity sets it.
double nservers
may be infinite (a Delay, or an inf-scheduled task)