5#ifndef LINE_API_QSYS_QSYS_RES_H
6#define LINE_API_QSYS_QSYS_RES_H
35#include <boost/math/special_functions/bessel.hpp>
36#include <boost/math/special_functions/gamma.hpp>
44template <
class T =
double>
56template <
class T =
double>
58 std::vector<QsysResFieldT<T>>
fields;
62 void set(
const std::string& name,
const T& v) { put(name, std::vector<T>{v},
true); }
64 void set(
const std::string& name,
const std::vector<T>& v) { put(name, v,
false); }
65 bool has(
const std::string& name)
const {
return find(name) !=
nullptr; }
67 T
scalar(
const std::string& name)
const {
69 if (f ==
nullptr || f->
value.empty())
throw Error(
"QsysRes: no field '" + name +
"'");
73 const std::vector<T>&
vec(
const std::string& name)
const {
75 if (f ==
nullptr)
throw Error(
"QsysRes: no field '" + name +
"'");
82 if (f.name == name)
return &f;
85 void put(
const std::string& name,
const std::vector<T>& v,
bool sc) {
86 for (QsysResFieldT<T>& f :
fields)
92 fields.push_back(QsysResFieldT<T>{name, v, sc});
111inline double gammaln(
double x) {
return std::lgamma(x); }
115 if (x <= 0.0)
return 1.0;
116 if (std::isinf(x))
return 0.0;
117 return boost::math::gamma_q(a, x);
122 if (x <= 0.0)
return 0.0;
123 if (std::isinf(x))
return 1.0;
124 return boost::math::gamma_p(a, x);
133 if (x < 600.0)
return boost::math::cyl_bessel_i(1.0, x) * std::exp(-x);
134 const double mu4 = 4.0;
135 double term = 1.0,
sum = 1.0;
136 for (
int k = 1; k <= 6; ++k) {
137 const double odd = 2.0 * k - 1.0;
138 term *= -(mu4 - odd * odd) / (k * 8.0 * x);
141 return sum / std::sqrt(2.0 * M_PI * x);
145inline std::vector<double>
geometric(
double c,
double r,
long nmax) {
146 std::vector<double> v(
static_cast<std::size_t
>(nmax + 1));
147 for (
long n = 0; n <= nmax; ++n) v[static_cast<std::size_t>(n)] = c * std::pow(r,
static_cast<double>(n));
156inline double ccdf_inverse(
const std::function<
double(
double)>& ccdf,
double target,
double hi) {
157 if (ccdf(0.0) <= target)
return 0.0;
159 while (ccdf(hi) > target) hi = 2.0 * hi;
160 for (
int it = 1; it <= 200; ++it) {
161 const double mid = (lo + hi) / 2.0;
162 if (ccdf(mid) > target) lo = mid;
164 if (hi - lo <= 1e-12 * std::max(1.0, hi))
break;
166 return (lo + hi) / 2.0;
170inline double vsum(
const std::vector<double>& x) {
172 for (
double v : x) s += v;
177inline std::vector<double>
lognormalize(
const std::vector<double>& logp,
const std::vector<double>& lognorm) {
178 double mx = -std::numeric_limits<double>::infinity();
179 for (
double v : lognorm) mx = std::max(mx, v);
181 for (
double v : lognorm) s += std::exp(v - mx);
182 const double ln = mx + std::log(s);
183 std::vector<double> p(logp.size());
184 for (std::size_t i = 0; i < logp.size(); ++i) p[i] = std::exp(logp[i] -
ln);
189inline std::vector<double>
cdf_of(
const std::function<
double(
double)>& ccdf,
const std::vector<double>& t) {
190 std::vector<double> v(t.size());
191 for (std::size_t i = 0; i < t.size(); ++i) v[i] = 1.0 - ccdf(t[i]);
196inline std::vector<double>
pct_of(
const std::function<
double(
double)>& ccdf,
const std::vector<double>& pct,
198 std::vector<double> v(pct.size());
199 for (std::size_t i = 0; i < pct.size(); ++i) v[i] =
ccdf_inverse(ccdf, 1.0 - pct[i] / 100.0, hi);
207 std::snprintf(buf,
sizeof buf,
"%g", rho);
208 throw InputError(
ErrorKind(
"Unstable"), std::string(fn) +
": unstable system: rho = " + buf +
" >= 1");
213[[noreturn]]
inline void throw_unstable(
const char* fn,
const char* what,
double v) {
215 std::snprintf(buf,
sizeof buf,
"%g", v);
216 throw InputError(
ErrorKind(
"Unstable"), std::string(fn) +
": unstable system: " + what +
" = " + buf +
" >= 1");
221 const std::string msg = std::string(fn) +
": unknown option '" + name +
"'";
231 const double v = std::exp(std::lgamma(n + 1.0) - std::lgamma(k + 1.0) - std::lgamma(n - k + 1.0));
232 return v < 4503599627370496.0 ? std::round(v) : v;
238 if (p <= 0.0 || p >= 100.0)
throw Error(std::string(fn) +
": percentiles must lie in (0, 100)");
Error(const std::string &what)
The exception types the port throws.
double vsum(const std::vector< double > &x)
sum(x)
std::vector< double > pct_of(const std::function< double(double)> &ccdf, const std::vector< double > &pct, double hi)
The percentiles by bisection, arrayfun(@(r) ccdf_inverse(ccdf, 1 - r/100, hi), pct).
std::vector< double > geometric(double c, double r, long nmax)
The 0:nmax power law c*r.
void throw_unknown_option(const char *fn, const std::string &name, bool argument_id)
MATLAB's "unknown option 'name'" refusal, as LINE:input:Argument or as a bare LINE:Error.
void throw_unstable(const char *fn, const char *what, double v)
A LINE:input:Unstable refusal "fn: unstable system: <what> = %g >= 1".
void require_stable(double rho, const char *fn)
The reference's LINE:input:Unstable refusal.
void check_percentiles(const std::vector< double > &pct, const char *fn)
A percentile vector checked against (0, 100), MATLAB's LINE:Error refusal.
double gammaln(double x)
MATLAB's gammaln.
double nchoosek_r(double n, double k)
The reference's nchoosek_r: exp(gammaln) rounded to the integer it is while that integer is exactly r...
double gammainc_lower(double x, double a)
MATLAB's gammainc(x, a, 'lower'), the regularized lower tail P(a, x).
double gammainc_upper(double x, double a)
MATLAB's gammainc(x, a, 'upper'), the regularized upper tail Q(a, x).
double besseli1_scaled(double x)
MATLAB's besseli(1, x, 1) = I_1(x) exp(-x), x >= 0.
std::vector< double > cdf_of(const std::function< double(double)> &ccdf, const std::vector< double > &t)
Fills out with 1 - ccdf(t) at each t, as 1 - arrayfun(ccdf, t).
double ccdf_inverse(const std::function< double(double)> &ccdf, double target, double hi)
The bisection inverse of a complementary CDF shared by the reference's functions (ccdf_inverse / mmck...
std::vector< double > lognormalize(const std::vector< double > &logp, const std::vector< double > &lognorm)
exp(logp - logsumexp(lognorm)), the reference's log-space normalization.
QsysResT< double > QsysRes
Conservation laws of a layered queueing network, enumerated from its structure.
One measure of a res struct: a scalar or a row vector.
The name-value options shared by the exact functions: tPoints, percentiles and nmax (a negative nmax ...
std::vector< double > percentiles
std::vector< double > tPoints
MATLAB's res struct: named measures in insertion order, plus res.analyzer.
void set(const std::string &name, const std::vector< T > &v)
Sets (or overwrites) a vector field.
std::vector< QsysResFieldT< double > > fields
bool has(const std::string &name) const
void set(const std::string &name, const T &v)
Sets (or overwrites) a scalar field.
const std::vector< T > & vec(const std::string &name) const
The vector field name; throws when absent.
T scalar(const std::string &name) const
The scalar field name; throws when absent.