5#ifndef LINE_API_LQN_LSN_MAX_MULTIPLICITY_H
6#define LINE_API_LQN_LSN_MAX_MULTIPLICITY_H
116 std::vector<Multiplicity<T>>
mult;
117 std::vector<LsnElementType>
type;
134std::vector<std::size_t> kahn(
const Matrix<T>& adj) {
135 const std::size_t n = adj.
rows();
137 std::vector<std::size_t> indeg(n, 0);
138 for (std::size_t c = 0; c < n; ++c)
139 for (std::size_t r = 0; r < n; ++r)
140 if (adj(r, c) > zero) ++indeg[c];
142 std::deque<std::size_t> q;
143 for (std::size_t v = 0; v < n; ++v)
144 if (indeg[v] == 0) q.push_back(v);
146 std::vector<std::size_t> order;
149 const std::size_t i = q.front();
152 for (std::size_t j = 0; j < n; ++j)
153 if (adj(i, j) > zero && --indeg[j] == 0) q.push_back(j);
169 const std::size_t n =
lsn.dag.rows();
170 if (
lsn.dag.cols() != n)
throw InputError(
"lsn_max_multiplicity: the call graph is not square");
171 if (
lsn.type.size() != n ||
lsn.isref.size() != n)
172 throw InputError(
"lsn_max_multiplicity: type/isref disagree with the graph size");
173 if (!
lsn.hassetup.empty() &&
lsn.hassetup.size() != n)
174 throw InputError(
"lsn_max_multiplicity: hassetup disagrees with the graph size");
175 if (!
lsn.entry_has_arrival.empty() &&
lsn.entry_has_arrival.size() != n)
176 throw InputError(
"lsn_max_multiplicity: entry_has_arrival disagrees with the graph size");
177 if (!
lsn.repl.empty() &&
lsn.repl.size() != n)
178 throw InputError(
"lsn_max_multiplicity: repl disagrees with the graph size");
179 auto rep = [&](std::size_t i) ->
long {
return lsn.repl.empty() ? 1L : std::max(1L,
lsn.repl[i]); };
184 for (std::size_t i = 0; i < n; ++i)
185 for (std::size_t j = 0; j < n; ++j)
188 const std::vector<std::size_t> order = detail::kahn(
ag);
189 if (order.size() != n)
190 throw InputError(
"lsn_max_multiplicity: the call graph has a cycle, no topological order");
193 std::vector<Multiplicity<T>> mult =
lsn.mult;
194 if (mult.size() > n)
throw InputError(
"lsn_max_multiplicity: more multiplicities than elements");
198 for (std::size_t i = 0; i < n; ++i) {
202 lsn.entry_has_arrival[i]) {
211 for (std::size_t k = 0; k < n; ++k) {
212 const std::size_t i = order[k];
213 const bool has_setup = !
lsn.hassetup.empty() &&
lsn.hassetup[i];
215 if (has_setup && inflow[i].positive()) {
217 outflow[i] = mult[i];
220 outflow[i] =
mult_min(inflow[i], mult[i]);
223 for (std::size_t j = 0; j < n; ++j) {
224 if (j == i || !(
ag(i, j) > zero))
continue;
227 const long per = std::max(1L, rep(i) / rep(j));
230 inflow[j] =
mult_add(inflow[j], total);
235 for (std::size_t i = 0; i < n; ++i)
The exception types the port throws.
Dense matrix and non-owning view.
LsnElementType
Element kinds, with the values of MATLAB's LayeredNetworkElement.
std::vector< Multiplicity< T > > lsn_max_multiplicity(const LsnInput< T > &lsn)
Maximum sustainable multiplicity (concurrency level) of every element of a layered software network.
Multiplicity< T > mult_add(const Multiplicity< T > &a, const Multiplicity< T > &b)
a + b, with infinity absorbing.
Multiplicity< T > mult_scale(const Multiplicity< T > &a, long k)
a times the integer k, with infinity absorbing.
Multiplicity< T > mult_min(const Multiplicity< T > &a, const Multiplicity< T > &b)
min(a,b), with infinity as the top element.
Conservation laws of a layered queueing network, enumerated from its structure.
Number-type abstraction for the templated API port.
A multiplicity, possibly infinite; MATLAB's mult(i) = Inf.
static Multiplicity finite(const T &v)
static Multiplicity inf()
static Multiplicity of(long v)