LINE Solver (C++)
Templated C++ port of the LINE queueing solver
Toggle main menu visibility
Loading...
Searching...
No Matches
sn_is_discrete_time.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_DISCRETE_TIME_H
6
#define LINE_API_SN_SN_IS_DISCRETE_TIME_H
7
8
/**
9
* @file
10
* @ingroup api_sn
11
* Port of matlab/src/api/sn/sn_is_discrete_time.m.
12
*
13
* Decides whether every interarrival and service law of a model lives on the
14
* slot lattice {slotLength, 2*slotLength, ...}, which is what lets SolverMAM
15
* take the discrete-time (Q-MAM) path instead of the continuous one.
16
*
17
* The test reads `procid`, `rates` and `scv` and NOT the fitted `proc`
18
* matrices: by the time a solver sees the struct a Geometric has already been
19
* converted to a CONTINUOUS MAP, so the lattice is no longer visible there. A
20
* DMAP is the exception, its (D0,D1) having MAP shape it survives verbatim.
21
* For the same reason this test must run BEFORE any phase-type conversion.
22
*
23
* ARITHMETIC: field, with one square root in the DiscreteUniform width. Every
24
* other test is a comparison, so the family instantiates under Rational apart
25
* from that branch, which needs a real square root.
26
*/
27
28
#include <cmath>
29
#include <cstddef>
30
#include <string>
31
32
#include "
line/lang/lang_types.h
"
33
#include "
line/lang/qn/network_struct.h
"
34
#include "
line/num/number.h
"
35
#include "
line/util/error.h
"
36
37
namespace
line
{
38
namespace
api
{
39
40
/** Which laws the model carries, and why it was refused when it was. */
41
struct
DiscreteTimeInfo
{
42
bool
has_lattice
=
false
;
///< some law lives on the slot lattice
43
bool
has_continuous
=
false
;
///< some law does not
44
bool
mixed
=
false
;
///< both, so no single time scale fits
45
bool
has_dmap
=
false
;
///< a DMAP is present, which has no continuous reading
46
std::string
reason
;
///< empty when the model is discrete-time
47
};
48
49
/** How the caller may override the automatic decision. */
50
struct
DiscreteTimeOptions
{
51
/** "auto", "discrete" or "continuous". */
52
std::string
timescale
=
"auto"
;
53
/** Slot length in model time units. */
54
double
slotlength
= 1.0;
55
};
56
57
namespace
detail {
58
59
/**
60
* Integral bounds of a DiscreteUniform recovered from its mean and SCV, using
61
* var = ((hi-lo+1)^2-1)/12. Returns false when the SCV is not usable.
62
*/
63
inline
bool
duniform_bounds(
double
mean_slots,
double
scv,
double
* lo,
double
* hi) {
64
if
(!std::isfinite(scv) || scv < 0)
return
false
;
65
const
double
var_slots = scv * mean_slots * mean_slots;
66
const
double
width = std::sqrt(std::max(0.0, 12 * var_slots + 1)) - 1;
67
*lo = std::round(mean_slots - width / 2);
68
*hi = std::round(mean_slots + width / 2);
69
return
true
;
70
}
71
72
}
// namespace detail
73
74
/**
75
* True when every law of `sn` is lattice-valued on `slot_length`.
76
*
77
* `slot_length` receives the slot in model time units and `info` the diagnosis.
78
* A DMAP mixed with continuous laws is an ERROR rather than a `false`: its
79
* (D0,D1) are probability matrices, so the continuous machinery would form
80
* inv(-D0) where the law needs inv(I-D0) and return a wrong number in silence.
81
*/
82
template
<
class
T>
83
bool
sn_is_discrete_time
(
const
qn::NetworkStruct<T>
&
sn
,
const
DiscreteTimeOptions
& options,
84
double
* slot_length,
DiscreteTimeInfo
* info) {
85
using
lang::ProcessType
;
86
87
const
std::string& timescale = options.
timescale
;
88
if
(timescale !=
"auto"
&& timescale !=
"discrete"
&& timescale !=
"continuous"
)
89
throw
InputError
(
90
"sn_is_discrete_time: timescale must be 'auto', 'discrete' or 'continuous'"
);
91
if
(!std::isfinite(options.
slotlength
) || options.
slotlength
<= 0)
92
throw
InputError
(
"sn_is_discrete_time: slotlength must be a positive finite scalar"
);
93
94
*slot_length = options.
slotlength
;
95
*info =
DiscreteTimeInfo
();
96
if
(timescale ==
"continuous"
)
return
false
;
97
98
const
double
tol = 1e-12;
99
for
(std::size_t ist = 0; ist <
sn
.nstations; ++ist)
100
for
(std::size_t r = 0; r <
sn
.nclasses; ++r) {
101
const
ProcessType pt =
sn
.procid(ist + 1, r + 1);
102
if
(pt == ProcessType::DISABLED || pt == ProcessType::NONE)
continue
;
103
if
(
sn
.disabled[ist][r])
continue
;
104
const
double
rate =
num_traits<T>::to_double
(
sn
.rates(ist, r));
105
if
(!std::isfinite(rate) || rate <= 0)
continue
;
// no interval law here
106
const
double
mean_slots = 1.0 / (rate * options.
slotlength
);
107
108
if
(pt == ProcessType::GEOMETRIC) {
109
// mean 1/p slots; p in (0,1] is recovered exactly from the mean
110
info->
has_lattice
=
true
;
111
if
(mean_slots < 1 - tol) {
112
info->
has_continuous
=
true
;
113
info->
reason
=
"a Geometric has a mean below the one-slot minimum of its "
114
"support {1,2,...}"
;
115
}
116
}
else
if
(pt == ProcessType::DMAP) {
117
info->
has_lattice
=
true
;
118
info->
has_dmap
=
true
;
119
}
else
if
(pt == ProcessType::DUNIFORM) {
120
info->
has_lattice
=
true
;
121
double
lo = 0, hi = 0;
122
if
(!detail::duniform_bounds(mean_slots,
num_traits<T>::to_double
(
sn
.scv(ist, r)),
123
&lo, &hi) ||
124
lo < 1 - tol) {
125
info->
has_continuous
=
true
;
126
info->
reason
=
"a DiscreteUniform spans a range not contained in {1,2,...}"
;
127
}
128
}
else
if
(pt == ProcessType::DET) {
129
if
(std::abs(mean_slots - std::round(mean_slots)) <= tol * std::max(1.0, mean_slots) &&
130
std::round(mean_slots) >= 1) {
131
info->
has_lattice
=
true
;
132
}
else
{
133
// a Det off the lattice is what makes the model continuous
134
info->
has_continuous
=
true
;
135
}
136
}
else
{
137
info->
has_continuous
=
true
;
138
}
139
}
140
141
info->
mixed
= info->
has_lattice
&& info->
has_continuous
;
142
143
if
(timescale ==
"discrete"
) {
144
if
(info->
mixed
)
145
throw
InputError
(
"sn_is_discrete_time: timescale='discrete' was requested but the "
146
"model mixes lattice and non-lattice laws: "
+
147
info->
reason
);
148
if
(!info->
has_lattice
)
149
throw
InputError
(
"sn_is_discrete_time: timescale='discrete' was requested but no "
150
"interarrival or service law is lattice-valued on the given slot"
);
151
return
true
;
152
}
153
154
const
bool
bool_out = info->
has_lattice
&& !info->
has_continuous
;
155
if
(!bool_out && info->
has_dmap
)
156
throw
InputError
(
"sn_is_discrete_time: the model mixes a DMAP with continuous-time laws. "
157
"A DMAP is only defined on a slotted time scale, so no solver can "
158
"interpret this model: "
+
159
info->
reason
);
160
if
(!bool_out && info->
reason
.empty() && info->
mixed
)
161
info->
reason
=
"the model mixes lattice-valued and continuous laws"
;
162
return
bool_out;
163
}
164
165
}
// namespace api
166
}
// namespace line
167
168
#endif
// LINE_API_SN_SN_IS_DISCRETE_TIME_H
line::InputError::InputError
InputError(const std::string &what)
Definition
error.h:39
line::qn::NetworkStruct
A network plus its refreshed NetworkStruct.
Definition
network_struct.h:838
error.h
The exception types the port throws.
lang_types.h
Enumerations and the minimal distribution descriptor shared by the model layer of the C++ port.
line::api
Definition
infer_fmlps.h:69
line::api::sn_is_discrete_time
bool sn_is_discrete_time(const qn::NetworkStruct< T > &sn, const DiscreteTimeOptions &options, double *slot_length, DiscreteTimeInfo *info)
True when every law of sn is lattice-valued on slot_length.
Definition
sn_is_discrete_time.h:83
line::lang::ProcessType
ProcessType
Distribution kinds, with the values of MATLAB ProcessType.
Definition
lang_types.h:483
line::sn
Definition
sn_gd_balance.h:42
line
Definition
aoi_dist2ph.h:52
network_struct.h
A queueing network and its refreshed NetworkStruct.
number.h
Number-type abstraction for the templated API port.
line::api::DiscreteTimeInfo
Which laws the model carries, and why it was refused when it was.
Definition
sn_is_discrete_time.h:41
line::api::DiscreteTimeInfo::mixed
bool mixed
both, so no single time scale fits
Definition
sn_is_discrete_time.h:44
line::api::DiscreteTimeInfo::has_dmap
bool has_dmap
a DMAP is present, which has no continuous reading
Definition
sn_is_discrete_time.h:45
line::api::DiscreteTimeInfo::has_lattice
bool has_lattice
some law lives on the slot lattice
Definition
sn_is_discrete_time.h:42
line::api::DiscreteTimeInfo::has_continuous
bool has_continuous
some law does not
Definition
sn_is_discrete_time.h:43
line::api::DiscreteTimeInfo::reason
std::string reason
empty when the model is discrete-time
Definition
sn_is_discrete_time.h:46
line::api::DiscreteTimeOptions
How the caller may override the automatic decision.
Definition
sn_is_discrete_time.h:50
line::api::DiscreteTimeOptions::timescale
std::string timescale
"auto", "discrete" or "continuous".
Definition
sn_is_discrete_time.h:52
line::api::DiscreteTimeOptions::slotlength
double slotlength
Slot length in model time units.
Definition
sn_is_discrete_time.h:54
line::num_traits
Definition
number.h:111
include
line
api
sn
sn_is_discrete_time.h
Generated by
1.18.0