LINE Solver (C++)
Templated C++ port of the LINE queueing solver
Loading...
Searching...
No Matches
dtmc_makestochastic.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_DTMC_MAKESTOCHASTIC_H
6#define LINE_API_MC_DTMC_MAKESTOCHASTIC_H
7
8/**
9 * @file
10 * @ingroup api_mc
11 * Normalize a non-negative matrix into a stochastic transition matrix.
12 *
13 * Templated port of matlab/lib/kpctoolbox/mc/dtmc_makestochastic.m and
14 * jar/src/main/java/jline/api/mc/Dtmc_makestochastic.java. Each row with a
15 * positive sum is divided by that sum, and the diagonal entry then absorbs
16 * whatever deficit is left, clipped into [0,1]; a row that sums to zero is
17 * replaced by the unit vector on its own state, which turns a dead state into
18 * an absorbing one rather than leaving a substochastic row behind.
19 *
20 * After the division the row already sums to one, so the diagonal update is an
21 * identity in exact arithmetic; it is kept because in floating point it is the
22 * step that removes the accumulated rounding of the division, and dropping it
23 * would make the double and exact paths disagree in the last bit.
24 *
25 * Every operation is a field operation, so this is exact at Rational.
26 */
27
28#include <cstddef>
29
30#include "line/num/number.h"
31#include "line/util/error.h"
32#include "line/util/matrix.h"
33
34namespace line {
35namespace mc {
36
37/**
38 * @brief Normalize a non-negative matrix into a stochastic transition matrix.
39 *
40 * @param Pin matrix with non-negative entries
41 * @return row-stochastic matrix of the same size
42 */
43template <class T>
45 const std::size_t n = Pin.rows();
46 if (Pin.cols() != n) throw InputError("dtmc_makestochastic: matrix is not square");
47 const T zero = num_traits<T>::from_int(0);
48 const T one = num_traits<T>::from_int(1);
49 Matrix<T> P = Pin;
50 for (std::size_t i = 0; i < n; ++i) {
51 T s = zero;
52 for (std::size_t j = 0; j < n; ++j) s += P(i, j);
53 if (s > zero) {
54 for (std::size_t j = 0; j < n; ++j) P(i, j) /= s;
55 T off = zero;
56 for (std::size_t j = 0; j < n; ++j)
57 if (j != i) off += P(i, j);
58 T d = one - off;
59 if (d < zero) d = zero;
60 if (d > one) d = one;
61 P(i, i) = d;
62 } else {
63 for (std::size_t j = 0; j < n; ++j) P(i, j) = zero;
64 P(i, i) = one;
65 }
66 }
67 return P;
68}
69
70} // namespace mc
71} // namespace line
72
73#endif // LINE_API_MC_DTMC_MAKESTOCHASTIC_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
The exception types the port throws.
Dense matrix and non-owning view.
Matrix< T > dtmc_makestochastic(const Matrix< T > &Pin)
Normalize a non-negative matrix into a stochastic transition matrix.
Number-type abstraction for the templated API port.