LINE Solver (C++)
Templated C++ port of the LINE queueing solver
Loading...
Searching...
No Matches
ctmc_sens.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_SENS_H
6#define LINE_API_MC_CTMC_SENS_H
7
8/**
9 * @file
10 * @ingroup api_mc
11 * Sensitivity of the steady-state distribution of a CTMC to a scalar
12 * parameter.
13 *
14 * Templated port of matlab/src/api/mc/ctmc_sens.m. Differentiating pi Q = 0 and
15 * pi e = 1 with respect to theta gives Trivedi and Bobbio (2017), Eq. (9.81),
16 *
17 * (dpi/dtheta) Q = -pi (dQ/dtheta), sum_i dpi_i/dtheta = 0,
18 *
19 * whose coefficient matrix is the one the steady-state solve already assembles:
20 * a sensitivity costs exactly one extra triangular solve. The normalization
21 * replaces the LAST equation of the transposed system, as in ctmc_solve.
22 *
23 * The whole computation is a linear solve over the field of the rates, so it
24 * carries NO gate: at Rational it returns the exact derivative of the exact
25 * stationary vector, which is the regime where a finite-difference estimate of
26 * the same quantity is worst behaved (it differences two nearly equal vectors)
27 * and where this port is therefore most worth having.
28 */
29
30#include <cstddef>
31#include <vector>
32
34#include "line/num/number.h"
35#include "line/util/error.h"
36#include "line/util/lu.h"
37#include "line/util/matrix.h"
38
39namespace line {
40namespace mc {
41
42/**
43 * @brief Sensitivity of the steady-state distribution of a CTMC to a scalar
44 * parameter.
45 *
46 * @param Q generator
47 * @param dQ derivative of the generator with respect to theta, same size
48 * @param pi steady-state distribution; must sum to one
49 * @return dpi/dtheta as a row vector of length n, summing to zero
50 */
51template <class T>
52std::vector<T> ctmc_sens(const Matrix<T>& Q, const Matrix<T>& dQ, const std::vector<T>& pi) {
53 const std::size_t n = Q.rows();
54 if (Q.cols() != n) throw InputError("ctmc_sens: generator is not square");
55 if (dQ.rows() != n || dQ.cols() != n) throw InputError("ctmc_sens: dQ must have the same size as Q");
56 if (pi.size() != n) throw InputError("ctmc_sens: pi has the wrong length");
57 const T zero = num_traits<T>::from_int(0);
58 const T one = num_traits<T>::from_int(1);
59
60 // b = -pi * dQ, with the last entry replaced by the normalization 0.
61 std::vector<T> b(n, zero);
62 for (std::size_t j = 0; j < n; ++j) {
63 T s = zero;
64 for (std::size_t i = 0; i < n; ++i) s += pi[i] * dQ(i, j);
65 b[j] = -s;
66 }
67 b[n - 1] = zero;
68
69 // A = Q' with its last ROW replaced by ones (MATLAB A(n,:) = ones(1,n)).
70 Matrix<T> A(n, n);
71 for (std::size_t i = 0; i < n; ++i)
72 for (std::size_t j = 0; j < n; ++j) A(i, j) = Q(j, i);
73 for (std::size_t j = 0; j < n; ++j) A(n - 1, j) = one;
74
75 return solve(A, b);
76}
77
78/** Overload computing the steady-state vector itself, as MATLAB does. */
79template <class T>
80std::vector<T> ctmc_sens(const Matrix<T>& Q, const Matrix<T>& dQ) {
81 return ctmc_sens(Q, dQ, ctmc_solve(Q));
82}
83
84} // namespace mc
85} // namespace line
86
87#endif // LINE_API_MC_CTMC_SENS_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
Steady-state distribution of a continuous-time Markov chain.
The exception types the port throws.
LU factorization with partial pivoting, templated on the number type.
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
std::vector< T > ctmc_sens(const Matrix< T > &Q, const Matrix< T > &dQ, const std::vector< T > &pi)
Sensitivity of the steady-state distribution of a CTMC to a scalar parameter.
Definition ctmc_sens.h:52
std::vector< T > solve(const Matrix< T > &A, const std::vector< T > &b)
Convenience: solve Ax = b, leaving A and b untouched.
Definition lu.h:158
Number-type abstraction for the templated API port.