LINE Solver (C++)
Templated C++ port of the LINE queueing solver
Loading...
Searching...
No Matches
cache_prob_is.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_CACHE_PROB_IS_H
6#define LINE_API_CACHE_PROB_IS_H
7
8/**
9 * @file
10 * @ingroup api_cache
11 * Importance-sampling estimate of the cache hit-probability distribution.
12 *
13 * Templated port of matlab/src/api/cache/cache_prob_is.m. The same proposal as
14 * cache_is is used; prob(i,1+j) is the ratio of the accumulated importance
15 * weight of the configurations that place item i on list j to the total
16 * weight, and prob(i,0) is the residual miss probability. The self-normalized
17 * form makes the constant proposal density cancel, so the estimator depends on
18 * the weights only through their ratios.
19 *
20 * The reference scales the weights by exp(-50) before accumulating them, to
21 * keep the sum inside the double range; the constant cancels in the ratio and
22 * is kept here for entry-by-entry agreement with MATLAB.
23 *
24 * Arithmetic. static_assert(has_transcendental) -- Monte Carlo weights formed
25 * through logs and an exponential, as in cache_is.
26 */
27
28#include <cmath>
29#include <cstddef>
30#include <random>
31#include <vector>
32
36#include "line/num/number.h"
37#include "line/util/error.h"
38#include "line/util/matrix.h"
39
40namespace line {
41namespace cache {
42
43/**
44 * @brief Importance-sampling estimate of the cache hit-probability
45 * distribution.
46 *
47 * @param gamma (n x h) access factors
48 * @param m (h) list capacities
49 * @param samples number of Monte Carlo samples (MATLAB default 1e5)
50 * @param seed seed of the sampling stream
51 * @param sigma (n) per-item storage cost; empty for uncapped lists
52 * @param k (h) per-list cost cap; empty for uncapped lists
53 * @return (n x h+1); column 0 is the miss probability, column 1+j the
54 * probability that the item sits on list j
55 */
56template <class T>
57Matrix<T> cache_prob_is(const Matrix<T>& gamma, const std::vector<int>& m, std::size_t samples,
58 std::uint64_t seed, const std::vector<int>& sigma,
59 const std::vector<int>& k) {
60 const bool capped = !sigma.empty() && !k.empty();
62 "cache_prob_is requires transcendental arithmetic: the weights are Monte Carlo "
63 "quantities formed through logs and an exponential");
64 if (gamma.cols() != m.size())
65 throw InputError("cache_prob_is: gamma and m disagree on the number of lists");
66 if (samples == 0) throw InputError("cache_prob_is: at least one sample is required");
67
68 using std::exp;
69 using std::log;
70 const T zero = num_traits<T>::from_int(0);
71 const T one = num_traits<T>::from_int(1);
72 const std::size_t n = gamma.rows();
73 const std::size_t h = m.size();
74 long mt = 0;
75 for (int v : m) {
76 if (v < 0) throw InputError("cache_prob_is: negative list capacity");
77 mt += v;
78 }
79
80 Matrix<T> prob(n, h + 1, zero);
81 if (n == 0) return prob;
82 if (mt == 0 || static_cast<long>(n) < mt) {
83 // No slot, or fewer items than slots: every item misses, as the
84 // reference reports.
85 for (std::size_t i = 0; i < n; ++i) prob(i, 0) = one;
86 return prob;
87 }
88 if (static_cast<long>(n) == mt) return cache_prob_erec(gamma, m, sigma, k);
89
90 Matrix<T> lgam(n, h, zero);
91 const T floorv = num_traits<T>::from_double(1e-300);
92 for (std::size_t i = 0; i < n; ++i)
93 for (std::size_t j = 0; j < h; ++j) lgam(i, j) = log(T(gamma(i, j) + floorv));
94
95 T logMFact = zero;
96 for (std::size_t j = 0; j < h; ++j)
97 logMFact += pfqn::detail::num_logfact_int<T>(static_cast<long>(m[j]));
98 const T logComb = pfqn::detail::num_logfact_int<T>(static_cast<long>(n)) -
99 pfqn::detail::num_logfact_int<T>(mt) -
100 pfqn::detail::num_logfact_int<T>(static_cast<long>(n) - mt);
101 const T logMultinom = pfqn::detail::num_logfact_int<T>(mt) - logMFact;
102 const T logProposal = -logComb - logMultinom;
103 const T shift = num_traits<T>::from_int(50); // the reference's overflow guard
104
105 Matrix<T> acc(n, h, zero);
106 T total = zero;
107 std::mt19937_64 rng(seed);
108 std::vector<std::size_t> perm, sel;
109 for (std::size_t s = 0; s < samples; ++s) {
110 detail::sample_without_replacement(n, static_cast<std::size_t>(mt), rng, perm, sel);
111 T logState = logMFact;
112 std::size_t idx = 0;
113 bool feasible = true;
114 for (std::size_t j = 0; j < h && feasible; ++j) {
115 if (capped) {
116 long listCost = 0;
117 for (int c = 0; c < m[j]; ++c) listCost += sigma[sel[idx + c]];
118 if (listCost > k[j]) {
119 feasible = false;
120 break;
121 }
122 }
123 for (int c = 0; c < m[j]; ++c) logState += lgam(sel[idx++], j);
124 }
125 if (!feasible) continue; // I{S_v in O} = 0
126 const T wgt = exp(T(logState - logProposal - shift));
127 total += wgt;
128 idx = 0;
129 for (std::size_t j = 0; j < h; ++j)
130 for (int c = 0; c < m[j]; ++c) acc(sel[idx++], j) += wgt;
131 }
132
133 if (total <= zero) {
134 for (std::size_t i = 0; i < n; ++i) prob(i, 0) = one;
135 return prob;
136 }
137 for (std::size_t i = 0; i < n; ++i) {
138 T hit = zero;
139 for (std::size_t j = 0; j < h; ++j) {
140 prob(i, 1 + j) = acc(i, j) / total;
141 hit += prob(i, 1 + j);
142 }
143 const T miss = one - hit;
144 prob(i, 0) = miss > zero ? miss : zero;
145 }
146 return prob;
147}
148
149/** cache_prob_is without storage cost caps. */
150template <class T>
151Matrix<T> cache_prob_is(const Matrix<T>& gamma, const std::vector<int>& m, std::size_t samples,
152 std::uint64_t seed) {
153 return cache_prob_is(gamma, m, samples, seed, std::vector<int>(), std::vector<int>());
154}
155
156/** cache_prob_is with the MATLAB default of 1e5 samples. */
157template <class T>
158Matrix<T> cache_prob_is(const Matrix<T>& gamma, const std::vector<int>& m) {
159 return cache_prob_is(gamma, m, static_cast<std::size_t>(100000), static_cast<std::uint64_t>(0));
160}
161
162} // namespace cache
163} // namespace line
164
165#endif // LINE_API_CACHE_PROB_IS_H
Importance-sampling estimate of the cache normalizing constant.
Exact per-item hit and miss probabilities of a multi-list cache.
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
The exception types the port throws.
Dense matrix and non-owning view.
Matrix< T > cache_prob_erec(const Matrix< T > &gamma, const std::vector< int > &m, const std::vector< int > &sigma, const std::vector< int > &k)
Per-item hit and miss probabilities under per-list storage cost caps, pi_ij = m_j gamma(i,...
Matrix< T > cache_prob_is(const Matrix< T > &gamma, const std::vector< int > &m, std::size_t samples, std::uint64_t seed, const std::vector< int > &sigma, const std::vector< int > &k)
Importance-sampling estimate of the cache hit-probability distribution.
Number-type abstraction for the templated API port.
Shared scalar machinery for the integration / asymptotic members of the pfqn family (pfqn_le,...