5#ifndef LINE_API_RETRIEVAL_RETRIEVAL_MVA_H
6#define LINE_API_RETRIEVAL_RETRIEVAL_MVA_H
66class RetrievalMvaSolver {
68 RetrievalMvaSolver(
const std::vector<int>& m,
const std::vector<T>& lambda,
70 : m_(m), lambda_(lambda), eta_(eta), gamma_(gamma), n_(lambda.size()), h_(m.size()),
74 for (std::size_t j = 0; j < h_; ++j) {
75 radix_[j] =
static_cast<std::size_t
>(m_[j]) + 1;
78 nmask_ =
static_cast<std::size_t
>(1) << n_;
79 const std::size_t cells = nmask_ * ncap_;
80 done_.assign(cells,
false);
82 pi0_.assign(cells * n_, zero);
83 pihit_.assign(cells * n_, zero);
84 pij_.assign(cells * n_ * h_, zero);
85 phi_.assign(cells * n_ * (r_ + 1), zero);
89 const std::size_t full = nmask_ - 1;
91 const std::size_t ci = capidx(m_);
96 for (std::size_t i = 0; i < n_; ++i) {
97 out.
pmiss[i] = pi0_[(full * ncap_ + ci) * n_ + i];
98 for (std::size_t j = 0; j < h_; ++j)
99 out.
phit(j, i) = pij_[((full * ncap_ + ci) * n_ + i) * h_ + j];
100 for (std::size_t s = 0; s <= r_; ++s)
101 out.
pdh(s, i) = phi_[((full * ncap_ + ci) * n_ + i) * (r_ + 1) + s];
107 std::size_t capidx(
const std::vector<int>& c)
const {
108 std::size_t idx = 0, mul = 1;
109 for (std::size_t j = 0; j < h_; ++j) {
110 idx +=
static_cast<std::size_t
>(c[j]) * mul;
116 T& PI0(std::size_t mask, std::size_t ci, std::size_t i) {
117 return pi0_[(mask * ncap_ + ci) * n_ + i];
119 T& PIHIT(std::size_t mask, std::size_t ci, std::size_t i) {
120 return pihit_[(mask * ncap_ + ci) * n_ + i];
122 T& PIJ(std::size_t mask, std::size_t ci, std::size_t i, std::size_t j) {
123 return pij_[((mask * ncap_ + ci) * n_ + i) * h_ + j];
125 T& PHI(std::size_t mask, std::size_t ci, std::size_t i, std::size_t s) {
126 return phi_[((mask * ncap_ + ci) * n_ + i) * (r_ + 1) + s];
129 void solve(std::size_t mask,
const std::vector<int>& c) {
130 const std::size_t ci = capidx(c);
131 if (done_[mask * ncap_ + ci])
return;
133 done_[mask * ncap_ + ci] =
true;
136 std::vector<std::size_t> active;
137 for (std::size_t i = 0; i < n_; ++i)
138 if (mask & (
static_cast<std::size_t
>(1) << i)) active.push_back(i);
141 for (
int x : c) csum += x;
142 if (csum >=
static_cast<long>(active.size())) {
146 done_[mask * ncap_ + ci] =
true;
153 for (std::size_t j = 0; j < h_; ++j) {
155 std::vector<int> cj = c;
158 for (std::size_t i : active)
solve(mask & ~(
static_cast<std::size_t
>(1) << i), cj);
161 for (std::size_t k : active)
solve(mask & ~(
static_cast<std::size_t
>(1) << k), c);
164 for (std::size_t j = 0; j < h_; ++j) {
165 if (c[j] == 0)
continue;
166 std::vector<int> cj = c;
168 const std::size_t cjx = capidx(cj);
170 for (std::size_t i : active) {
171 const std::size_t maski = mask & ~(
static_cast<std::size_t
>(1) << i);
173 for (std::size_t s = 0; s < r_; ++s) {
175 for (std::size_t k : active)
176 if (k != i) sphi += PHI(maski, cjx, k, s + 1);
177 acc += lambda_[i] * eta_(i, s + 1) * (one + sphi);
179 theta[i] = gamma_(i, j) / (one + lambda_[i] * eta_(i, 0) + acc);
182 for (std::size_t i : active) sden += theta[i] * (one - PIHIT(mask, cjx, i));
184 throw NumericError(
"retrieval_mva: degenerate list occupancy (zero denominator)");
186 for (std::size_t i : active)
187 PIJ(mask, ci, i, j) = theta[i] * xi_j * (one - PIHIT(mask, cjx, i));
190 for (std::size_t i : active) {
192 for (std::size_t j = 0; j < h_; ++j) ph += PIJ(mask, ci, i, j);
193 PIHIT(mask, ci, i) = ph;
196 for (std::size_t i : active) {
197 const std::size_t maski = mask & ~(
static_cast<std::size_t
>(1) << i);
199 for (std::size_t s = 0; s < r_; ++s) {
201 for (std::size_t k : active)
202 if (k != i) sphi += PHI(maski, ci, k, s + 1);
203 acc += lambda_[i] * eta_(i, s + 1) * (one + sphi);
206 (one - PIHIT(mask, ci, i)) / (one + lambda_[i] * eta_(i, 0) + acc);
209 for (std::size_t k : active) {
210 const std::size_t maskk = mask & ~(
static_cast<std::size_t
>(1) << k);
211 const T pi0k = PI0(mask, ci, k);
212 PHI(mask, ci, k, 0) = lambda_[k] * eta_(k, 0) * pi0k;
213 for (std::size_t s = 0; s < r_; ++s) {
215 for (std::size_t i : active)
216 if (i != k) sphi += PHI(maskk, ci, i, s + 1);
217 PHI(mask, ci, k, s + 1) = lambda_[k] * pi0k * eta_(k, s + 1) * (one + sphi);
221 done_[mask * ncap_ + ci] =
true;
224 const std::vector<int>& m_;
225 const std::vector<T>& lambda_;
228 std::size_t n_, h_, r_;
229 std::vector<std::size_t> radix_;
230 std::size_t ncap_ = 1, nmask_ = 1;
231 std::vector<bool> done_;
232 std::vector<T> pi0_, pihit_, pij_, phi_;
249 const std::size_t n = lambda.size();
250 if (eta.
rows() != n || gamma.
rows() != n)
251 throw InputError(
"retrieval_mva: eta/gamma and lambda disagree on the item count");
252 if (gamma.
cols() != m.size())
253 throw InputError(
"retrieval_mva: gamma and m disagree on the number of lists");
254 if (eta.
cols() == 0)
throw InputError(
"retrieval_mva: eta has no columns");
256 if (x < 0)
throw InputError(
"retrieval_mva: negative list capacity");
257 if (n > 8 *
sizeof(std::size_t) - 1)
258 throw UnsupportedError(
"retrieval_mva: too many items for a bitmask subset enumeration");
259 detail::RetrievalMvaSolver<T> solver(m, lambda, eta, gamma);
NumericError(const std::string &what)
UnsupportedError(const std::string &what)
The exception types the port throws.
Dense matrix and non-owning view.
RetrievalMvaResult< T > retrieval_mva(const std::vector< int > &m, const std::vector< T > &lambda, const Matrix< T > &eta, const Matrix< T > &gamma)
Exact MVA-style recursion for delayed-hit (list-based) cache metrics.
std::vector< T > solve(const Matrix< T > &A, const std::vector< T > &b)
Convenience: solve Ax = b, leaving A and b untouched.
Number-type abstraction for the templated API port.
Mirrors the [pmiss, phit, pdh] return list of the MATLAB function.
Matrix< T > phit
(h x n) hit ratios pi_{i,j}
Matrix< T > pdh
((r+1) x n) delayed-hit probabilities phi_{s,i}, s = 0..r
std::vector< T > pmiss
(n) miss ratios pi_{i,0}