LINE Solver (C++)
Templated C++ port of the LINE queueing solver
Loading...
Searching...
No Matches
mmdp_isfeasible.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_MAM_MMDP_ISFEASIBLE_H
6#define LINE_API_MAM_MMDP_ISFEASIBLE_H
7
8/**
9 * @file
10 * @ingroup api_mam
11 * Feasibility predicate for a Markov-modulated deterministic process.
12 *
13 * Templated port of matlab/src/api/mam/mmdp_isfeasible.m. An MMDP is the pair
14 * (Q, R) with Q the generator of the modulating chain and R the diagonal
15 * matrix of the deterministic service (or inter-arrival) times attached to
16 * each modulating state. The pair is feasible when
17 *
18 * - Q is square, has non-positive diagonal, non-negative off-diagonal and
19 * zero row sums, i.e. it is a conservative generator;
20 * - R is square of the same order, diagonal, with non-negative diagonal.
21 *
22 * ARITHMETIC. The predicate is a finite set of sign and sum comparisons, so
23 * it instantiates at every arithmetic including Rational. The tolerance is an
24 * explicit argument rather than a hard-wired 1e-10, so the exact
25 * instantiation can be given tol = 0 and then rejects any deviation however
26 * small, which is the right check for an algebraically assembled pair; the
27 * MATLAB default of 1e-10 is what the tolerant overload supplies, and it is
28 * the right check for the output of a fit.
29 */
30
31#include <cstddef>
32
33#include "line/num/number.h"
34#include "line/util/matrix.h"
35
36namespace line {
37namespace mam {
38
39/** True when (Q, R) is a valid MMDP pair up to the given tolerance. */
40template <class T>
41bool mmdp_isfeasible(const Matrix<T>& Q, const Matrix<T>& R, const T& tol) {
42 const T zero = num_traits<T>::from_int(0);
43 const std::size_t n = Q.rows();
44 if (Q.cols() != n) return false;
45
46 for (std::size_t i = 0; i < n; ++i) {
47 if (Q(i, i) > tol) return false;
48 for (std::size_t j = 0; j < n; ++j)
49 if (i != j && Q(i, j) < -tol) return false;
50 T rowsum = zero;
51 for (std::size_t j = 0; j < n; ++j) rowsum += Q(i, j);
52 if (num_abs(T(rowsum)) > tol) return false;
53 }
54
55 if (R.rows() != n || R.cols() != n) return false;
56
57 for (std::size_t i = 0; i < n; ++i) {
58 if (R(i, i) < -tol) return false;
59 for (std::size_t j = 0; j < n; ++j)
60 if (i != j && num_abs(T(R(i, j))) > tol) return false;
61 }
62 return true;
63}
64
65/** mmdp_isfeasible with the MATLAB tolerance, 1e-10. */
66template <class T>
67bool mmdp_isfeasible(const Matrix<T>& Q, const Matrix<T>& R) {
68 return mmdp_isfeasible(Q, R, T(num_traits<T>::from_double(1e-10)));
69}
70
71} // namespace mam
72} // namespace line
73
74#endif // LINE_API_MAM_MMDP_ISFEASIBLE_H
std::size_t cols() const
Definition matrix.h:90
std::size_t rows() const
Definition matrix.h:89
Dense matrix and non-owning view.
bool mmdp_isfeasible(const Matrix< T > &Q, const Matrix< T > &R, const T &tol)
True when (Q, R) is a valid MMDP pair up to the given tolerance.
T num_abs(const T &v)
Definition number.h:172
Number-type abstraction for the templated API port.