LINE Solver (C++)
Templated C++ port of the LINE queueing solver
Loading...
Searching...
No Matches
ctmc_pseudostochcomp.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_MC_CTMC_PSEUDOSTOCHCOMP_H
6#define LINE_API_MC_CTMC_PSEUDOSTOCHCOMP_H
7
8/**
9 * @file
10 * @ingroup api_mc
11 * Pseudo stochastic complement of a CTMC partition.
12 *
13 * Templated port of jar/src/main/java/jline/api/mc/Ctmc_pseudostochcomp.java,
14 * which has no MATLAB twin. The exact complement over a retained set I censors
15 * the excursions through the complement Ic and needs the inverse of Q22; the
16 * pseudo complement replaces that inverse by the single rank-one return law
17 * S = Q11 + Q12 1 y, y = pi(Ic) Q21 / sum( pi(Ic) Q21 ),
18 * i.e. every excursion into Ic is assumed to re-enter I through the stationary
19 * re-entry distribution y, independently of where it left. This is exact when
20 * Q22 is a single lumped state and is the Takahashi-style approximation
21 * otherwise; it costs one stationary solve instead of one linear solve per
22 * retained state.
23 *
24 * The default retained set, used when `keep` is empty, is the first
25 * ceil(n/2) states, matching the reference.
26 *
27 * ARITHMETIC: field plus the stationary solve, so exact under Rational whenever
28 * ctmc_solve is.
29 */
30
31#include <cstddef>
32#include <vector>
33
35#include "line/num/number.h"
36#include "line/util/error.h"
37#include "line/util/matrix.h"
38
39namespace line {
40namespace mc {
41
42/** Blocks of the partition together with the pseudo complement over I. */
43template <class T>
45 Matrix<T> S; ///< pseudo stochastic complement over the retained set
46 Matrix<T> Q11; ///< retained-to-retained block
47 Matrix<T> Q12; ///< retained-to-complement block
48 Matrix<T> Q21; ///< complement-to-retained block
49 Matrix<T> Q22; ///< complement-to-complement block
50 Matrix<T> Tm; ///< the rank-one return term S - Q11
51};
52
53/**
54 * @brief Pseudo stochastic complement of a CTMC partition.
55 *
56 * @param Q (n x n) generator
57 * @param keep 0-based indices of the retained set I; empty selects the first
58 * ceil(n/2) states
59 */
60template <class T>
62 const std::vector<std::size_t>& keep) {
63 const std::size_t n = Q.rows();
64 if (Q.cols() != n) throw InputError("ctmc_pseudostochcomp: generator is not square");
65 const T zero = num_traits<T>::from_int(0);
66
67 std::vector<std::size_t> I = keep;
68 if (I.empty())
69 for (std::size_t i = 0; i < (n + 1) / 2; ++i) I.push_back(i);
70
71 std::vector<bool> kept(n, false);
72 for (std::size_t i = 0; i < I.size(); ++i) {
73 if (I[i] >= n) throw InputError("ctmc_pseudostochcomp: a retained index is out of range");
74 kept[I[i]] = true;
75 }
76 std::vector<std::size_t> Ic;
77 for (std::size_t i = 0; i < n; ++i)
78 if (!kept[i]) Ic.push_back(i);
79 if (Ic.empty()) throw InputError("ctmc_pseudostochcomp: the complement set is empty");
80
81 const std::size_t nk = I.size(), nd = Ic.size();
83 r.Q11 = Matrix<T>(nk, nk, zero);
84 r.Q12 = Matrix<T>(nk, nd, zero);
85 r.Q21 = Matrix<T>(nd, nk, zero);
86 r.Q22 = Matrix<T>(nd, nd, zero);
87 for (std::size_t a = 0; a < nk; ++a) {
88 for (std::size_t b = 0; b < nk; ++b) r.Q11(a, b) = Q(I[a], I[b]);
89 for (std::size_t b = 0; b < nd; ++b) r.Q12(a, b) = Q(I[a], Ic[b]);
90 }
91 for (std::size_t a = 0; a < nd; ++a) {
92 for (std::size_t b = 0; b < nk; ++b) r.Q21(a, b) = Q(Ic[a], I[b]);
93 for (std::size_t b = 0; b < nd; ++b) r.Q22(a, b) = Q(Ic[a], Ic[b]);
94 }
95
96 const std::vector<T> pie = ctmc_solve(Q);
97
98 // y = pi(Ic) Q21, normalized to a probability over the re-entry states.
99 std::vector<T> y(nk, zero);
100 T sy = zero;
101 for (std::size_t b = 0; b < nk; ++b) {
102 T acc = zero;
103 for (std::size_t a = 0; a < nd; ++a) acc += pie[Ic[a]] * r.Q21(a, b);
104 y[b] = acc;
105 sy += acc;
106 }
107 if (sy == zero) throw NumericError("ctmc_pseudostochcomp: no flow returns to the retained set");
108 for (std::size_t b = 0; b < nk; ++b) y[b] = T(y[b] / sy);
109
110 // Q12 1 y: the row sums of Q12 spread over the re-entry law.
111 r.Tm = Matrix<T>(nk, nk, zero);
112 for (std::size_t a = 0; a < nk; ++a) {
113 T out = zero;
114 for (std::size_t b = 0; b < nd; ++b) out += r.Q12(a, b);
115 for (std::size_t b = 0; b < nk; ++b) r.Tm(a, b) = T(out * y[b]);
116 }
117
118 r.S = r.Q11;
119 for (std::size_t a = 0; a < nk; ++a)
120 for (std::size_t b = 0; b < nk; ++b) r.S(a, b) = T(r.S(a, b) + r.Tm(a, b));
121 return r;
122}
123
124/** Default partition: the first ceil(n/2) states. */
125template <class T>
127 return ctmc_pseudostochcomp(Q, std::vector<std::size_t>());
128}
129
130} // namespace mc
131} // namespace line
132
133#endif // LINE_API_MC_CTMC_PSEUDOSTOCHCOMP_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
NumericError(const std::string &what)
Definition error.h:45
Steady-state distribution of a continuous-time Markov chain.
The exception types the port throws.
Dense matrix and non-owning view.
std::vector< T > ctmc_solve(const Matrix< T > &Qin)
Steady-state distribution of a continuous-time Markov chain.
Definition ctmc_solve.h:122
PseudoStochCompResult< T > ctmc_pseudostochcomp(const Matrix< T > &Q, const std::vector< std::size_t > &keep)
Pseudo stochastic complement of a CTMC partition.
Number-type abstraction for the templated API port.
Blocks of the partition together with the pseudo complement over I.
Matrix< T > Q22
complement-to-complement block
Matrix< T > Q11
retained-to-retained block
Matrix< T > Q21
complement-to-retained block
Matrix< T > Tm
the rank-one return term S - Q11
Matrix< T > Q12
retained-to-complement block
Matrix< T > S
pseudo stochastic complement over the retained set