LINE Solver (C++)
Templated C++ port of the LINE queueing solver
Loading...
Searching...
No Matches
infer_rps.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_INFER_INFER_RPS_H
6#define LINE_API_INFER_INFER_RPS_H
7
8/**
9 * @file
10 * @ingroup api_infer
11 * Regression for Processor Sharing (RPS) demand estimator.
12 *
13 * Templated port of matlab/src/api/infer/infer_rps.m. No JAR counterpart.
14 *
15 * Mean value analysis of a PS station gives E[R_r] = E[D_r] E[Qbar_A]/V, with
16 * Qbar_A the total number of jobs seen on admission INCLUDING the arriving job
17 * and V the number of servers. The demand of each class is the non-negative
18 * least squares fit of its response times against Qbar_A/V.
19 *
20 * MATLAB calls lsqnonneg, but the design matrix here has a SINGLE column, so
21 * the non-negative least squares problem has the closed form
22 * max(0, a.b / a.a): the unconstrained minimizer is the ordinary projection
23 * and the active-set method returns 0 exactly when it is negative. The port
24 * evaluates that closed form, so it needs no optimizer and reproduces
25 * lsqnonneg exactly rather than approximately.
26 *
27 * MATLAB takes the class count from max(class); the port does the same, so a
28 * trailing class with no samples at all is simply not represented in the
29 * output, exactly as in MATLAB.
30 *
31 * ARITHMETIC: two inner products, one division and one comparison against
32 * zero, so a finite field computation, exact in the exact instantiation. The
33 * response times are non-negative and Qbar_A >= 1, so the estimate can only
34 * hit the bound when every response time is zero.
35 */
36
37#include <cstddef>
38#include <vector>
39
40#include "line/num/number.h"
41#include "line/util/error.h"
42#include "line/util/matrix.h"
43
44namespace line {
45namespace infer {
46
47/**
48 * @brief Regression for Processor Sharing (RPS) demand estimator.
49 *
50 * @param rt (n) response time samples
51 * @param cls (n) class of each sample, 0-based
52 * @param ql (n x R) per-class queue lengths at arrival, excluding the arriving job
53 * @param V number of servers of the PS station
54 * @return (max(cls)+1) estimated mean service demands
55 */
56template <class T>
57std::vector<T> infer_rps(const std::vector<T>& rt, const std::vector<std::size_t>& cls,
58 const Matrix<T>& ql, long V) {
59 const std::size_t n = rt.size();
60 if (cls.size() != n) throw InputError("infer_rps: rt and class disagree on the sample count");
61 if (ql.rows() != n) throw InputError("infer_rps: ql and rt disagree on the sample count");
62 if (V <= 0) throw InputError("infer_rps: the number of servers must be positive");
63 if (n == 0) throw InputError("infer_rps: no samples");
64
65 std::size_t R = 0;
66 for (std::size_t c : cls) R = c + 1 > R ? c + 1 : R;
67
68 const T zero = num_traits<T>::from_int(0);
69 const T one = num_traits<T>::from_int(1);
70 const T Vt = num_traits<T>::from_int(V);
71
72 std::vector<T> demand(R, zero);
73 for (std::size_t r = 0; r < R; ++r) {
74 T aa = zero, ab = zero;
75 std::size_t count = 0;
76 for (std::size_t i = 0; i < n; ++i) {
77 if (cls[i] != r) continue;
78 ++count;
79 T qbar = one; // the arriving job itself
80 for (std::size_t c = 0; c < ql.cols(); ++c) qbar += ql(i, c);
81 const T a = qbar / Vt;
82 aa += a * a;
83 ab += a * rt[i];
84 }
85 if (count == 0)
86 throw InputError("infer_rps: a class below the maximum has no samples at all");
87 if (aa == zero) throw NumericError("infer_rps: degenerate regressor for a class");
88 const T x = ab / aa;
89 demand[r] = x > zero ? x : zero; // the non-negativity bound of lsqnonneg
90 }
91 return demand;
92}
93
94} // namespace infer
95} // namespace line
96
97#endif // LINE_API_INFER_INFER_RPS_H
InputError(const std::string &what)
Definition error.h:39
std::size_t cols() const
Definition matrix.h:90
std::size_t rows() const
Definition matrix.h:89
NumericError(const std::string &what)
Definition error.h:45
The exception types the port throws.
Dense matrix and non-owning view.
std::vector< T > infer_rps(const std::vector< T > &rt, const std::vector< std::size_t > &cls, const Matrix< T > &ql, long V)
Regression for Processor Sharing (RPS) demand estimator.
Definition infer_rps.h:57
Number-type abstraction for the templated API port.