5#ifndef LINE_API_DA_DA_CACHEQN_RETRIEVAL_H
6#define LINE_API_DA_DA_CACHEQN_RETRIEVAL_H
96 "da_cacheqn_retrieval requires transcendental arithmetic: it alternates two "
97 "tolerance-stopped solves");
100 const std::size_t I =
sn.nodes.size(), K =
sn.nclasses;
102 std::vector<std::size_t> caches;
103 for (std::size_t nd = 0; nd < I; ++nd)
104 if (
sn.nodes[nd].nodetype == qn::NodeType::Cache) caches.push_back(nd);
105 if (caches.size() != 1)
106 throw UnsupportedError(
"da_cacheqn_retrieval: requires exactly one Cache node");
107 const std::size_t ci = caches[0];
111 throw UnsupportedError(
"da_cacheqn_retrieval: the Cache carries no retrieval system");
113 const std::vector<std::size_t>& queueNodes = ch.
retrieval_queues.begin()->second;
114 if (queueNodes.size() != 1)
116 "da_cacheqn_retrieval: currently supports a single-station (single-backend) retrieval "
117 "system; this cache fetches through " + std::to_string(queueNodes.size()));
118 const std::size_t fetchNode = queueNodes[0];
119 const std::size_t fetchStation =
sn.nodes[fetchNode - 1].station;
120 if (fetchStation == 0)
121 throw UnsupportedError(
"da_cacheqn_retrieval: the retrieval node is not a station");
123 const std::size_t nitems = ch.
nitems;
125 for (
int c : ch.
itemcap) totcap += c;
126 const long n_eff_l = std::max<long>(1,
static_cast<long>(nitems) - totcap);
127 const double n_eff =
static_cast<double>(n_eff_l);
131 if (std::isfinite(c.population)) Npop_d += c.population;
132 const std::size_t Npop =
static_cast<std::size_t
>(std::llround(Npop_d));
135 "da_cacheqn_retrieval: the closed delayed-hit decomposition needs a positive closed "
143 std::vector<T> alpha(std::max<std::size_t>(1, Npop), one);
144 for (std::size_t k = 1; k <= Npop; ++k) {
145 const double d = n_eff * (1.0 - std::pow(1.0 - 1.0 / n_eff,
static_cast<double>(k)));
148 for (std::size_t i = 0; i <
sn.nstations; ++i) {
149 std::vector<T>& lld =
sn.stations[i].lldscaling;
150 if (lld.size() < Npop) lld.resize(Npop, one);
152 sn.stations[fetchStation - 1].lldscaling = alpha;
155 sn.nodes[ci].nodetype = qn::NodeType::ClassSwitch;
157 std::vector<T> pread = ch.
pread.at(readClass - 1);
159 for (
const T& v : pread) psum += v;
161 throw UnsupportedError(
"da_cacheqn_retrieval: the read class has no item popularity");
162 for (T& v : pread) v = T(v / psum);
170 fpopt.
iter_max =
static_cast<std::size_t
>(
opt.iter_max);
173 std::vector<T> x0(K, zero);
174 x0[readClass - 1] = one;
176 const auto sweep = [&](
const std::vector<T>& x,
177 std::size_t) -> std::pair<std::vector<T>, std::vector<T> > {
178 std::vector<T> lambda = x;
191 dch.
pread.resize(lambda.size());
196 for (std::size_t v = 0; v < u; ++v)
197 for (std::size_t k = 0; k < nitems; ++k) lam_un(v, k) = iso.
lambda_cache[v](k, 0);
200 std::vector<T> pi0(nitems, zero);
201 for (std::size_t k = 0; k < nitems && k < mf.
pi0.size(); ++k) pi0[k] = mf.
pi0[k];
203 for (std::size_t k = 0; k < nitems; ++k) nonhit += T(pread[k] * pi0[k]);
204 const T hp = T(one - nonhit);
209 const std::size_t r = readClass - 1;
210 for (std::size_t col = 0; col < I * K; ++col)
sn.rtnodes(ci * K + r, col) = zero;
212 if (hc == 0 ||
mc == 0)
214 "da_cacheqn_retrieval: the read class has no hit or miss class");
215 sn.rtnodes(ci * K + r, ci * K + (hc - 1)) = hp;
216 for (std::size_t i = 0; i < nitems; ++i) {
217 const std::size_t rcls =
221 if (rcls == 0)
continue;
222 sn.rtnodes(ci * K + r, (fetchNode - 1) * K + (rcls - 1)) = T(pread[i] * pi0[i]);
223 for (std::size_t col = 0; col < I * K; ++col)
224 sn.rtnodes((fetchNode - 1) * K + (rcls - 1), col) = zero;
225 sn.rtnodes((fetchNode - 1) * K + (rcls - 1), ci * K + (
mc - 1)) = one;
227 for (std::size_t col = 0; col < I * K; ++col)
228 sn.rtnodes(ci * K + (rcls - 1), col) = zero;
230 sn.da_recompute_visits_from_rtnodes();
233 outr.
res = netfun(
sn);
236 for (std::size_t c = 0; c <
sn.nchains; ++c)
237 for (std::size_t a = 0; a < I; ++a)
238 for (std::size_t k = 0; k < K; ++k)
239 nv(a, k) = T(nv(a, k) +
sn.nodevisits[c](a, k));
240 std::size_t chain =
sn.nchains;
241 for (std::size_t c = 0; c <
sn.nchains; ++c)
242 if (
sn.chains[c][r]) chain = c;
244 if (chain <
sn.nchains) {
245 const std::size_t refnode =
sn.node_of_station(
sn.classes[r].refstat);
246 denom =
sn.refclass[chain] > 0 ? nv(refnode - 1,
sn.refclass[chain] - 1)
247 : nv(refnode - 1, r);
250 if (chain <
sn.nchains)
251 for (std::size_t k = 0; k < K; ++k)
252 if (
sn.chains[chain][k] && k < outr.
res.X.size()) Xr += outr.
res.X[k];
253 if (denom > zero) lambda[r] = T(Xr * nv(ci, r) / denom);
258 return std::make_pair(lambda, x);
Cache miss rates from the fixed-point multipliers.
UnsupportedError(const std::string &what)
A network plus its refreshed NetworkStruct.
Isolated-cache input construction for the decomposition methods.
Damped fixed-point iteration, the shared driver of the decomposition algorithms.
The exception types the port throws.
Dense matrix and non-owning view.
The option and result types every MVA analyzer shares.
CacheMissResult< T > cache_miss_fpi(const Matrix< T > &gamma, const std::vector< int > &m, const Matrix< T > &lambda)
Cache miss rates from the fixed-point multipliers.
CacheqnRetrievalResult< T > da_cacheqn_retrieval(qn::NetworkStruct< T > sn, const std::function< mva::MvaSolution< T >(const qn::NetworkStruct< T > &)> &netfun, const mva::MvaOptions &opt)
Port of da_cacheqn_retrieval.
FpiResult< T > da_fpi(const std::function< std::pair< std::vector< T >, std::vector< T > >(const std::vector< T > &, std::size_t)> &iterfun, const std::vector< T > &x0, const FpiOptions &options=FpiOptions())
Damped fixed-point iteration, the shared driver of the decomposition algorithms.
CacheIsolateResult< T > da_cache_isolate(const CacheParam< T > &ch, const std::vector< T > &lambda)
Isolated-cache input construction for the decomposition methods.
A queueing network and its refreshed NetworkStruct.
Number-type abstraction for the templated API port.
Return value of cache_miss, mirroring [M,MU,MI,pi0].
std::vector< T > pi0
(n) per-item miss probability; empty when no lambda given
Return value of da_cache_isolate, mirroring [gamma,lambda_cache,Rcost].
std::vector< Matrix< T > > lambda_cache
(u) matrices of size n x (h+1)
Matrix< T > gamma
(n x h) access factors
The fields of sn.nodeparam{cache} that da_cache_isolate reads.
std::vector< int > itemcap
(h) list capacities
std::vector< std::vector< Matrix< T > > > accost
(u) x (n) of (h+1)x(h+1), or empty
std::vector< std::vector< T > > pread
(u) x (n), empty row = NaN
What the delayed-hit decomposition returns.
std::vector< T > hitprob
(K) P(item cached), read class only
std::vector< T > delayedprob
(K) zero on this path; see the header
qn::NetworkStruct< T > sn
the mutated struct, cache relabelled
mva::MvaSolution< T > res
std::vector< T > missprob
(K)
Options mirroring the fields MATLAB reads off the options struct.
The options SolverMVA reads.
Class-level results, the [Q,U,R,T,C,X] of the MATLAB analyzers.
std::map< std::size_t, std::vector< std::size_t > > retrieval_queues
read class(0-based)->nodes
std::vector< std::vector< Matrix< T > > > accost
(u) x (n) of (h+1)x(h+1), or empty
std::vector< std::vector< std::size_t > > retrieval_classes
(nitems x nclasses), 1-based
std::vector< int > itemcap
std::vector< std::size_t > missclass
std::vector< std::size_t > hitclass
std::vector< std::vector< T > > pread
(u) x (n), empty row = NaN
One job class of the network.