LINE Solver (C++)
Templated C++ port of the LINE queueing solver
Toggle main menu visibility
Loading...
Searching...
No Matches
fes_map_interp.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_FES_MAP_INTERP_H
6
#define LINE_API_FES_MAP_INTERP_H
7
8
/**
9
* @file
10
* @ingroup api_fes
11
* Shape-preserving interpolation of the flow-equivalent descriptors, and the
12
* population grid they are evaluated on.
13
*
14
* Templated port of matlab/src/api/fes/fes_map_interp.m, fes_map_interp_edge.m and
15
* fes_map_grid.m, mirrored by the JAR and native Python.
16
*
17
* Fritsch and Carlson slopes are used, with the noncentered three-point endpoint
18
* rule of de Boor, so the interpolant never overshoots and a monotone sequence of
19
* throughputs stays monotone. The algorithm is written out rather than delegated
20
* to MATLAB's pchip so that the four codebases return identical values; the
21
* MATLAB port is checked against the built-in to machine precision.
22
*
23
* ARITHMETIC: field operations only, exact at T = Rational.
24
*/
25
26
#include <algorithm>
27
#include <cmath>
28
#include <cstddef>
29
#include <vector>
30
31
#include "
line/num/number.h
"
32
#include "
line/util/matrix.h
"
33
34
namespace
line
{
35
namespace
fes
{
36
37
/** Leading populations kept in full by the default grid. */
38
const
std::size_t
FES_MAP_GRID_NHEAD
= 10;
39
/** Equispaced points above them. */
40
const
std::size_t
FES_MAP_GRID_NTAIL
= 10;
41
42
/**
43
* Populations at which the inter-departure MAP is evaluated. Fitting one MAP per
44
* population is wasteful because the processes of neighbouring populations are
45
* similar; the reference evaluates the first ten populations and ten further
46
* equispaced points.
47
*/
48
inline
std::vector<std::size_t>
fes_map_grid
(std::size_t n, std::size_t nhead =
FES_MAP_GRID_NHEAD
,
49
std::size_t ntail =
FES_MAP_GRID_NTAIL
) {
50
std::vector<std::size_t> grid;
51
if
(n <= nhead + ntail) {
52
for
(std::size_t k = 1; k <= n; ++k) grid.push_back(k);
53
return
grid;
54
}
55
std::vector<bool> taken(n + 1,
false
);
56
for
(std::size_t k = 1; k <= nhead; ++k) taken[k] =
true
;
57
for
(std::size_t j = 0; j < ntail; ++j) {
58
const
double
t = (ntail == 1) ?
static_cast<
double
>
(n)
59
:
static_cast<
double
>
(nhead + 1) +
60
static_cast<
double
>
(j) *
61
static_cast<
double
>
(n - nhead - 1) /
62
static_cast<
double
>
(ntail - 1);
63
taken[
static_cast<
std::size_t
>
(std::llround(t))] =
true
;
64
}
65
for
(std::size_t k = 1; k <= n; ++k)
66
if
(taken[k]) grid.push_back(k);
67
return
grid;
68
}
69
70
namespace
detail {
71
72
/** Noncentered three-point endpoint slope with the monotonicity clamps of de Boor. */
73
template
<
class
T>
74
T interp_edge(
const
T& h1,
const
T& h2,
const
T& del1,
const
T& del2) {
75
const
T zero =
num_traits<T>::from_int
(0);
76
const
T two =
num_traits<T>::from_int
(2);
77
const
T three =
num_traits<T>::from_int
(3);
78
const
T d = T(((two * h1 + h2) * del1 - h1 * del2) / (h1 + h2));
79
const
int
sd = (d > zero) - (d < zero);
80
const
int
s1 = (del1 > zero) - (del1 < zero);
81
const
int
s2 = (del2 > zero) - (del2 < zero);
82
if
(sd != s1)
return
zero;
83
const
T ad = (d < zero) ? T(-d) : d;
84
const
T a1 = (del1 < zero) ? T(-(three * del1)) : T(three * del1);
85
if
(s1 != s2 && ad > a1)
return
three * del1;
86
return
d;
87
}
88
89
}
// namespace detail
90
91
/**
92
* Monotone piecewise cubic Hermite interpolation of one series.
93
*
94
* @param x sample abscissae, strictly increasing
95
* @param y sample values
96
* @param xq query abscissae
97
*/
98
template
<
class
T>
99
std::vector<T>
fes_map_interp
(
const
std::vector<T>& x,
const
std::vector<T>& y,
100
const
std::vector<T>& xq) {
101
const
std::size_t n = x.size();
102
const
T zero =
num_traits<T>::from_int
(0);
103
const
T two =
num_traits<T>::from_int
(2);
104
const
T three =
num_traits<T>::from_int
(3);
105
std::vector<T> yq(xq.size(), zero);
106
if
(n == 1) {
107
for
(std::size_t q = 0; q < xq.size(); ++q) yq[q] = y[0];
108
return
yq;
109
}
110
111
std::vector<T> h(n - 1), delta(n - 1);
112
for
(std::size_t i = 0; i + 1 < n; ++i) {
113
h[i] = x[i + 1] - x[i];
114
delta[i] = T((y[i + 1] - y[i]) / h[i]);
115
}
116
117
std::vector<T> d(n, zero);
118
if
(n == 2) {
119
d[0] = delta[0];
120
d[1] = delta[0];
121
}
else
{
122
for
(std::size_t i = 1; i + 1 < n; ++i) {
123
if
(delta[i - 1] * delta[i] > zero) {
124
const
T w1 = two * h[i] + h[i - 1];
125
const
T w2 = h[i] + two * h[i - 1];
126
d[i] = T((w1 + w2) / (w1 / delta[i - 1] + w2 / delta[i]));
127
}
128
}
129
d[0] = detail::interp_edge(h[0], h[1], delta[0], delta[1]);
130
d[n - 1] = detail::interp_edge(h[n - 2], h[n - 3], delta[n - 2], delta[n - 3]);
131
}
132
133
for
(std::size_t q = 0; q < xq.size(); ++q) {
134
const
T t = xq[q];
135
std::size_t i;
136
if
(!(t > x[0])) {
137
i = 0;
138
}
else
if
(!(t < x[n - 1])) {
139
i = n - 2;
140
}
else
{
141
i = 0;
142
while
(i + 2 < n && !(x[i + 1] > t)) ++i;
143
}
144
const
T s = t - x[i];
145
const
T c2 = T((three * delta[i] - two * d[i] - d[i + 1]) / h[i]);
146
const
T c3 = T((d[i] - two * delta[i] + d[i + 1]) / (h[i] * h[i]));
147
yq[q] = y[i] + s * (d[i] + s * (c2 + s * c3));
148
}
149
return
yq;
150
}
151
152
}
// namespace fes
153
}
// namespace line
154
155
#endif
// LINE_API_FES_MAP_INTERP_H
matrix.h
Dense matrix and non-owning view.
line::fes
Definition
fes_aggregate.h:79
line::fes::FES_MAP_GRID_NTAIL
const std::size_t FES_MAP_GRID_NTAIL
Equispaced points above them.
Definition
fes_map_interp.h:40
line::fes::FES_MAP_GRID_NHEAD
const std::size_t FES_MAP_GRID_NHEAD
Leading populations kept in full by the default grid.
Definition
fes_map_interp.h:38
line::fes::fes_map_interp
std::vector< T > fes_map_interp(const std::vector< T > &x, const std::vector< T > &y, const std::vector< T > &xq)
Monotone piecewise cubic Hermite interpolation of one series.
Definition
fes_map_interp.h:99
line::fes::fes_map_grid
std::vector< std::size_t > fes_map_grid(std::size_t n, std::size_t nhead=FES_MAP_GRID_NHEAD, std::size_t ntail=FES_MAP_GRID_NTAIL)
Populations at which the inter-departure MAP is evaluated.
Definition
fes_map_interp.h:48
line
Definition
aoi_dist2ph.h:52
number.h
Number-type abstraction for the templated API port.
line::num_traits
Definition
number.h:111
include
line
api
fes
fes_map_interp.h
Generated by
1.18.0