5#ifndef LINE_API_MAPQN_MAPQN_QRF_BAS_NLP_H
6#define LINE_API_MAPQN_MAPQN_QRF_BAS_NLP_H
71 const std::vector<char> zeroed = detail::bas_zero(p, x, m);
72 detail::bas_one(p, x, m);
73 detail::bas_symmetry(p, x, m, zeroed);
74 detail::bas_marginals(p, x, m);
75 detail::bas_ueff(p, x, m);
76 detail::bas_thm1(p, x, m);
77 detail::bas_thm2(p, x, m);
78 detail::bas_cor1(p, x, m);
79 detail::bas_thm30(p, x, m);
80 detail::bas_thm3(p, x, m);
81 detail::bas_thm3f(p, x, m);
82 detail::bas_thm3i(p, x, m);
83 detail::bas_thm3l(p, x, m);
84 detail::bas_thm4(p, x, m);
110 std::vector<std::size_t>* ii, std::vector<std::size_t>* jj,
112 for (
int m = 0; m < x.
MR; ++m)
113 for (
int i = 0; i < x.
M; ++i)
114 for (
int ki = 0; ki < x.
K[i]; ++ki)
115 for (
int j = 0; j < x.
M; ++j) {
116 if (i == j)
continue;
117 for (
int kj = 0; kj < x.
K[j]; ++kj)
118 for (
int ni = n_from; ni <= F[i]; ++ni)
119 for (
int nj = n_from; nj <= F[j]; ++nj) {
120 ij->push_back(x.
p2(i, ni, ki, j, nj, kj, m));
121 ii->push_back(x.
p2(i, ni, ki, i, ni, ki, m));
122 jj->push_back(x.
p2(j, nj, kj, j, nj, kj, m));
130 std::vector<std::size_t> out;
131 for (
int m = 0; m < x.
MR; ++m)
132 for (
int i = 0; i < x.
M; ++i)
133 for (
int k = 0; k < x.
K[i]; ++k)
134 for (
int ni = n_from; ni <= F[i]; ++ni) out.push_back(x.
p2(i, ni, k, i, ni, k, m));
157 unsigned max_iter = 200) {
167 const std::string name =
168 bethe ?
"qrf_bas_bethe" : (mem ?
"qrf_bas_mem" :
"qrf_bas_mmi");
174 std::vector<std::size_t> ij, ii, jj, diag;
179 ": the model has no marginal variables, so the objective is empty");
185 ": the model has no off-diagonal joint variables, so the mutual "
186 "information objective is empty");
194 auto objective = [&](
const std::vector<T>& z) -> T {
196 for (std::size_t t = 0; t < diag.size(); ++t) {
197 const T pv = z[diag[t]];
200 for (std::size_t t = 0; t < ij.size(); ++t) {
201 const T pij = z[ij[t]], pii = z[ii[t]], pjj = z[jj[t]];
202 f += T(mi_scale * pij *
207 auto gradient = [&](
const std::vector<T>& z) -> std::vector<T> {
209 for (std::size_t t = 0; t < diag.size(); ++t) {
210 const T pv = z[diag[t]];
211 g[diag[t]] += T(
qrf_log<T>(tol + pv) + pv / (tol + pv));
213 for (std::size_t t = 0; t < ij.size(); ++t) {
214 const T pij = z[ij[t]], pii = z[ii[t]], pjj = z[jj[t]];
217 g[ii[t]] -= T(mi_scale * pij / (tol + pii));
218 g[jj[t]] -= T(mi_scale * pij / (tol + pjj));
224 const std::vector<T> xopt =
solve_qrf_nlp_lp(objective, gradient, x0, poly, name, max_iter);
244 for (
int i = 0; i < p.
M; ++i)
245 for (
int ki = 0; ki < p.
K[i]; ++ki)
246 out.
UN[
static_cast<std::size_t
>(i)] += T(xopt[x.
e(i, ki)] * inv_m);
247 for (
int i = 0; i < p.
M; ++i)
248 for (
int m = 0; m < p.
MR; ++m)
249 for (
int ni = 1; ni <= p.
F[i]; ++ni)
250 for (
int ki = 0; ki < p.
K[i]; ++ki)
251 out.
QN[
static_cast<std::size_t
>(i)] +=
Sparse LP in the natural form, with per-variable bounds.
The exception types the port throws.
A sparse LP backend for line::lp::LpModel, on HiGHS (MIT).
Quadratic-reduction bound on the utilization of one queue of a closed MAP queueing network with a FIN...
Shared machinery of the QRF nonlinear bounds (qrf_noblo_*, qrf_bas_*).
void mmi_terms(const QrBasIndex &x, const std::vector< int > &F, std::vector< std::size_t > *ij, std::vector< std::size_t > *ii, std::vector< std::size_t > *jj, int n_from=1)
The (ij, ii, jj) column triples of the MI objective, i != j, ni, nj >= n_from.
lp::LpModel< T > bas_polytope(const QrBasParams< T > &p, const QrBasIndex &x)
The BAS feasible set, built by the same calls the LP bound makes.
std::vector< std::size_t > mem_terms(const QrBasIndex &x, const std::vector< int > &F, int n_from=1)
The diagonal columns of the MEM objective, ni >= n_from (1 for MEM, 0 for BETHE).
Objective
Which functional mapqn_qrf_bas minimizes over the BAS polytope.
std::vector< T > qrf_feasible_start_lp(const lp::LpModel< T > &polytope, const std::string &name)
A feasible point of an LpModel polytope: the MINIMUM-NORM one.
QrfMetrics< T > mapqn_qrf_bas_mmi(const QrBasParams< T > &p, unsigned max_iter=200)
Minimum-mutual-information bound on the BAS-blocking polytope.
QrfMetrics< T > mapqn_qrf_bas_bethe(const QrBasParams< T > &p, unsigned max_iter=200)
Tree-reweighted (Bethe) free entropy bound on the BAS-blocking polytope.
QrfMetrics< T > mapqn_qrf_bas_mem(const QrBasParams< T > &p, unsigned max_iter=200)
Maximum-entropy bound on the BAS-blocking polytope.
QrfMetrics< T > mapqn_qrf_bas(const QrBasParams< T > &p, qrfbas::Objective obj, unsigned max_iter=200)
Solve one BAS-blocking NLP bound.
std::vector< T > solve_qrf_nlp_lp(Obj objective, Grad gradient, const std::vector< T > &x0, const lp::LpModel< T > &polytope, const std::string &name, unsigned max_iter=200, double gap_tol=1e-10)
Minimize a convex objective over {Aeq x = beq, Aub x <= bub, 0 <= x <= 1}, starting from a feasible p...
T qrf_logtol()
The reference's LOGTOL: the shift that keeps log() off zero.
T qrf_log(const T &v)
log() in the working arithmetic.
Number-type abstraction for the templated API port.
Templated primal simplex with Bland's rule.
Variable layout: p2(j,nj,kj,i,ni,hi,m) then e(i,ki).
std::size_t num_vars() const
std::size_t p2(int j, int nj, int kj, int i, int ni, int hi, int m) const
std::size_t e(int i, int ki) const
Parameters of the BAS bound, mirroring the reference's params.
std::vector< int > F
(M) capacity of each queue
std::vector< int > K
(M) number of phases of each queue
int MR
number of blocking configurations
The utilizations and queue lengths read off an optimal pair tensor.