5#ifndef LINE_API_CACHE_TTL_LRUA_H
6#define LINE_API_CACHE_TTL_LRUA_H
75Matrix<T> lrua_randprob(
const Matrix<T>& lambda,
const std::vector<Matrix<T>>& R,
76 const std::vector<T>& x) {
78 const std::size_t n = lambda.rows();
79 const std::size_t h = x.size();
80 const T zero = num_traits<T>::from_int(0);
81 const T one = num_traits<T>::from_int(1);
82 Matrix<T> randprob(n, h + 1, zero);
84 for (std::size_t i = 0; i < n; ++i) {
86 if (lambda(i, 0) == zero) {
90 Matrix<T> trans(h + 1, h + 1, zero);
91 for (std::size_t j = 0; j <= h; ++j) {
92 for (std::size_t k = 0; k <= h; ++k) {
93 if (R[i](j, k) == zero)
continue;
95 trans(j, k) = R[i](j, k);
97 trans(j, k) = (one - exp(T(-lambda(i, j) * x[j - 1]))) * R[i](j, k);
101 "cache_ttl_lrua: the access graph routes into the not-cached node, "
102 "which has no characteristic time");
103 trans(k, j) = exp(T(-lambda(i, k) * x[k - 1]));
108 std::vector<std::size_t> chain;
109 for (std::size_t c = 0; c <= h; ++c) {
111 for (std::size_t r = 0; r <= h; ++r)
112 if (!(trans(r, c) == zero)) {
116 if (!allzero) chain.push_back(c);
118 if (chain.empty())
throw NumericError(
"cache_ttl_lrua: the item has no reachable node");
119 Matrix<T> P(chain.size(), chain.size());
120 for (std::size_t a = 0; a < chain.size(); ++a)
121 for (std::size_t b = 0; b < chain.size(); ++b) P(a, b) = trans(chain[a], chain[b]);
124 std::vector<T> avgtime(chain.size());
126 for (std::size_t a = 0; a < chain.size(); ++a) {
127 const std::size_t node = chain[a];
129 avgtime[a] = one / lambda(i, 0);
131 avgtime[a] = (one - exp(T(-lambda(i, node) * x[node - 1]))) / lambda(i, node);
132 den += ssprob[a] * avgtime[a];
134 if (den == zero)
throw NumericError(
"cache_ttl_lrua: zero total holding time for an item");
135 for (std::size_t a = 0; a < chain.size(); ++a)
136 randprob(i, chain[a]) = ssprob[a] * avgtime[a] / den;
157 const std::vector<T>& m,
const T& tol,
unsigned maxswp = 200) {
159 "cache_ttl_lrua requires transcendental arithmetic");
160 const std::size_t n = lambda.
rows();
161 const std::size_t h = m.size();
162 if (n == 0)
throw InputError(
"cache_ttl_lrua: no items");
163 if (h == 0)
throw InputError(
"cache_ttl_lrua: no lists");
164 if (lambda.
cols() != h + 1)
165 throw InputError(
"cache_ttl_lrua: the rate matrix must have h+1 columns");
166 if (R.size() != n)
throw InputError(
"cache_ttl_lrua: one access graph per item is required");
167 for (std::size_t i = 0; i < n; ++i)
168 if (R[i].rows() != h + 1 || R[i].cols() != h + 1)
169 throw InputError(
"cache_ttl_lrua: each access graph must be (h+1 x h+1)");
171 for (std::size_t l = 0; l < h; ++l)
172 if (!(m[l] > zero))
throw InputError(
"cache_ttl_lrua: list capacities must be positive");
175 for (
unsigned sweep = 0; sweep < maxswp; ++sweep) {
176 const std::vector<T> xold = x;
177 for (std::size_t l = 0; l < h; ++l) {
178 std::vector<T> work = x;
179 auto resid = [&](
const T& v) {
181 const Matrix<T> P = detail::lrua_randprob(lambda, R, work);
183 for (std::size_t i = 0; i < n; ++i) occ += P(i, l + 1);
184 return T(occ - m[l]);
188 if (!(resid(lo) < zero))
189 throw NumericError(
"cache_ttl_lrua: list occupancy exceeds its capacity even at a "
190 "vanishing characteristic time");
218 for (std::size_t i = 0; i < n; ++i)
219 if (lambda(i, l + 1) > colmax) colmax = lambda(i, l + 1);
221 const T saturated = colmax > zero
224 if (!(resid(saturated) > zero)) {
231 if (!(hi < saturated)) hi = saturated;
235 if (!(hi < saturated)) {
245 for (std::size_t l = 0; l < h; ++l) {
246 const T den = xold[l] > tol ? xold[l] : tol;
247 const T d =
num_abs(T(x[l] - xold[l])) / den;
248 if (d > rel) rel = d;
250 if (rel < tol)
break;
252 return detail::lrua_randprob(lambda, R, x);
NumericError(const std::string &what)
Equilibrium distribution of a discrete-time Markov chain, and stochastic complementation.
The exception types the port throws.
Dense matrix and non-owning view.
Matrix< T > cache_ttl_lrua(const Matrix< T > &lambda, const std::vector< Matrix< T > > &R, const std::vector< T > &m, const T &tol, unsigned maxswp=200)
TTL (characteristic-time) approximation of an LRU cache whose lists form an arbitrary access graph.
std::vector< T > dtmc_solve(const Matrix< T > &P)
Stationary distribution of a stochastic matrix P.
RootResult< T > root_bisect(F f, const T &a, const T &b, const T &tol, unsigned maxiter=200)
Bisection on a bracket with a sign change.
Number-type abstraction for the templated API port.
Deterministic scalar root finding.
Outcome of a scalar solve.
T root
best estimate of the root