5#ifndef LINE_API_MAPQN_MAPQN_QRF_COMMON_H
6#define LINE_API_MAPQN_MAPQN_QRF_COMMON_H
130 std::size_t
p2_at(std::size_t j, std::size_t nj, std::size_t k, std::size_t i,
131 std::size_t ni, std::size_t h, std::size_t m)
const {
132 return (((((j * (
N + 1) + nj) *
Kmax + k) *
M + i) * (
N + 1) + ni) *
Kmax + h) *
MR + m;
134 const T&
p(std::size_t j, std::size_t nj, std::size_t k, std::size_t i, std::size_t ni,
135 std::size_t h, std::size_t m)
const {
136 return p2[
p2_at(j, nj, k, i, ni, h, m)];
138 T&
p(std::size_t j, std::size_t nj, std::size_t k, std::size_t i, std::size_t ni,
139 std::size_t h, std::size_t m) {
140 return p2[
p2_at(j, nj, k, i, ni, h, m)];
166inline std::size_t
qrf_num_vars(std::size_t M, std::size_t N,
const std::vector<int>& K,
168 std::size_t outer = 0, phases = 0;
169 for (std::size_t i = 0; i < M; ++i) {
170 outer += (N + 1) *
static_cast<std::size_t
>(K[i]);
171 phases +=
static_cast<std::size_t
>(K[i]);
173 return outer * outer * MR + phases;
183inline std::vector<long>
qrf_index_map(std::size_t M, std::size_t N,
const std::vector<int>& K,
185 const std::size_t Kmax =
static_cast<std::size_t
>(*std::max_element(K.begin(), K.end()));
191 std::vector<long> idx(M * (N + 1) * Kmax * M * (N + 1) * Kmax * MR, -1);
193 for (std::size_t j = 0; j < M; ++j)
194 for (std::size_t nj = 0; nj <= N; ++nj)
195 for (std::size_t k = 0; k < static_cast<std::size_t>(K[j]); ++k)
196 for (std::size_t i = 0; i < M; ++i)
197 for (std::size_t ni = 0; ni <= N; ++ni)
198 for (std::size_t h = 0; h < static_cast<std::size_t>(K[i]); ++h)
199 for (std::size_t m = 0; m < MR; ++m)
200 idx[shape.
p2_at(j, nj, k, i, ni, h, m)] = ctr++;
207 const std::vector<int>& K, std::size_t MR) {
209 const std::size_t Kmax =
static_cast<std::size_t
>(*std::max_element(K.begin(), K.end()));
215 out.
p2.assign(M * (N + 1) * Kmax * M * (N + 1) * Kmax * MR, zero);
216 out.
e.assign(M * Kmax, zero);
218 for (std::size_t j = 0; j < M; ++j)
219 for (std::size_t nj = 0; nj <= N; ++nj)
220 for (std::size_t k = 0; k < static_cast<std::size_t>(K[j]); ++k)
221 for (std::size_t i = 0; i < M; ++i)
222 for (std::size_t ni = 0; ni <= N; ++ni)
223 for (std::size_t h = 0; h < static_cast<std::size_t>(K[i]); ++h)
224 for (std::size_t m = 0; m < MR; ++m)
225 out.
p(j, nj, k, i, ni, h, m) = x[ctr++];
226 for (std::size_t i = 0; i < M; ++i)
227 for (std::size_t k = 0; k < static_cast<std::size_t>(K[i]); ++k)
228 out.
e[i * Kmax + k] = x[ctr++];
235 throw InputError(
"sub_qrfvar: the decision vector is shorter than the layout requires");
247 const std::vector<int>& K,
const std::vector<int>& F, std::size_t MR) {
251 for (std::size_t m = 0; m < MR; ++m)
252 for (std::size_t i = 0; i < M; ++i)
253 for (std::size_t ki = 0; ki < static_cast<std::size_t>(K[i]); ++ki)
254 for (std::size_t j = 0; j < M; ++j) {
255 if (i == j)
continue;
256 for (std::size_t kj = 0; kj < static_cast<std::size_t>(K[j]); ++kj)
257 for (std::size_t ni = 0; ni <= static_cast<std::size_t>(F[i]); ++ni)
258 for (std::size_t nj = 0; nj <= static_cast<std::size_t>(F[j]); ++nj) {
259 const T pij = v.
p(i, ni, ki, j, nj, kj, m);
260 const T pii = v.
p(i, ni, ki, i, ni, ki, m);
261 const T pjj = v.
p(j, nj, kj, j, nj, kj, m);
279 const std::vector<int>& K,
const std::vector<int>& F, std::size_t MR) {
283 for (std::size_t m = 0; m < MR; ++m)
284 for (std::size_t i = 0; i < M; ++i)
285 for (std::size_t k = 0; k < static_cast<std::size_t>(K[i]); ++k)
286 for (std::size_t ni = 1; ni <= static_cast<std::size_t>(F[i]); ++ni) {
287 const T pv = v.
p(i, ni, k, i, ni, k, m);
302std::vector<T>
mmi_gradient(
const std::vector<T>& x, std::size_t M, std::size_t N,
303 const std::vector<int>& K,
const std::vector<int>& F, std::size_t MR,
304 const std::vector<long>& idx) {
308 for (std::size_t m = 0; m < MR; ++m)
309 for (std::size_t i = 0; i < M; ++i)
310 for (std::size_t ki = 0; ki < static_cast<std::size_t>(K[i]); ++ki)
311 for (std::size_t j = 0; j < M; ++j) {
312 if (i == j)
continue;
313 for (std::size_t kj = 0; kj < static_cast<std::size_t>(K[j]); ++kj)
314 for (std::size_t ni = 0; ni <= static_cast<std::size_t>(F[i]); ++ni) {
315 const T pii = v.
p(i, ni, ki, i, ni, ki, m);
316 const long iii = idx[v.
p2_at(i, ni, ki, i, ni, ki, m)];
317 for (std::size_t nj = 0; nj <= static_cast<std::size_t>(F[j]); ++nj) {
318 const T pij = v.
p(i, ni, ki, j, nj, kj, m);
319 const T pjj = v.
p(j, nj, kj, j, nj, kj, m);
320 const long iij = idx[v.
p2_at(i, ni, ki, j, nj, kj, m)];
321 const long ijj = idx[v.
p2_at(j, nj, kj, j, nj, kj, m)];
326 if (iii >= 0) g[iii] -= pij / (tol + pii);
327 if (ijj >= 0) g[ijj] -= pij / (tol + pjj);
336std::vector<T>
mem_gradient(
const std::vector<T>& x, std::size_t M, std::size_t N,
337 const std::vector<int>& K,
const std::vector<int>& F, std::size_t MR,
338 const std::vector<long>& idx) {
342 for (std::size_t m = 0; m < MR; ++m)
343 for (std::size_t i = 0; i < M; ++i)
344 for (std::size_t k = 0; k < static_cast<std::size_t>(K[i]); ++k)
345 for (std::size_t ni = 1; ni <= static_cast<std::size_t>(F[i]); ++ni) {
346 const T pv = v.
p(i, ni, k, i, ni, k, m);
347 const long ip = idx[v.
p2_at(i, ni, k, i, ni, k, m)];
349 g[ip] +=
qrf_log<T>(tol + pv) + pv / (tol + pv);
384 const std::vector<int>& K,
const std::vector<int>& F, std::size_t MR) {
389 for (std::size_t m = 0; m < MR; ++m)
390 for (std::size_t i = 0; i < M; ++i)
391 for (std::size_t ki = 0; ki < static_cast<std::size_t>(K[i]); ++ki)
392 for (std::size_t j = 0; j < M; ++j) {
393 if (i == j)
continue;
394 for (std::size_t kj = 0; kj < static_cast<std::size_t>(K[j]); ++kj)
395 for (std::size_t ni = 0; ni <= static_cast<std::size_t>(F[i]); ++ni)
396 for (std::size_t nj = 0; nj <= static_cast<std::size_t>(F[j]); ++nj) {
397 const T pij = v.
p(i, ni, ki, j, nj, kj, m);
398 const T pii = v.
p(i, ni, ki, i, ni, ki, m);
399 const T pjj = v.
p(j, nj, kj, j, nj, kj, m);
400 fobj += lambda * pij * (
qrf_log<T>(tol + pij) -
405 for (std::size_t m = 0; m < MR; ++m)
406 for (std::size_t i = 0; i < M; ++i)
407 for (std::size_t k = 0; k < static_cast<std::size_t>(K[i]); ++k)
408 for (std::size_t ni = 0; ni <= static_cast<std::size_t>(F[i]); ++ni) {
409 const T pv = v.
p(i, ni, k, i, ni, k, m);
425std::vector<T>
bethe_gradient(
const std::vector<T>& x, std::size_t M, std::size_t N,
426 const std::vector<int>& K,
const std::vector<int>& F, std::size_t MR,
427 const std::vector<long>& idx) {
432 for (std::size_t m = 0; m < MR; ++m)
433 for (std::size_t i = 0; i < M; ++i)
434 for (std::size_t ki = 0; ki < static_cast<std::size_t>(K[i]); ++ki)
435 for (std::size_t j = 0; j < M; ++j) {
436 if (i == j)
continue;
437 for (std::size_t kj = 0; kj < static_cast<std::size_t>(K[j]); ++kj)
438 for (std::size_t ni = 0; ni <= static_cast<std::size_t>(F[i]); ++ni) {
439 const T pii = v.
p(i, ni, ki, i, ni, ki, m);
440 const long iii = idx[v.
p2_at(i, ni, ki, i, ni, ki, m)];
441 for (std::size_t nj = 0; nj <= static_cast<std::size_t>(F[j]); ++nj) {
442 const T pij = v.
p(i, ni, ki, j, nj, kj, m);
443 const T pjj = v.
p(j, nj, kj, j, nj, kj, m);
444 const long iij = idx[v.
p2_at(i, ni, ki, j, nj, kj, m)];
445 const long ijj = idx[v.
p2_at(j, nj, kj, j, nj, kj, m)];
450 if (iii >= 0) g[iii] -= lambda * pij / (tol + pii);
451 if (ijj >= 0) g[ijj] -= lambda * pij / (tol + pjj);
455 for (std::size_t m = 0; m < MR; ++m)
456 for (std::size_t i = 0; i < M; ++i)
457 for (std::size_t k = 0; k < static_cast<std::size_t>(K[i]); ++k)
458 for (std::size_t ni = 0; ni <= static_cast<std::size_t>(F[i]); ++ni) {
459 const T pv = v.
p(i, ni, k, i, ni, k, m);
460 const long ip = idx[v.
p2_at(i, ni, k, i, ni, k, m)];
462 g[ip] +=
qrf_log<T>(tol + pv) + pv / (tol + pv);
488 const std::vector<int>& F, std::size_t MR,
494 for (std::size_t ti = 0; ti < M; ++ti)
495 for (std::size_t m = 0; m < MR; ++m)
496 for (std::size_t ni = 1; ni <= static_cast<std::size_t>(F[ti]); ++ni) {
498 if (alpha !=
nullptr && alpha->rows() >
static_cast<int>(ti) &&
499 alpha->cols() >=
static_cast<int>(ni))
500 a = (*alpha)(ti, ni - 1);
501 for (std::size_t ki = 0; ki < static_cast<std::size_t>(K[ti]); ++ki) {
502 const T pv = v.
p(ti, ni, ki, ti, ni, ki, m);
505 out.
BN[ti] += a * pv;
524 const std::size_t m = A.
rows(), n = A.
cols();
525 if (m == 0)
return std::vector<std::size_t>();
526 std::vector<std::vector<double>> res(m, std::vector<double>(n, 0.0));
527 std::vector<double> nrm(m, 0.0);
528 for (std::size_t i = 0; i < m; ++i) {
529 for (std::size_t j = 0; j < n; ++j) res[i][j] = num_traits<T>::to_double(A(i, j));
530 for (std::size_t j = 0; j < n; ++j) nrm[i] += res[i][j] * res[i][j];
533 for (std::size_t i = 0; i < m; ++i) first = std::max(first, std::sqrt(nrm[i]));
534 if (first == 0.0)
return std::vector<std::size_t>();
537 const double rtol = (tol > 0.0) ? tol
538 :
static_cast<double>(std::max(m, n)) * 2.220446049250313e-16 *
541 std::vector<bool> taken(m,
false);
542 std::vector<std::size_t> keep;
543 std::vector<std::vector<double>> basis;
544 for (std::size_t step = 0; step < std::min(m, n); ++step) {
545 std::size_t best = m;
547 for (std::size_t i = 0; i < m; ++i) {
548 if (taken[i])
continue;
549 const double v = std::sqrt(std::max(0.0, nrm[i]));
555 if (best == m)
break;
557 keep.push_back(best);
558 std::vector<double> q = res[best];
559 const double qn = std::sqrt(nrm[best]);
560 for (std::size_t j = 0; j < n; ++j) q[j] /=
qn;
562 for (std::size_t i = 0; i < m; ++i) {
563 if (taken[i])
continue;
565 for (std::size_t j = 0; j < n; ++j) dot += res[i][j] * q[j];
567 for (std::size_t j = 0; j < n; ++j) {
568 res[i][j] -= dot * q[j];
569 newn += res[i][j] * res[i][j];
574 std::sort(keep.begin(), keep.end());
594template <
class T,
class Fn>
597 std::vector<T> basis(n, zero);
598 const std::vector<T> r0 = fn(basis);
601 out.
b.assign(r0.size(), zero);
602 for (std::size_t i = 0; i < r0.size(); ++i) out.
b[i] = -r0[i];
604 for (std::size_t col = 0; col < n; ++col) {
606 const std::vector<T> rc = fn(basis);
608 for (std::size_t i = 0; i < r0.size(); ++i) out.
A(i, col) = rc[i] - r0[i];
610 if (!r0.empty() && n > 0) {
611 std::vector<T> probe(n, zero);
612 for (std::size_t j = 0; j < n; ++j)
614 0.1 + 0.8 * (n == 1 ? 0.0 :
static_cast<double>(j) /
static_cast<double>(n - 1)));
615 const std::vector<T> rp = fn(probe);
617 for (std::size_t i = 0; i < r0.size(); ++i) {
619 for (std::size_t j = 0; j < n; ++j) v += out.
A(i, j) * probe[j];
624 "qrf_affine_matrices: the constraint residuals are not affine in x; the matrix "
625 "form recovered here would be wrong away from the probe");
655 for (std::size_t i = 0; i < A.
rows(); ++i) {
656 for (std::size_t j = 0; j < A.
cols(); ++j) aug(i, j) = A(i, j);
657 aug(i, A.
cols()) = b[i];
661 "qrf_reduce_equalities: the equality system is inconsistent (the augmented matrix has "
662 "the higher rank), i.e. the polytope is empty");
665 for (std::size_t r = 0; r < out.
keep.size(); ++r) {
666 for (std::size_t j = 0; j < A.
cols(); ++j) out.
A(r, j) = A(out.
keep[r], j);
667 out.
b[r] = b[out.
keep[r]];
680 const Matrix<T>& Aub,
const std::vector<T>& bub, std::size_t n) {
684 for (std::size_t j = 0; j < n; ++j) {
688 for (std::size_t i = 0; i < Aeq.
rows(); ++i) {
690 for (std::size_t j = 0; j < n; ++j)
691 if (Aeq(i, j) != zero) model.
row_add(j, Aeq(i, j));
694 for (std::size_t i = 0; i < Aub.
rows(); ++i) {
696 for (std::size_t j = 0; j < n; ++j)
697 if (Aub(i, j) != zero) model.
row_add(j, Aub(i, j));
717 std::vector<std::vector<double>> basis;
718 const double eps = 1e-10;
719 for (std::size_t r = 0; r < A.
rows(); ++r) {
720 std::vector<double> v(n, 0.0);
721 for (std::size_t j = 0; j < n; ++j) v[j] = num_traits<T>::to_double(A(r, j));
722 for (std::size_t b = 0; b < basis.size(); ++b) {
724 for (std::size_t j = 0; j < n; ++j) dot += v[j] * basis[b][j];
725 for (std::size_t j = 0; j < n; ++j) v[j] -= dot * basis[b][j];
728 for (std::size_t j = 0; j < n; ++j) nv += v[j] * v[j];
730 if (nv <= eps)
continue;
731 for (std::size_t j = 0; j < n; ++j) v[j] /= nv;
734 const std::size_t rank = basis.size();
735 std::vector<std::vector<double>> nullb;
736 for (std::size_t c = 0; c < n && rank + nullb.size() < n; ++c) {
737 std::vector<double> v(n, 0.0);
739 for (std::size_t b = 0; b < basis.size(); ++b) {
741 for (std::size_t j = 0; j < n; ++j) dot += v[j] * basis[b][j];
742 for (std::size_t j = 0; j < n; ++j) v[j] -= dot * basis[b][j];
744 for (std::size_t b = 0; b < nullb.size(); ++b) {
746 for (std::size_t j = 0; j < n; ++j) dot += v[j] * nullb[b][j];
747 for (std::size_t j = 0; j < n; ++j) v[j] -= dot * nullb[b][j];
750 for (std::size_t j = 0; j < n; ++j) nv += v[j] * v[j];
752 if (nv <= 1e-8)
continue;
753 for (std::size_t j = 0; j < n; ++j) v[j] /= nv;
757 for (std::size_t j = 0; j < nullb.size(); ++j)
794template <
class T,
class Obj,
class Grad>
797 unsigned max_iter = 200,
double gap_tol = 1e-10) {
800 const std::size_t n = x0.size();
801 std::vector<T> x = x0;
812 for (
unsigned it = 0; it < max_iter; ++it) {
813 const std::vector<T> g = gradient(x);
815 for (std::size_t j = 0; j < n; ++j) model.
set_cost(j, g[j]);
821 ": the linear minimization over the QRF polytope failed, so no "
822 "descent direction and no optimality certificate can be had");
826 for (std::size_t j = 0; j < n; ++j)
828 if (gap <= gap_tol)
break;
832 const double invphi = 0.6180339887498949;
833 double a = 0.0, b = 1.0;
834 double c = b - invphi * (b - a), d = a + invphi * (b - a);
835 auto at = [&](
double t) {
836 std::vector<T> y(n, zero);
838 for (std::size_t j = 0; j < n; ++j) y[j] = x[j] + tt * (sol.
x[j] - x[j]);
841 const double f_cur = at(0.0);
842 double fc = at(c), fd = at(d);
843 for (
int k = 0; k < 60 && (b - a) > 1e-12; ++k) {
848 c = b - invphi * (b - a);
854 d = a + invphi * (b - a);
858 const double gamma = 0.5 * (a + b);
859 if (gamma <= 0.0)
break;
875 const double f_new = at(gamma);
876 if (!(f_new < f_cur - 1e-12 * (1.0 + std::fabs(f_cur))))
break;
879 for (std::size_t j = 0; j < n; ++j) x[j] = x[j] + gt * (sol.
x[j] - x[j]);
885template <
class T,
class Obj,
class Grad>
886std::vector<T>
solve_qrf_nlp(Obj objective, Grad gradient,
const std::vector<T>& x0,
887 const Matrix<T>& Aeq,
const std::vector<T>& beq,
888 const Matrix<T>& Aub,
const std::vector<T>& bub,
889 const std::string& name,
unsigned max_iter = 200,
890 double gap_tol = 1e-10) {
892 const std::size_t n = x0.size();
895 for (std::size_t j = 0; j < n; ++j) base.
set_bounds(j, zero, one);
896 for (std::size_t i = 0; i < Aeq.
rows(); ++i) {
898 for (std::size_t j = 0; j < n; ++j)
899 if (Aeq(i, j) != zero) base.
row_add(j, Aeq(i, j));
902 for (std::size_t i = 0; i < Aub.
rows(); ++i) {
904 for (std::size_t j = 0; j < n; ++j)
905 if (Aub(i, j) != zero) base.
row_add(j, Aub(i, j));
908 return solve_qrf_nlp_lp(objective, gradient, x0, base, name, max_iter, gap_tol);
919 const std::string& name) {
922 [&](
const std::vector<T>& x) {
924 for (std::size_t j = 0; j < x.size(); ++j) s += x[j] * x[j];
927 [](
const std::vector<T>& x) {
return x; }, x0, polytope, name +
" phase 1", 500u, 1e-12);
961 ": the polytope is infeasible; a well-posed instance always has a "
962 "feasible point, so this is a modelling error");
976 const Matrix<T>& Aub,
const std::vector<T>& bub,
982 "qrf_feasible_start: the QRF polytope is infeasible; a well-posed instance always has "
983 "one, so an empty polytope is a modelling error rather than a numerical accident");
Sparse LP in the natural form, with per-variable bounds.
void emit_eq(const T &rhs)
void set_maximize(bool m)
true to maximize c'x (the default), false to minimize.
void emit_le(const T &rhs)
void set_cost(std::size_t j, const T &v)
std::size_t num_vars() const
void row_clear()
Discard whatever the row accumulator holds.
void set_bounds(std::size_t j, const T &lo, const T &hi)
void row_add(std::size_t j, const T &v)
row(j) += v, the accumulation the MATLAB reference performs.
The exception types the port throws.
A sparse LP backend for line::lp::LpModel, on HiGHS (MIT).
Dense matrix and non-owning view.
LpSolution< T > lp_solve(const LpModel< T > &model, std::size_t dense_max_cols=512)
Solve, choosing the backend by arithmetic and size.
LpSolution< T > simplex_solve(const LpModel< T > &model, std::size_t max_iterations=0)
Solve the model.
@ Optimal
an optimal vertex was reached
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.
std::vector< T > mem_gradient(const std::vector< T > &x, std::size_t M, std::size_t N, const std::vector< int > &K, const std::vector< int > &F, std::size_t MR, const std::vector< long > &idx)
Gradient of mem_objective: d/dp of p log(p') is log p' + p/p'.
QrfMetrics< T > qrf_extract_results(const QrfVars< T > &v, std::size_t M, const std::vector< int > &K, const std::vector< int > &F, std::size_t MR, const Matrix< T > *alpha=nullptr)
extract_results: the diagonal marginals of the optimal tensor, plus the alpha-weighted mean BN.
T mem_objective(const std::vector< T > &x, std::size_t M, std::size_t N, const std::vector< int > &K, const std::vector< int > &F, std::size_t MR)
Maximum-entropy objective, returned as the NEGATIVE entropy +sum p log p over the diagonal entries,...
std::size_t qrf_num_vars(std::size_t M, std::size_t N, const std::vector< int > &K, std::size_t MR)
Number of decision variables the layout actually USES.
QrfAffine< T > qrf_affine_matrices(Fn fn, std::size_t n)
Recover (A, b) from an affine residual map.
T mmi_objective(const std::vector< T > &x, std::size_t M, std::size_t N, const std::vector< int > &K, const std::vector< int > &F, std::size_t MR)
Mutual-information objective.
std::vector< T > qrf_feasible_start(const Matrix< T > &Aeq, const std::vector< T > &beq, const Matrix< T > &Aub, const std::vector< T > &bub, std::size_t n)
A point of the polytope, as the phase 1 of qrf_noblo_start.m.
Matrix< T > qrf_null_space(const Matrix< T > &A, std::size_t n)
Orthonormal basis of null(A), as an (n x d) matrix.
QrfVars< T > sub_qrfvar(const std::vector< T > &x, std::size_t M, std::size_t N, const std::vector< int > &K, std::size_t MR)
Unflatten x into the pair tensor and the effective rates.
std::vector< T > bethe_gradient(const std::vector< T > &x, std::size_t M, std::size_t N, const std::vector< int > &K, const std::vector< int > &F, std::size_t MR, const std::vector< long > &idx)
Gradient of bethe_objective.
std::vector< T > solve_qrf_nlp(Obj objective, Grad gradient, const std::vector< T > &x0, const Matrix< T > &Aeq, const std::vector< T > &beq, const Matrix< T > &Aub, const std::vector< T > &bub, const std::string &name, unsigned max_iter=200, double gap_tol=1e-10)
The same, with the polytope given as matrices rather than as an LpModel.
QrfReduced< T > qrf_reduce_equalities(const Matrix< T > &A, const std::vector< T > &b)
Drop the linearly dependent equality rows, keeping the feasible set exact.
lp::LpModel< T > qrf_polytope(const Matrix< T > &Aeq, const std::vector< T > &beq, const Matrix< T > &Aub, const std::vector< T > &bub, std::size_t n)
The polytope of a QRF instance, as an LpModel over the box [0,1]^n.
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...
std::vector< long > qrf_index_map(std::size_t M, std::size_t N, const std::vector< int > &K, std::size_t MR)
Flat position of every p2 entry, in the FILL ORDER of sub_qrfvar.
std::vector< T > mmi_gradient(const std::vector< T > &x, std::size_t M, std::size_t N, const std::vector< int > &K, const std::vector< int > &F, std::size_t MR, const std::vector< long > &idx)
Gradient of mmi_objective.
T bethe_objective(const std::vector< T > &x, std::size_t M, std::size_t N, const std::vector< int > &K, const std::vector< int > &F, std::size_t MR)
Tree-reweighted (Bethe) free entropy at the uniform spanning-tree weight, the objective of qrf....
std::vector< T > qrf_min_norm_point(const lp::LpModel< T > &polytope, const std::vector< T > &x0, const std::string &name)
The minimum-norm point of the polytope, from any feasible point of it.
std::vector< std::size_t > qrf_independent_rows(const Matrix< T > &A, double tol=-1.0)
Rows of a maximal linearly independent subset of A, by pivoted Gram-Schmidt.
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.
std::vector< T > x
primal solution in the ORIGINAL variable space
An affine residual map recovered as (A, b) with fn(x) = A x - b.
The utilizations and queue lengths read off an optimal pair tensor.
std::vector< T > BN
The ALPHA-WEIGHTED diagonal marginal mean: the mean number of jobs actually in service,...
The equality block with its dependent rows dropped.
std::vector< std::size_t > keep
The unflattened decision vector: the pair tensor and the effective rates.
const T & p(std::size_t j, std::size_t nj, std::size_t k, std::size_t i, std::size_t ni, std::size_t h, std::size_t m) const
std::size_t p2_at(std::size_t j, std::size_t nj, std::size_t k, std::size_t i, std::size_t ni, std::size_t h, std::size_t m) const
T & p(std::size_t j, std::size_t nj, std::size_t k, std::size_t i, std::size_t ni, std::size_t h, std::size_t m)
std::vector< T > p2
p2[j][nj][k][i][ni][h][m], flattened row-major over the seven indices.
std::vector< T > e
e[i*Kmax + k]