LINE Solver (C++)
Templated C++ port of the LINE queueing solver
Loading...
Searching...
No Matches
sn_open_prob_terms.h
Go to the documentation of this file.
1/*
2 * Copyright (c) 2012-2026, QORE Lab, Imperial College London
3 * All rights reserved.
4 */
5#ifndef LINE_API_SN_SN_OPEN_PROB_TERMS_H
6#define LINE_API_SN_SN_OPEN_PROB_TERMS_H
7
8/**
9 * @file
10 * @ingroup api_sn
11 * Open-class contribution to an aggregate state probability at one station.
12 *
13 * Templated port of jar/src/main/java/jline/api/sn/SnOpenProbTerms.java, which
14 * factors the mixed branch shared by `@@SolverMVA/getProbAggr.m` and
15 * `@@SolverMVA/getProbSysAggr.m` (and the native Python `_open_prob_aggr_terms`)
16 * out of both getters. The three station shapes are:
17 *
18 * - EXT (a Source): no contribution, its population belongs to the environment;
19 * - INF (a Delay): an independent Poisson per open class, mean Q(i,r);
20 * - anything else: the multinomial-geometric BCMP form
21 * (1 - sum_r rho_r) (sum_r n_r)! prod_r rho_r^n_r / n_r!.
22 *
23 * The whole term is returned in logs, since the callers accumulate a log
24 * probability and only exponentiate at the end.
25 *
26 * INFEASIBILITY IS A FLAG, NOT -Inf. The reference returns negative infinity for
27 * a state the law gives zero mass to (a class present where its utilization is
28 * zero, or a saturated station). Rational has no infinity, so the verdict rides
29 * in `feasible` and the caller decides what sentinel to emit; every caller in
30 * this port short-circuits, so the log value is never read when it is false.
31 *
32 * ARITHMETIC: transcendental. Needs log and lgamma, so it does not instantiate
33 * under Rational.
34 */
35
36#include <cmath>
37#include <cstddef>
38
42#include "line/num/number.h"
43#include "line/util/error.h"
44#include "line/util/matrix.h"
45
46namespace line {
47namespace api {
48
49/** The log contribution, and whether the state carries any mass at all. */
50template <class T>
52 T logp; ///< log of the open-class factor at this station
53 bool feasible; ///< false when the law gives the state zero probability
54};
55
56/**
57 * @brief Open-class contribution to an aggregate state probability at one
58 * station.
59 *
60 * @param sn the network struct
61 * @param Q mean queue lengths, stations by classes
62 * @param U utilizations, stations by classes
63 * @param nir per-class job counts, stations by classes (row `ist` is read)
64 * @param ist 0-based station index
65 */
66template <class T>
68 const Matrix<T>& U, const Matrix<T>& nir, std::size_t ist) {
70 "sn_open_prob_terms evaluates a product-form law and needs logarithms");
71 using std::log;
72 if (ist >= sn.stations.size())
73 throw InputError("sn_open_prob_terms: station index out of range");
74 const T zero = num_traits<T>::from_int(0), one = num_traits<T>::from_int(1);
75 const qn::SchedStrategy sched = sn.stations[ist].sched;
76
78 out.logp = zero;
79 out.feasible = true;
80 if (sched == qn::SchedStrategy::EXT) return out;
81
82 if (sched == qn::SchedStrategy::INF) {
83 for (std::size_t r = 0; r < sn.nclasses; ++r) {
84 if (std::isfinite(sn.classes[r].population)) continue;
85 const T q = Q(ist, r);
86 if (q > zero) {
87 out.logp = T(out.logp + nir(ist, r) * log(q) - q -
88 pfqn::detail::num_factln<T>(nir(ist, r)));
89 } else if (nir(ist, r) > zero) {
90 out.feasible = false;
91 return out;
92 }
93 }
94 return out;
95 }
96
97 T rho_total = zero, n_total = zero;
98 for (std::size_t r = 0; r < sn.nclasses; ++r) {
99 if (std::isfinite(sn.classes[r].population)) continue;
100 rho_total = T(rho_total + U(ist, r));
101 n_total = T(n_total + nir(ist, r));
102 }
103 if (!(rho_total < one)) { // a saturated station has no stationary law
104 out.feasible = false;
105 return out;
106 }
107 out.logp = T(out.logp + log(T(one - rho_total)) + pfqn::detail::num_factln<T>(n_total));
108 for (std::size_t r = 0; r < sn.nclasses; ++r) {
109 if (std::isfinite(sn.classes[r].population)) continue;
110 if (!(nir(ist, r) > zero)) continue;
111 const T rho_r = U(ist, r);
112 if (!(rho_r > zero)) {
113 out.feasible = false;
114 return out;
115 }
116 out.logp =
117 T(out.logp + nir(ist, r) * log(rho_r) - pfqn::detail::num_factln<T>(nir(ist, r)));
118 }
119 return out;
120}
121
122} // namespace api
123} // namespace line
124
125#endif // LINE_API_SN_SN_OPEN_PROB_TERMS_H
InputError(const std::string &what)
Definition error.h:39
A network plus its refreshed NetworkStruct.
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.
OpenProbTerm< T > sn_open_prob_terms(const qn::NetworkStruct< T > &sn, const Matrix< T > &Q, const Matrix< T > &U, const Matrix< T > &nir, std::size_t ist)
Open-class contribution to an aggregate state probability at one station.
SchedStrategy
Scheduling disciplines, with the values of MATLAB SchedStrategy.
Definition lang_types.h:181
A queueing network and its refreshed NetworkStruct.
Number-type abstraction for the templated API port.
Shared scalar machinery for the integration / asymptotic members of the pfqn family (pfqn_le,...
The log contribution, and whether the state carries any mass at all.
bool feasible
false when the law gives the state zero probability
T logp
log of the open-class factor at this station