LINE Solver (C++)
Templated C++ port of the LINE queueing solver
Loading...
Searching...
No Matches
snc_thetaopt.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_SNC_THETAOPT_H
6#define LINE_API_SNC_THETAOPT_H
7
8/**
9 * @file
10 * @ingroup api_snc
11 * Minimizes a Chernoff bound over the free parameter theta.
12 *
13 * Every bound in the snc domain holds for each theta > 0 for which the arrival
14 * MGF is finite and the station is stable, so the reported bound is the infimum
15 * over theta. The objective is evaluated on a logarithmic grid, non-finite
16 * values (a diverging MGF, an unstable leftover rate) are discarded, and the
17 * best grid point is refined by golden-section search in log10(theta).
18 *
19 * THE TWO-STAGE SEARCH IS NOT A CONVENIENCE: the feasible set is an interval
20 * whose endpoints are not known in closed form once envelopes are composed, and
21 * an unguarded local search steps into the infeasible region and terminates
22 * there.
23 *
24 * Port of matlab/src/api/snc/snc_thetaopt.m, whose refinement is `fminbnd`
25 * (golden section plus parabolic interpolation); the plain golden section here
26 * reaches the same optimum on these smooth objectives, as the JAR port does.
27 */
28
29#include <algorithm>
30#include <cmath>
31#include <exception>
32#include <functional>
33#include <limits>
34#include <vector>
36#include "line/util/error.h"
37
38namespace line {
39namespace snc {
40
41namespace detail {
42
43/** Substituted for a non-finite objective, so the search can still compare it. */
44constexpr double kSncInfeasible = 1e300;
45
46inline double snc_safeval(const std::function<double(double)>& fun, double theta) {
47 double v;
48 try {
49 v = fun(theta);
50 } catch (const std::exception&) {
51 return kSncInfeasible;
52 }
53 if (!std::isfinite(v)) return kSncInfeasible;
54 return v;
55}
56
57} // namespace detail
58
59/**
60 * @brief Minimizes a Chernoff bound over the free parameter theta.
61 *
62 * @param fun the objective, a function of theta
63 * @param thetamax upper end of the search range
64 * @return the minimum and its theta; (infinity, NaN) if nothing is feasible
65 */
66inline SncResult snc_thetaopt(const std::function<double(double)>& fun, double thetamax = 1e3) {
67 if (thetamax <= 0) throw UnsupportedError("snc_thetaopt: thetamax must be positive");
68 const int GRID = 600;
69 const double loExp = -6.0, hiExp = std::log10(thetamax);
70 std::vector<double> grid(GRID), fval(GRID);
71 int imin = 0;
72 for (int i = 0; i < GRID; ++i) {
73 grid[i] = std::pow(10.0, loExp + (hiExp - loExp) * i / (GRID - 1.0));
74 fval[i] = detail::snc_safeval(fun, grid[i]);
75 if (fval[i] < fval[imin]) imin = i;
76 }
77 double val = fval[imin];
78 if (val >= 1e299)
79 return SncResult{std::numeric_limits<double>::infinity(),
80 std::numeric_limits<double>::quiet_NaN()};
81 double theta = grid[imin];
82
83 double lo = std::log10(grid[std::max(imin - 1, 0)]);
84 double hi = std::log10(grid[std::min(imin + 1, GRID - 1)]);
85 if (hi > lo) {
86 const double invphi = (std::sqrt(5.0) - 1.0) / 2.0;
87 double x1 = hi - invphi * (hi - lo), x2 = lo + invphi * (hi - lo);
88 double f1 = detail::snc_safeval(fun, std::pow(10.0, x1));
89 double f2 = detail::snc_safeval(fun, std::pow(10.0, x2));
90 for (int it = 0; it < 200 && (hi - lo) > 1e-12; ++it) {
91 if (f1 < f2) {
92 hi = x2;
93 x2 = x1;
94 f2 = f1;
95 x1 = hi - invphi * (hi - lo);
96 f1 = detail::snc_safeval(fun, std::pow(10.0, x1));
97 } else {
98 lo = x1;
99 x1 = x2;
100 f1 = f2;
101 x2 = lo + invphi * (hi - lo);
102 f2 = detail::snc_safeval(fun, std::pow(10.0, x2));
103 }
104 }
105 const double xopt = 0.5 * (lo + hi);
106 const double vopt = detail::snc_safeval(fun, std::pow(10.0, xopt));
107 if (vopt < val) {
108 val = vopt;
109 theta = std::pow(10.0, xopt);
110 }
111 }
112 return SncResult{val, theta};
113}
114
115namespace detail {
116
117/** Both envelopes at one theta, with `ok=false` when the composition is infeasible. */
118struct SncPair {
119 bool ok = false;
120 Env a, s;
121};
122
123inline SncPair snc_pair(const Envelope& arv, const Envelope& srv, double theta) {
124 SncPair p;
125 p.a = arv(theta);
126 p.s = srv(theta);
127 p.ok = std::isfinite(p.a.sigma) && std::isfinite(p.a.rho) && std::isfinite(p.s.sigma) &&
128 std::isfinite(p.s.rho) && p.s.rho > p.a.rho;
129 return p;
130}
131
132} // namespace detail
133
134} // namespace snc
135} // namespace line
136
137#endif // LINE_API_SNC_THETAOPT_H
UnsupportedError(const std::string &what)
Definition error.h:51
The exception types the port throws.
std::function< Env(double)> Envelope
An envelope as a function of the Chernoff parameter.
Definition snc_types.h:48
SncResult snc_thetaopt(const std::function< double(double)> &fun, double thetamax=1e3)
Minimizes a Chernoff bound over the free parameter theta.
Shared types of the stochastic network calculus domain.
A bound together with the theta that attains it.
Definition snc_types.h:51