LINE Solver (C++)
Templated C++ port of the LINE queueing solver
Loading...
Searching...
No Matches
sn_arrival_rate_fun.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_ARRIVAL_RATE_FUN_H
6#define LINE_API_SN_SN_ARRIVAL_RATE_FUN_H
7
8/**
9 * @file
10 * @ingroup api_sn
11 * Port of matlab/src/api/sn/sn_arrival_rate_fun.m.
12 *
13 * The arrival rate of a station-class pair AS A FUNCTION OF TIME. The
14 * time-varying analyses (Mt/G/inf, the modified offered load, the Gt/Mt/st+GI
15 * fluid queue) consume lambda(t) itself, not a mean rate: their whole content
16 * is the LAG between when work arrives and when it is felt, and a time-averaged
17 * rate has no lag. LINE carries a time-varying arrival as an NHPP or a MAPt,
18 * whose schedule is piecewise constant, so lambda(t) is read off the segment in
19 * force at t.
20 *
21 * For any other process the rate is constant and the handle returns it, which
22 * is what lets a caller ask for the time-varying analysis of a stationary model
23 * and get the stationary answer rather than an error.
24 *
25 * ARITHMETIC: field. map_pie is a linear solve; no transcendental appears.
26 */
27
28#include <cmath>
29#include <cstddef>
30#include <functional>
31#include <limits>
32#include <vector>
33
37#include "line/num/number.h"
38
39namespace line {
40namespace api {
41
42/** lambda(t), with whether it actually varies and the cycle length. */
43template <class T>
45 std::function<T(const T&)> lambda; ///< the rate as a function of time
46 bool timeVarying = false; ///< whether it depends on t at all
47 double period = std::numeric_limits<double>::infinity(); ///< cycle length when cyclic
48};
49
50/**
51 * Build lambda(t) for station `ist` (0-based), class `r`.
52 */
53template <class T>
55 std::size_t r) {
57 const T rate = sn.rates(ist, r);
58 const lang::Distrib<T>& d = sn.service[ist][r];
59 if (!d.has_schedule()) {
60 out.lambda = [rate](const T&) { return rate; };
61 return out;
62 }
63 // The schedule is ALREADY in MAP form here: `sched_D0[k]`, `sched_D1[k]` are
64 // the pair of segment k for a MAPt and for a PHt alike, the PHt having been
65 // converted on the way in. An NHPP is the one-phase case, whose D1 entry IS
66 // its lambda.
67 const std::vector<T> bp = d.sched_bp;
68 const std::size_t n = d.sched_D0.size();
69 std::vector<T> seg(n, num_traits<T>::from_int(0));
70 for (std::size_t k = 0; k < n; ++k) {
71 const Matrix<T>& D0 = d.sched_D0[k];
72 const Matrix<T>& D1 = d.sched_D1[k];
73 if (D0.rows() == 1) {
74 seg[k] = D1(0, 0);
75 } else {
76 // The arrival rate of a segment is pie_k D1_k e, the stationary
77 // throughput of that segment's own MAP.
79 m.D0 = D0;
80 m.D1 = D1;
81 const std::vector<T> pie = mam::map_pie(m);
83 for (std::size_t i = 0; i < D1.rows(); ++i)
84 for (std::size_t j = 0; j < D1.cols(); ++j) v = T(v + pie[i] * D1(i, j));
85 seg[k] = v;
86 }
87 }
88 for (std::size_t k = 1; k < n; ++k)
89 if (std::fabs(num_traits<T>::to_double(seg[k]) - num_traits<T>::to_double(seg[0])) > 1e-12)
90 out.timeVarying = true;
91 const bool cyclic = d.sched_cyclic;
92 if (cyclic && bp.size() >= 2)
93 out.period = num_traits<T>::to_double(bp.back()) - num_traits<T>::to_double(bp.front());
94 out.lambda = [bp, seg, cyclic](const T& t) {
95 T u = t;
96 if (cyclic && bp.size() >= 2 && bp.back() > bp.front()) {
97 const double span = num_traits<T>::to_double(bp.back() - bp.front());
98 double x = num_traits<T>::to_double(t) - num_traits<T>::to_double(bp.front());
99 x = std::fmod(std::fmod(x, span) + span, span);
100 u = T(bp.front() + num_traits<T>::from_double(x));
101 }
102 // Segment k is in force on [bp[k], bp[k+1]). Before the first breakpoint
103 // the first segment holds and after the last the last one does, so a
104 // caller integrating over an infinite past (the Mt/G/inf convolution)
105 // gets a defined rate everywhere rather than a NaN.
106 std::size_t k = 0;
107 for (std::size_t i = 0; i + 1 < bp.size(); ++i)
108 if (u >= bp[i]) k = i;
109 if (k >= seg.size()) k = seg.size() - 1;
110 return seg[k];
111 };
112 return out;
113}
114
115} // namespace api
116} // namespace line
117
118#endif // LINE_API_SN_SN_ARRIVAL_RATE_FUN_H
std::size_t cols() const
Definition matrix.h:90
std::size_t rows() const
Definition matrix.h:89
A network plus its refreshed NetworkStruct.
What refreshProcessRepresentations and refreshLST compute FROM a distribution: the (D0,...
Markovian arrival process descriptors: stationary vectors, rate, moments, autocorrelation and the ind...
ArrivalRateFun< T > sn_arrival_rate_fun(const qn::NetworkStruct< T > &sn, std::size_t ist, std::size_t r)
Build lambda(t) for station ist (0-based), class r.
std::vector< T > map_pie(const Map< T > &m)
Phase distribution seen by an arriving job, pie = pi D1 / (pi D1 e).
Definition map_moment.h:89
A queueing network and its refreshed NetworkStruct.
Number-type abstraction for the templated API port.
lambda(t), with whether it actually varies and the cycle length.
std::function< T(const T &)> lambda
the rate as a function of time
bool timeVarying
whether it depends on t at all
double period
cycle length when cyclic
std::vector< T > sched_bp
sn.proc{i}{r} = {breakpoints, A, B, cyclic} of a MAPt / PHt / NHPP.
Definition lang_types.h:794
bool has_schedule() const
Definition lang_types.h:797
std::vector< Matrix< T > > sched_D1
Definition lang_types.h:795
std::vector< Matrix< T > > sched_D0
Definition lang_types.h:795
A MAP as the pair of matrices (D0, D1).
Definition map_moment.h:53
Matrix< T > D1
Definition map_moment.h:55
Matrix< T > D0
Definition map_moment.h:54