LINE Solver (C++)
Templated C++ port of the LINE queueing solver
Loading...
Searching...
No Matches
pfqn_comomrm_ld.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_PFQN_COMOMRM_LD_H
6#define LINE_API_PFQN_COMOMRM_LD_H
7
8/**
9 * @file
10 * @ingroup api_pfqn
11 * CoMoM for the repairman model with an arbitrary LOAD-DEPENDENT rate lattice
12 * at the single queueing station.
13 *
14 * Templated port of matlab/src/api/pfqn/pfqn_comomrm_ld.m. The recursion is
15 * the bidiagonal transfer-matrix sweep of pfqn_comomrm_ms, from which this
16 * routine differs only in where the rate lattice comes from and in the
17 * preprocessing that folds pure delay rows out of the demand matrix.
18 *
19 * Delay detection. When no think time is supplied, a station whose rate row is
20 * exactly the identity lattice mu(i,k) = k is an infinite server, and the
21 * reference moves its demand row into Z and drops it from L and mu. MATLAB
22 * tests this with a 2-norm against a tolerance; this port tests exact equality,
23 * for the same reason pfqn_unique merges on exact equality: a tolerant test
24 * silently reclassifies a station and changes the model, which has no meaning
25 * in the rational field. A caller wanting the tolerant behaviour should round
26 * its rate lattice before calling, where the rounding is visible.
27 *
28 * Arithmetic: EXACT-CAPABLE, unconditionally. See pfqn_comomrm_ms for why the
29 * reference's per-step renormalization is dropped rather than reproduced.
30 */
31
32#include <cstddef>
33#include <vector>
34
38#include "line/num/number.h"
39#include "line/util/error.h"
40#include "line/util/matrix.h"
41
42namespace line {
43namespace pfqn {
44
45/**
46 * @brief CoMoM for the repairman model with an arbitrary LOAD-DEPENDENT rate
47 * lattice at the single queueing station.
48 *
49 * @param L (M x R) demands
50 * @param N (R) populations
51 * @param Z (K x R) think times; empty or zero triggers delay detection on mu
52 * @param mu (M x >=Nt) load-dependent rate lattice
53 */
54template <class T>
55ComomRmResult<T> pfqn_comomrm_ld(const Matrix<T>& L, const std::vector<int>& N, const Matrix<T>& Z,
56 const Matrix<T>& mu) {
57 const std::size_t R = N.size();
58 const T zero = num_traits<T>::from_int(0);
59 const T one = num_traits<T>::from_int(1);
60
61 int Nt = 0;
62 for (int v : N) {
63 if (v < 0) throw InputError("pfqn_comomrm_ld: negative population");
64 Nt += v;
65 }
66
67 std::size_t M = L.empty() ? 0 : L.rows();
68 if (M > 0 && L.cols() != R)
69 throw InputError("pfqn_comomrm_ld: L and N disagree on the class count");
70
71 // Aggregate the think-time rows.
72 std::vector<T> Zsum(R, zero);
73 T Ztot = zero;
74 if (!Z.empty()) {
75 if (Z.cols() != R) throw InputError("pfqn_comomrm_ld: Z and N disagree on the class count");
76 for (std::size_t k = 0; k < Z.rows(); ++k)
77 for (std::size_t r = 0; r < R; ++r) Zsum[r] += Z(k, r);
78 }
79 for (std::size_t r = 0; r < R; ++r) Ztot += Zsum[r];
80
81 Matrix<T> Lq = L;
82 Matrix<T> muq = mu;
83 if (Ztot == zero && M > 0) {
84 if (mu.rows() != M)
85 throw InputError("pfqn_comomrm_ld: mu and L disagree on the station count");
86 // A row whose rate lattice is 1, 2, 3, ... is an infinite server.
87 std::vector<std::size_t> queues, delays;
88 for (std::size_t i = 0; i < M; ++i) {
89 bool isDelay = Nt > 0;
90 for (int k = 1; k <= Nt; ++k)
91 if (mu(i, static_cast<std::size_t>(k - 1)) != num_traits<T>::from_int(k)) {
92 isDelay = false;
93 break;
94 }
95 (isDelay ? delays : queues).push_back(i);
96 }
97 if (!delays.empty()) {
98 for (std::size_t d = 0; d < delays.size(); ++d)
99 for (std::size_t r = 0; r < R; ++r) Zsum[r] += L(delays[d], r);
100 Lq = Matrix<T>(queues.size(), R);
101 muq = Matrix<T>(queues.size(), mu.cols());
102 for (std::size_t q = 0; q < queues.size(); ++q) {
103 for (std::size_t r = 0; r < R; ++r) Lq(q, r) = L(queues[q], r);
104 for (std::size_t k = 0; k < mu.cols(); ++k) muq(q, k) = mu(queues[q], k);
105 }
106 M = queues.size();
107 }
108 }
109
110 Matrix<T> Zmat(1, R);
111 for (std::size_t r = 0; r < R; ++r) Zmat(0, r) = Zsum[r];
112
113 T Lsum = zero;
114 for (std::size_t i = 0; i < M; ++i)
115 for (std::size_t r = 0; r < R; ++r) Lsum += Lq(i, r);
116 if (M == 0 || Lsum == zero) {
117 // Only delays remain: the model is the trivial multinomial one.
118 const NcResult<T> ca = pfqn_ca(Matrix<T>(), N, Zmat);
120 res.G = ca.G;
121 res.lG = ca.lG;
122 res.prob.assign(static_cast<std::size_t>(Nt) + 1, zero);
123 res.prob.back() = one;
124 return res;
125 }
126
127 const NcSanitizeResult<T> san = pfqn_nc_sanitize(Lq, N, Zmat);
128 if (san.L.rows() > 1)
129 throw InputError("pfqn_comomrm_ld: the solver accepts at most a single queueing station");
130
131 int Ntk = 0;
132 for (int v : san.N) Ntk += v;
133 if (Ntk == 0 || san.L.empty()) {
135 res.G = san.Gremaind;
136 res.lG = san.lGremaind;
137 res.prob.assign(static_cast<std::size_t>(Nt) + 1, zero);
138 res.prob[0] = one;
139 return res;
140 }
141
142 const std::size_t Rk = san.N.size();
143 std::vector<T> Lv(Rk, zero), Zv(Rk, zero);
144 for (std::size_t r = 0; r < Rk; ++r) {
145 Lv[r] = san.L(0, r);
146 for (std::size_t k = 0; k < san.Z.rows(); ++k) Zv[r] += san.Z(k, r);
147 }
148 std::vector<T> muv(static_cast<std::size_t>(Ntk), one);
149 for (int k = 0; k < Ntk; ++k) muv[static_cast<std::size_t>(k)] = muq(0, static_cast<std::size_t>(k));
150
151 return detail::comomrm_finish(detail::comomrm_bidiag(Lv, san.N, Zv, muv), san.Gremaind);
152}
153
154} // namespace pfqn
155} // namespace line
156
157#endif // LINE_API_PFQN_COMOMRM_LD_H
InputError(const std::string &what)
Definition error.h:39
std::size_t cols() const
Definition matrix.h:90
std::size_t rows() const
Definition matrix.h:89
bool empty() const
Definition matrix.h:92
The exception types the port throws.
Dense matrix and non-owning view.
NcSanitizeResult< T > pfqn_nc_sanitize(const std::vector< T > &lambda, const Matrix< T > &L, const std::vector< int > &N, const Matrix< T > &Z, const T &atol)
Preprocessing shared by the normalizing-constant solvers: drop the classes that cannot contribute,...
NcResult< T > pfqn_ca(const Matrix< T > &L, const std::vector< int > &N, const Matrix< T > &Z)
Convolution algorithm for the exact normalizing constant of a closed product-form network (Buzen 1973...
Definition pfqn_ca.h:120
ComomRmResult< T > pfqn_comomrm_ld(const Matrix< T > &L, const std::vector< int > &N, const Matrix< T > &Z, const Matrix< T > &mu)
CoMoM for the repairman model with an arbitrary LOAD-DEPENDENT rate lattice at the single queueing st...
Number-type abstraction for the templated API port.
Convolution algorithm for the exact normalizing constant of a closed product-form network (Buzen 1973...
CoMoM for the MULTISERVER repairman model: one queueing station with S servers (optionally replicated...
Preprocessing shared by the normalizing-constant solvers: drop the classes that cannot contribute,...
T G
normalizing constant
std::vector< T > prob
(Nt+1) queue-length marginal, prob[k] = P(n = k)
double lG
its logarithm
Return value of the normalizing-constant family, mirroring Ret.pfqnNc.
Definition pfqn_ca.h:44
T G
normalizing constant in the requested arithmetic
Definition pfqn_ca.h:45
double lG
log of the constant, always a double and always finite
Definition pfqn_ca.h:46
T Gremaind
multiplicative factor removed from G
Matrix< T > Z
retained think times, rescaled and reordered
Matrix< T > L
retained demands, rescaled and reordered
double lGremaind
its logarithm, for the log-space callers
std::vector< int > N
retained populations, reordered