5#ifndef LINE_API_MAM_MAP_GAMMA_H
6#define LINE_API_MAM_MAP_GAMMA_H
55inline double map_gamma_ls(
const std::vector<double>& lag,
const std::vector<double>& rho,
56 double rho0,
double start,
const std::vector<double>& weights) {
57 const std::size_t m = lag.size();
58 std::vector<double> sw(m, 1.0);
60 for (std::size_t i = 0; i < m; ++i) sw[i] = std::sqrt(weights[i]);
62 const std::vector<double>* plag = &lag;
63 const std::vector<double>* prho = ρ
64 auto res = [plag, prho, &sw, rho0, m](
const std::vector<double>& x) {
65 std::vector<double> r(m);
66 for (std::size_t i = 0; i < m; ++i)
67 r[i] = sw[i] * (rho0 * std::pow(x[0], (*plag)[i]) - (*prho)[i]);
70 auto jac = [plag, &sw, rho0, m](
const std::vector<double>& x) {
71 Matrix<double> J(m, 1, 0.0);
72 for (std::size_t i = 0; i < m; ++i)
73 J(i, 0) = sw[i] * rho0 * (*plag)[i] * std::pow(x[0], (*plag)[i] - 1.0);
78 const LevmarResult<double> out =
levmar_jac(res, jac, std::vector<double>(1, start), m, opt);
83inline double map_gamma_median(std::vector<double> v) {
84 std::sort(v.begin(), v.end());
85 const std::size_t n = v.size();
86 if (n % 2 == 1)
return v[n / 2];
87 return 0.5 * (v[n / 2 - 1] + v[n / 2]);
91inline double map_gamma_fit(
const std::vector<double>& lag,
const std::vector<double>& rho,
92 double rho0,
double start) {
93 const std::size_t m = lag.size();
94 double gamma = map_gamma_ls(lag, rho, rho0, start, std::vector<double>());
99 for (std::size_t i = 0; i < m; ++i) {
100 const double j = rho0 * lag[i] * std::pow(gamma, lag[i] - 1.0);
103 std::vector<double> adjust(m);
104 for (std::size_t i = 0; i < m; ++i) {
105 const double j = rho0 * lag[i] * std::pow(gamma, lag[i] - 1.0);
106 const double h = norm2 > 0.0 ? std::min(0.9999, j * j / norm2) : 0.0;
107 adjust[i] = 1.0 / std::sqrt(1.0 - h);
113 for (std::size_t i = 0; i < m; ++i) mean += rho[i];
114 mean /=
static_cast<double>(m);
116 for (std::size_t i = 0; i < m; ++i) var += (rho[i] - mean) * (rho[i] - mean);
117 var /=
static_cast<double>(m - 1);
118 double tiny = 1e-6 * std::sqrt(var);
119 if (tiny == 0.0) tiny = 1.0;
121 const double tune = 1.4;
122 const double delta = std::sqrt(std::numeric_limits<double>::epsilon());
123 std::vector<double> weights(m);
124 for (
unsigned iter = 0; iter < 200; ++iter) {
125 const double previous = gamma;
126 std::vector<double> radj(m), absr(m);
127 for (std::size_t i = 0; i < m; ++i) {
128 radj[i] = (rho[i] - rho0 * std::pow(gamma, lag[i])) * adjust[i];
129 absr[i] = std::fabs(radj[i]);
131 const double sigma = map_gamma_median(absr) / 0.6745;
132 const double scale = std::max(sigma, tiny) * tune;
133 for (std::size_t i = 0; i < m; ++i) weights[i] = 1.0 / (1.0 + std::fabs(radj[i] / scale));
134 gamma = map_gamma_ls(lag, rho, rho0, previous, weights);
135 if (std::fabs(gamma - previous) <
136 delta * std::max(std::fabs(gamma), std::fabs(previous)))
157 if (limit < 1)
throw InputError(
"map_gamma: the lag limit must be positive");
162 const std::size_t n = m.
order();
163 if (n == 1)
return out;
165 const std::vector<T> a =
map_acf(m, std::vector<unsigned>{1u, 2u});
167 out.
gamma = a[1] / a[0];
170 const long step = std::max<long>(1, limit / 10);
171 std::vector<unsigned> lags;
172 for (
long l = 1; l <= limit; l += step) lags.push_back(
static_cast<unsigned>(l));
175 const T scv = (m2 - m1 * m1) / (m1 * m1);
176 if (scv == zero)
throw NumericError(
"map_gamma: the MAP has zero scv, rho0 is undefined");
179 const std::vector<T> acf =
map_acf(m, lags);
180 std::vector<double> dl(lags.size()), dr(lags.size());
181 for (std::size_t i = 0; i < lags.size(); ++i) {
182 dl[i] =
static_cast<double>(lags[i]);
NumericError(const std::string &what)
The exception types the port throws.
Levenberg-Marquardt for nonlinear least squares.
Markovian arrival process descriptors: stationary vectors, rate, moments, autocorrelation and the ind...
Dense matrix and non-owning view.
std::vector< T > map_acf(const Map< T > &m, const std::vector< unsigned > &lags)
Autocorrelation coefficients of the inter-arrival times at the given lags,.
T map_mean(const Map< T > &m)
Mean inter-arrival time, 1/lambda.
MapGammaResult< T > map_gamma_full(const Map< T > &m, long limit=1000)
T map_moment(const Map< T > &m, unsigned k)
Raw moment of order k of the inter-arrival time: k!
T map_gamma(const Map< T > &m, long limit=1000)
Autocorrelation decay rate of a MAP (map_gamma.m).
LevmarResult< T > levmar_jac(F f, J jac, const std::vector< T > &x0, std::size_t m, const LevmarOptions< T > &opt)
Levenberg-Marquardt with a caller-supplied Jacobian.
LevmarOptions< T > levmar_defaults()
MINPACK-like defaults, with a central-difference step of eps^(1/3).
Number-type abstraction for the templated API port.
Result of map_gamma, mirroring the MATLAB [GAMMA, RHO0] pair.
T gamma
the fitted geometric decay rate of the acf
T rho0
(1 - 1/scv)/2, the lag-0 amplitude; zero below order three
A MAP as the pair of matrices (D0, D1).
std::size_t order() const