LINE Solver (C++)
Templated C++ port of the LINE queueing solver
Loading...
Searching...
No Matches
sn_is_phasetype.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_SN_SN_IS_PHASETYPE_H
6#define LINE_API_SN_SN_IS_PHASETYPE_H
7
8/**
9 * @file
10 * @ingroup api_sn
11 * Whether a (D0, D1, ...) list is a valid phase-type / MAP representation.
12 *
13 * Port of matlab/src/api/sn/sn_is_phasetype.m. D0 has non-negative
14 * off-diagonals, every further block is non-negative, and
15 * the entry vector, when supplied, is non-negative. It does NOT check that the
16 * rows sum to zero -- `refreshProcessRepresentations` calls it to decide
17 * whether a fitted representation may be USED, and a representation that fails
18 * only the row-sum test has a different problem.
19 *
20 * A representation that cannot be inspected -- an empty list, a shorter one
21 * than (D0, D1), a non-square D0, a D0 carrying NaN -- returns TRUE, exactly as
22 * the reference does: the predicate reports a DEFECT it can see, and "nothing
23 * to see" is not a defect. A block after D0 that carries NaN is skipped for the
24 * same reason.
25 *
26 * ARITHMETIC: field. Sign tests against GlobalConstants::Zero.
27 */
28
29#include <cmath>
30#include <cstddef>
31#include <vector>
32
34#include "line/util/matrix.h"
35
36namespace line {
37namespace api {
38
39/**
40 * @brief Whether a (D0, D1, ...) list is a valid phase-type / MAP
41 * representation.
42 *
43 * @param maps the (D0, D1, ...) blocks
44 * @param pie the entry vector, empty when there is none to check
45 */
46template <class T>
47bool sn_is_phasetype(const std::vector<Matrix<T>>& maps, const std::vector<T>& pie) {
48 const double tol = lang::GlobalConstants::Zero;
49 if (maps.size() < 2) return true;
50 const Matrix<T>& D0 = maps[0];
51 const std::size_t n = D0.rows();
52 if (n == 0 || D0.cols() != n) return true;
53 for (std::size_t a = 0; a < n; ++a)
54 for (std::size_t b = 0; b < n; ++b) {
55 const double v = num_traits<T>::to_double(D0(a, b));
56 if (std::isnan(v)) return true; // uninspectable, as the reference has it
57 }
58 for (std::size_t a = 0; a < n; ++a)
59 for (std::size_t b = 0; b < n; ++b) {
60 if (a == b) continue;
61 if (num_traits<T>::to_double(D0(a, b)) < -tol) return false;
62 }
63 for (std::size_t k = 1; k < maps.size(); ++k) {
64 const Matrix<T>& Dk = maps[k];
65 bool hasnan = false;
66 for (std::size_t a = 0; a < Dk.rows() && !hasnan; ++a)
67 for (std::size_t b = 0; b < Dk.cols(); ++b)
68 if (std::isnan(num_traits<T>::to_double(Dk(a, b)))) {
69 hasnan = true;
70 break;
71 }
72 if (hasnan) continue;
73 for (std::size_t a = 0; a < Dk.rows(); ++a)
74 for (std::size_t b = 0; b < Dk.cols(); ++b)
75 if (num_traits<T>::to_double(Dk(a, b)) < -tol) return false;
76 }
77 for (std::size_t a = 0; a < pie.size(); ++a) {
78 const double v = num_traits<T>::to_double(pie[a]);
79 if (std::isnan(v)) return true;
80 if (v < -tol) return false;
81 }
82 return true;
83}
84
85template <class T>
86bool sn_is_phasetype(const std::vector<Matrix<T>>& maps) {
87 return sn_is_phasetype(maps, std::vector<T>());
88}
89
90} // namespace api
91} // namespace line
92
93#endif // LINE_API_SN_SN_IS_PHASETYPE_H
std::size_t cols() const
Definition matrix.h:90
std::size_t rows() const
Definition matrix.h:89
Enumerations and the minimal distribution descriptor shared by the model layer of the C++ port.
Dense matrix and non-owning view.
bool sn_is_phasetype(const std::vector< Matrix< T > > &maps, const std::vector< T > &pie)
Whether a (D0, D1, ...) list is a valid phase-type / MAP representation.
static constexpr double Zero
Definition lang_types.h:670