LINE Solver (C++)
Templated C++ port of the LINE queueing solver
Loading...
Searching...
No Matches
mapqn_bnd_qr_ld.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_MAPQN_MAPQN_BND_QR_LD_H
6#define LINE_API_MAPQN_MAPQN_BND_QR_LD_H
7
8/**
9 * @file
10 * @ingroup api_mapqn
11 * Quadratic-reduction bound on a marginal of a load-dependent MAP queueing
12 * network.
13 *
14 * Templated port of matlab/lib/qrf/mapqn_bnd_qr_ld.m (ground truth) and of
15 * jar/src/main/java/jline/api/mapqn/Mapqn_bnd_qr_ld.java.
16 *
17 * What it computes: the exact stationary distribution of a MAP queueing
18 * network is intractable, so the quadratic reduction keeps only the PAIRWISE
19 * joint distribution p2(j,nj,k,i,ni,h) -- the probability that queue j holds
20 * nj jobs in phase k while queue i holds ni jobs in phase h -- and imposes
21 * every linear relation the true distribution must satisfy: normalization
22 * (ONE), the states that cannot occur (ZERO1/2/3), symmetry of the pair,
23 * consistency of the pairwise law with its own marginal (MARGINALS), Little's
24 * law (THM1, THM1c), the second moment of the population (PC2), phase balance
25 * (THM2), population flow balance (THM3a, THM3b), queue balance (QBAL), the
26 * order-1 correlation cuts (COR1a, COR1b) and the QMIN inequality (THM4). The
27 * true distribution is feasible for that polytope, so maximizing or minimizing
28 * one coordinate over it BOUNDS the corresponding true probability. The bound
29 * is a relaxation, not an approximation: it is valid, not merely close.
30 *
31 * The objective coordinate is the diagonal entry
32 * p2(objective_queue, objective_n, objective_phase, same, same, same), which
33 * is P(queue j holds n jobs in phase k). Summing the bound over n >= 1 and k
34 * is how the reference obtains a utilization bound.
35 *
36 * Arithmetic: the whole assembly is +, -, * and / on the model data, and the
37 * LP is solved by line::lp::simplex_solve, which uses Bland's rule and no
38 * tolerance. At T = line::Rational the returned bound is therefore the EXACT
39 * optimum of the exact polytope, with no LP tolerance at all -- unlike the
40 * MATLAB reference, which reaches it with interior-point linprog and lands a
41 * few digits short (its own comment records ~1e-7 residual error on the
42 * paper's BAS instance), and unlike the JAR, which uses a double-precision
43 * Apache Commons simplex.
44 *
45 * Variable bounds: 0 <= p2 <= 1 with the ZERO states pinned to 0 are passed to
46 * the solver as bounds. They do NOT become rows the way the JAR needs them to,
47 * because Apache SimplexSolver does not box variables and the maximization is
48 * unbounded without them; LpModel boxes natively, substitutes out the pinned
49 * variables entirely, and materializes at most one row per genuinely
50 * upper-bounded variable.
51 *
52 * Cost: the model has ((N+1) sum_i K(i))^2 variables, so it grows as the
53 * fourth power of the population. The tableau here is dense, which confines
54 * the port to small and medium instances; the reference's large blocking
55 * instances need a sparse revised simplex.
56 */
57
60#include "line/num/number.h"
61#include "line/util/error.h"
62#include "line/util/simplex.h"
63
64namespace line {
65namespace mapqn {
66
67/**
68 * Bound P(queue objective_queue holds objective_n jobs in phase
69 * objective_phase), in the requested direction.
70 *
71 * @param p network parameters; queues and phases are 0-based
72 * @param objective_queue queue index, 0..M-1
73 * @param objective_phase phase index, 0..K(objective_queue)-1
74 * @param objective_n population level, 0..N
75 * @param sense Max for an upper bound, Min for a lower bound
76 */
77template <class T>
78MapqnQrResult<T> mapqn_bnd_qr_ld(const MapqnParams<T>& p, int objective_queue, int objective_phase,
79 int objective_n, MapqnSense sense = MapqnSense::Max) {
80 p.validate();
81 if (p.N < 1) throw InputError("mapqn_bnd_qr_ld: N must be at least 1");
82 detail::qr_check_objective(p, objective_queue, objective_phase, objective_n);
83
84 const P2Index idx(p.M, p.N, p.K);
85 lp::LpModel<T> m(idx.num_vars());
86 const T one = num_traits<T>::from_int(1);
87 for (std::size_t j = 0; j < idx.num_vars(); ++j) m.set_bounds(j, T(), one);
88
89 // Families, in the order the reference emits them.
90 const std::vector<char> is_zero = qr_zero_bounds(p, idx, m);
91 qr_one(p, idx, m);
92 qr_symmetry(p, idx, m, is_zero);
93 qr_marginals(p, idx, m);
94 qr_thm1(p, idx, m);
95 qr_thm1c(p, idx, m);
96 qr_pc2(p, idx, m);
97 qr_thm2(p, idx, m);
98 qr_thm3a(p, idx, m);
99 qr_thm3b(p, idx, m);
100 qr_qbal(p, idx, m);
101 qr_cor1a(p, idx, m);
102 qr_cor1b(p, idx, m);
103 qr_thm4(p, idx, m);
104
105 return detail::qr_finish(p, idx, m, objective_queue, objective_phase, objective_n, sense);
106}
107
108} // namespace mapqn
109} // namespace line
110
111#endif // LINE_API_MAPQN_MAPQN_BND_QR_LD_H
InputError(const std::string &what)
Definition error.h:39
Sparse LP in the natural form, with per-variable bounds.
Definition simplex.h:112
void set_bounds(std::size_t j, const T &lo, const T &hi)
Definition simplex.h:139
The exception types the port throws.
Model parameters and variable indexing shared by the mapqn QR bounds.
The constraint families of the quadratic-reduction (QR) polytope.
void qr_pc2(const MapqnParams< T > &p, const P2Index &idx, lp::LpModel< T > &m)
PC2 (second moment): sum_{i,j,ni>=1,nj>=1,h,k} nj ni p2(j,nj,k,i,ni,h) = N^2.
void qr_qbal(const MapqnParams< T > &p, const P2Index &idx, lp::LpModel< T > &m)
QBAL (queue balance): LHS1 + LHS2 = RHS1 + RHS2 for each (i,k).
void qr_thm4(const MapqnParams< T > &p, const P2Index &idx, lp::LpModel< T > &m)
THM4 (QMIN): for each (j,k,i), sum_{t,h,nj,nt} nt p2(j,nj,k,t,nt,h) >= N sum_{h,nj,...
void qr_thm1(const MapqnParams< T > &p, const P2Index &idx, lp::LpModel< T > &m)
THM1 (Little's law in probability form): for each (j,k), sum_{i,nj>=1,ni>=1,h} ni p2(j,...
std::vector< char > qr_zero_bounds(const MapqnParams< T > &p, const P2Index &idx, lp::LpModel< T > &m)
ZERO1/2/3: states that carry no probability mass, imposed as ub = 0.
MapqnSense
Which direction the bound is taken in.
void qr_symmetry(const MapqnParams< T > &p, const P2Index &idx, lp::LpModel< T > &m, const std::vector< char > &is_zero)
SYMMETRY: p2(i,ni,h,j,nj,k) = p2(j,nj,k,i,ni,h), emitted once per pair.
void qr_marginals(const MapqnParams< T > &p, const P2Index &idx, lp::LpModel< T > &m)
MARGINALS: p2(j,nj,k,j,nj,k) = sum over (ni <= N-nj, h) of p2(j,nj,k,i,ni,h) for every i !...
void qr_one(const MapqnParams< T > &p, const P2Index &idx, lp::LpModel< T > &m)
ONE: sum over (nj,k) of p2(j,nj,k,j,nj,k) = 1, per queue j.
void qr_thm1c(const MapqnParams< T > &p, const P2Index &idx, lp::LpModel< T > &m)
THM1c: the nj = 0 companion of THM1, conditioning on queue j being empty.
void qr_thm2(const MapqnParams< T > &p, const P2Index &idx, lp::LpModel< T > &m)
THM2 (phase balance): for each (i,k) the total rate out of phase k at queue i equals the total rate i...
void qr_thm3a(const MapqnParams< T > &p, const P2Index &idx, lp::LpModel< T > &m)
THM3a (population flow balance, 1 <= ni <= N-1): the rate at which queue i is entered while holding n...
void qr_cor1a(const MapqnParams< T > &p, const P2Index &idx, lp::LpModel< T > &m)
COR1a: the order-1 correlation cut, for each (i, kstar, ni = 0..N-2).
void qr_thm3b(const MapqnParams< T > &p, const P2Index &idx, lp::LpModel< T > &m)
THM3b: the ni = 0 boundary case of THM3a, resolved per arrival phase u.
void qr_cor1b(const MapqnParams< T > &p, const P2Index &idx, lp::LpModel< T > &m)
COR1b: the ni = N-1 boundary of COR1a (blocks A', C', D', E', H').
MapqnQrResult< T > mapqn_bnd_qr_ld(const MapqnParams< T > &p, int objective_queue, int objective_phase, int objective_n, MapqnSense sense=MapqnSense::Max)
Bound P(queue objective_queue holds objective_n jobs in phaseobjective_phase), in the requested direc...
Number-type abstraction for the templated API port.
Templated primal simplex with Bland's rule.
Parameters of a MAP queueing network for the QR bounds.
int N
total population
std::vector< int > K
K[i] = number of phases at queue i.
int M
number of queues
Result of a QR bound solve.
Flat index of the joint variable p2(j,nj,k,i,ni,h).
std::size_t num_vars() const