5#ifndef LINE_SOLVERS_NC_SOLVER_NC_CACHE_H
6#define LINE_SOLVERS_NC_SOLVER_NC_CACHE_H
118 "solver_nc_cache_analyzer: the cache occupancy is a normalizing constant formed in "
119 "logarithms and needs transcendental arithmetic");
123 const double dnan = std::numeric_limits<double>::quiet_NaN();
124 const std::size_t K =
sn.nclasses;
126 std::size_t cacheNode = 0, sourceStation = 0;
127 for (std::size_t i = 0; i <
sn.nodes.size(); ++i) {
128 if (
sn.nodes[i].nodetype == qn::NodeType::Cache) cacheNode = i + 1;
129 if (
sn.nodes[i].nodetype == qn::NodeType::Source)
130 sourceStation =
sn.nodes[i].station;
132 if (cacheNode == 0)
throw UnsupportedError(
"solver_nc_cache_analyzer: no Cache node");
133 if (sourceStation == 0)
throw UnsupportedError(
"solver_nc_cache_analyzer: no Source node");
134 const auto itp =
sn.nodeparam.find(cacheNode);
135 if (itp ==
sn.nodeparam.end())
136 throw UnsupportedError(
"solver_nc_cache_analyzer: the Cache node carries no parameters");
139 std::vector<T> sourceRate(K, zero);
140 for (std::size_t r = 0; r < K; ++r)
141 if (!
sn.disabled[sourceStation - 1][r]) sourceRate[r] =
sn.rates(sourceStation - 1, r);
143 const std::vector<int>& m = ch.
itemcap;
144 const std::size_t n = ch.
nitems;
151 bool shortForAll = !m.empty();
153 if (
static_cast<long>(n) >=
static_cast<long>(cap) + 2) shortForAll =
false;
156 "solver_nc_cache_analyzer: NC requires the number of items to exceed the "
157 "cache capacity at least by 2; this cache holds " + std::to_string(n) +
158 " items with capacity " + std::to_string(m[0]));
160 const std::size_t h = m.size();
161 const std::size_t u = K;
166 std::vector<Matrix<T>> lambda(u,
Matrix<T>(n, h + 1, zero));
167 for (std::size_t v = 0; v < u; ++v)
168 if (!ch.
pread[v].empty())
169 for (std::size_t k = 0; k < n && k < ch.
pread[v].size(); ++k)
170 for (std::size_t l = 0; l <= h; ++l)
171 lambda[v](k, l) = T(sourceRate[v] * ch.
pread[v][k]);
176 std::vector<std::vector<Matrix<T>>> R = ch.
accost;
179 for (std::size_t v = 0; v < u; ++v)
180 for (std::size_t k = 0; k < n; ++k) {
182 for (std::size_t l = 0; l < h; ++l) Rm(l, l + 1) = one;
192 for (std::size_t v = 0; v < u; ++v)
193 for (std::size_t k = 0; k < n; ++k) lam1(v, k) = lambda[v](k, 0);
196 const std::vector<int>& sigma = ch.
itemsize;
197 const std::vector<int>& costcap = ch.
costcap;
198 if (!costcap.empty()) {
201 "solver_nc_cache_analyzer: storage cost caps require per-item sizes");
202 if (sigma.size() != n)
204 "solver_nc_cache_analyzer: the item size vector must have one entry per item");
205 if (costcap.size() != h)
207 "solver_nc_cache_analyzer: the cost cap vector must have one entry per cache "
214 std::ostringstream w;
215 w <<
"storage cost caps block the promotion path of item "
220 <<
" further pairs). The exact recursion normalizes over all size-feasible "
221 "states, which is then a strict superset of the states the cache can reach; "
222 "cross-check with SolverLDES.";
223 out.
sol.warning = w.str();
227 std::string cacheMethod =
opt.method;
231 if (cacheMethod ==
"rayint" || cacheMethod ==
"spm") cacheMethod =
"default";
237 for (std::size_t j = 0; j < h; ++j) msum += m[j];
238 const bool useSpmSize =
239 cacheMethod ==
"default" && !sigma.empty() && msum < static_cast<long>(n);
240 if (!costcap.empty() && !useSpmSize && cacheMethod !=
"exact" &&
241 cacheMethod !=
"sampling") {
245 double lattice =
static_cast<double>(n);
246 for (std::size_t j = 0; j < h; ++j)
247 lattice *=
static_cast<double>(m[j] + 1) *
static_cast<double>(costcap[j] + 1);
248 cacheMethod = (lattice <= 1e6) ?
"exact" :
"sampling";
250 std::ostringstream w;
251 w <<
"method '" <<
opt.method <<
"' does not support storage cost caps; using '"
252 << cacheMethod <<
"' instead.";
253 out.
sol.warning = out.
sol.warning.empty() ? w.str() : out.
sol.warning +
" " + w.str();
256 std::vector<T> missRate(u, zero);
259 if (cacheMethod ==
"exact") {
264 "solver_nc_cache_analyzer: NC does not support the exact solution of this "
265 "cache replacement policy -- only RR and FIFO are exchangeable, and a "
266 "recency-based policy (LRU, h-LRU, q-LRU, CLIMB) would silently receive the "
267 "exchangeable answer. Use the default (approximate) method or SolverCTMC");
269 for (std::size_t v = 0; v < u; ++v) {
271 for (std::size_t k = 0; k < n; ++k) acc += T(lambda[v](k, 0) * out.
pij(k, 0));
276 }
else if (useSpmSize) {
280 std::vector<int> raycap = costcap;
281 if (raycap.empty()) {
285 std::vector<int> srt = sigma;
286 std::sort(srt.begin(), srt.end(), std::greater<int>());
288 for (std::size_t j = 0; j < h; ++j) {
290 for (
int a = 0; a < m[j]; ++a) top += srt[static_cast<std::size_t>(a)];
297 for (std::size_t v = 0; v < u; ++v) {
299 for (std::size_t k = 0; k < n; ++k) acc += T(lambda[v](k, 0) * out.
pij(k, 0));
303 }
else if (cacheMethod ==
"sampling") {
321 for (std::size_t v = 0; v < u; ++v) {
322 if (v >= sourceRate.size())
break;
324 if (!(lam > 0.0))
continue;
325 out.
missprob[v] = T(missRate[v] / sourceRate[v]);
331 const std::size_t M =
sn.nstations;
336 out.
sol.sol.C.assign(K, zero);
337 out.
sol.sol.X.assign(K, zero);
338 for (std::size_t r = 0; r < K; ++r) out.
sol.sol.Tp(sourceStation - 1, r) = sourceRate[r];
339 for (std::size_t r = 0; r < K; ++r) {
342 if (hc == 0 ||
mc == 0)
continue;
343 out.
sol.sol.X[
mc - 1] = T(out.
sol.sol.X[
mc - 1] + missRate[r]);
344 out.
sol.sol.X[hc - 1] = T(out.
sol.sol.X[hc - 1] + (sourceRate[r] - missRate[r]));
346 out.
sol.sol.lG = 0.0;
347 out.
sol.sol.iter = 1;
348 out.
sol.sol.method = method;
349 out.
sol.actualmethod = method;
356 for (std::size_t v = 0; v < u; ++v) {
357 if (ch.
pread[v].empty())
continue;
358 for (std::size_t l = 0; l < h; ++l) {
360 for (std::size_t k = 0; k < n && k < ch.
pread[v].size(); ++k)
361 acc += T(ch.
pread[v][k] * out.
pij(k, l + 1));
379 if (!sigma.empty() && out.
pij.rows() == n && out.
pij.cols() == h + 1) {
390 if (
sn.nodes.size() != 3)
return false;
391 int src = 0, ca = 0, snk = 0;
393 if (nd.
nodetype == qn::NodeType::Source) ++src;
394 else if (nd.
nodetype == qn::NodeType::Cache) ++ca;
395 else if (nd.
nodetype == qn::NodeType::Sink) ++snk;
397 if (!(src == 1 && ca == 1 && snk == 1))
return false;
Mean per-list storage cost of a cache with item sizes, and the screen for promotion paths that storag...
Access factors of a tree-structured multi-list cache.
Cache miss rates from the importance-sampling hit probabilities.
Saddle-point approximation of the cache miss rates.
Exact per-item hit and miss probabilities of a multi-list cache.
Importance-sampling estimate of the cache hit-probability distribution.
Saddle-point approximation of the per-item cache hit probabilities.
Ray (WKB) asymptotic expansion of the cost-capped cache normalizing constant.
UnsupportedError(const std::string &what)
A network plus its refreshed NetworkStruct.
The exception types the port throws.
Dense matrix and non-owning view.
std::vector< CacheBlockedPair > cache_cost_pathcheck(const Matrix< T > &gamma, const std::vector< int > &sigma, const std::vector< int > &k, const std::vector< int > &parent)
std::vector< T > cache_cost(const Matrix< T > &gamma, const std::vector< int > &m, const std::vector< int > &sigma, const std::vector< int > &k, const Matrix< T > &pij)
Mean per-list storage cost of a cache with item sizes, and the screen for promotion paths that storag...
CacheGammaResult< T > cache_gamma_lp(const std::vector< Matrix< T > > &lambda, const std::vector< std::vector< Matrix< T > > > &R)
Access factors of a tree-structured multi-list cache.
CacheMissIsResult< T > cache_miss_is(const Matrix< T > &gamma, const std::vector< int > &m, const Matrix< T > &lambda, std::size_t samples, std::uint64_t seed, const std::vector< int > &sigma, const std::vector< int > &cap)
Cache miss rates from the importance-sampling hit probabilities.
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.
CacheSpmSizeResult< T > cache_spm_size(const Matrix< T > &gamma, const std::vector< int > &m, const std::vector< int > &sigma, const std::vector< int > &k, CacheCostMode mode=CacheCostMode::AtMost)
Ray (WKB) asymptotic expansion of the cost-capped cache normalizing constant.
CacheMissSpmResult< T > cache_miss_spm(const Matrix< T > &gamma, const std::vector< int > &m, const Matrix< T > &lambda)
Saddle-point approximation of the cache miss rates.
Matrix< T > cache_prob_spm(const Matrix< T > &gamma, const std::vector< int > &m)
Saddle-point approximation of the per-item cache hit probabilities.
@ FIFO
first in, first out
NcCacheSolution< T > solver_nc_cache_analyzer(const qn::NetworkStruct< T > &sn, const NcSolverOptions &opt)
Port of solver_nc_cache_analyzer.m.
bool nc_is_noreentrant_cache(const qn::NetworkStruct< T > &sn)
True when the model is exactly a Source, a Cache and a Sink.
Controls and result shape shared by the normalizing-constant analyzers.
A queueing network and its refreshed NetworkStruct.
Port of solver_nc.m: the load-INDEPENDENT normalizing-constant analyzer.
Return value of cache_gamma_lp, mirroring [gamma,u,n,h].
std::vector< int > parent
Parent list of each list, 0-based, -1 for lists rooted in the miss list.
Matrix< T > gamma
(n x h) access factors
std::vector< T > MU
(u) per-user miss rate; empty when no lambda given
Return value of cache_miss_spm, mirroring [M,MU,MI,pi0,lE].
std::vector< T > MU
(u) per-user miss rate
Outcome of the expansion.
Matrix< T > pij
Occupancy pi, n x (h+1), column 0 the miss probability.
What the cache analyzer returns beyond the usual metric table.
Matrix< T > hitproblist
(u x h) access-weighted per-list hit probability, NaN if not exact
Matrix< T > pij
(n x h+1) per-item occupancy, column 0 = miss
std::vector< T > missrate
(u) per-class miss rate
std::vector< cache::CacheBlockedPair > costcap_blocked
Storage cost caps that block a promotion path, so that the exact recursion normalizes over MORE state...
std::vector< T > missprob
(u) per-class miss and hit PROBABILITIES, missrate divided by the read class's arrival rate and its c...
Matrix< T > itemprob
(n x h+1) the same from the EXACT recursion, NaN above 10 items
bool costcap_method_switched
True when the requested method had no cost-capped counterpart and was switched.
std::vector< T > listcost
(h) mean storage cost held by each list, EMPTY without item sizes
The [Q,U,R,T,C,X,lG] of the reference, plus the algorithm that ran.
Controls, defaulting to SolverOptions('NC') in the reference.
std::vector< int > itemsize
Per-item storage cost (size) and per-list cap on the total cost of the resident items (ton21cache Sec...
std::vector< int > costcap
std::vector< std::vector< Matrix< T > > > accost
(u) x (n) of (h+1)x(h+1), or empty
std::vector< int > itemcap
std::vector< std::size_t > missclass
std::vector< std::size_t > hitclass
lang::ReplacementStrategy replacestrat
std::vector< std::vector< T > > pread
(u) x (n), empty row = NaN
One job class of the network.
double population
infinite for an open class