LINE Solver (C++)
Templated C++ port of the LINE queueing solver
Loading...
Searching...
No Matches
cache_retrieval_inputs.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_RETRIEVAL_CACHE_RETRIEVAL_INPUTS_H
6#define LINE_API_RETRIEVAL_CACHE_RETRIEVAL_INPUTS_H
7
8/**
9 * @file
10 * @ingroup api_retrieval
11 * Extract the delayed-hit retrieval-algorithm inputs from a NetworkStruct, a
12 * port of matlab/src/api/retrieval/cache_retrieval_inputs.m.
13 *
14 * Given a Cache equipped with a retrieval system (set_retrieval_system), rebuilds
15 * the inputs the retrieval_* algorithms read: the list capacities m, the per-item
16 * arrival rates lambda (readRate * pread), the access factors gamma
17 * (cache_gamma_lp), the fetching demands eta, the per-station phase-type service
18 * (alpha, T -> RetrievalStationPH), and the per-item routing R over the cache and
19 * the retrieval stations. Single read class (IRM); IS / PS / SIRO / FCFS / LCFSPR
20 * stations only, with SIRO/FCFS requiring exponential, class-independent service.
21 *
22 * ARITHMETIC: transcendental (the downstream FPI does), so this refuses under
23 * Rational at the analyzer's guard; here it is field arithmetic plus PH means.
24 */
25
26#include <cmath>
27#include <cstddef>
28#include <string>
29#include <vector>
30
35#include "line/num/number.h"
36#include "line/util/error.h"
37#include "line/util/linalg.h"
38#include "line/util/matrix.h"
39
40namespace line {
41namespace retrieval {
42
43/** The [m, lambda, gamma, eta, alpha/T (station), R] the retrieval algorithms read. */
44template <class T>
46 std::vector<int> m; ///< (h) list capacities
47 std::vector<T> lambda; ///< (n) per-item arrival rates
48 Matrix<T> gamma; ///< (n x h) access factors
49 Matrix<T> eta; ///< (n x (r+1)) fetching demands
50 std::vector<RetrievalStationPH<T> > station; ///< (S) per-station PH service + type
51 std::vector<Matrix<T> > R; ///< (n) routing over cache+stations, (S+1)x(S+1)
52 std::size_t read_class = 0; ///< 1-based read (job-in) class
53 std::vector<std::size_t> queue_nodes; ///< 1-based retrieval station nodes
54};
55
56/**
57 * @brief Extract the delayed-hit retrieval-algorithm inputs from a
58 * NetworkStruct, a port of
59 * matlab/src/api/retrieval/cache_retrieval_inputs.m.
60 *
61 * @param sn the model struct with a retrieval-system cache
62 * @param lambda_override the closed-sublayer read rate; <0 selects the Source
63 * throughput (open model)
64 */
65template <class T>
67 double lambda_override = -1.0) {
68 const T zero = num_traits<T>::from_int(0);
69 // -- locate the cache and its retrieval system --------------------------
70 std::size_t ci = 0;
71 for (const auto& kv : sn.nodeparam)
72 if (sn.nodes[kv.first - 1].nodetype == qn::NodeType::Cache) {
73 if (ci != 0) throw InputError("cache_retrieval_inputs: more than one Cache node");
74 ci = kv.first;
75 }
76 if (ci == 0) throw InputError("cache_retrieval_inputs: no Cache node");
77 const qn::CacheParam<T>& ch = sn.nodeparam.at(ci);
78 if (ch.retrieval_capacity <= 0)
79 throw InputError("cache_retrieval_inputs: the Cache has no retrieval system");
80 if (ch.retrieval_queues.size() != 1)
81 throw UnsupportedError("cache_retrieval_inputs: a single read class is supported");
82
84 out.m = ch.itemcap;
85 const std::size_t n = ch.nitems, h = ch.itemcap.size(), K = sn.nclasses;
86
87 const std::size_t rd0 = ch.retrieval_queues.begin()->first; // 0-based read class
88 const std::size_t jobin = rd0 + 1; // 1-based
89 out.read_class = jobin;
90 out.queue_nodes = ch.retrieval_queues.begin()->second; // 1-based nodes
91 const std::vector<std::size_t>& qn = out.queue_nodes;
92 const std::size_t S = qn.size();
93 if (S == 0) throw InputError("cache_retrieval_inputs: the retrieval system has no stations");
94
95 // -- per-item arrival rates lambda(i) = readRate * pread(i) -------------
96 T readRate;
97 if (lambda_override >= 0.0) {
98 readRate = num_traits<T>::from_double(lambda_override);
99 } else {
100 const std::size_t src_st = sn.stations[sn.sourceIdx - 1].nodetype == qn::NodeType::Source
101 ? sn.sourceIdx
102 : 0;
103 if (src_st == 0) throw InputError("cache_retrieval_inputs: open model needs a Source");
104 readRate = sn.disabled[src_st - 1][jobin - 1] ? zero : sn.rates(src_st - 1, jobin - 1);
105 }
106 const std::vector<T>& pread = ch.pread[jobin - 1];
107 out.lambda.assign(n, zero);
108 for (std::size_t i = 0; i < n; ++i) out.lambda[i] = T(readRate * pread[i]);
109
110 // -- gamma via cache_gamma_lp (one user stream) -------------------------
111 Matrix<T> lam3d(n, h + 1, zero);
112 for (std::size_t i = 0; i < n; ++i)
113 for (std::size_t l = 0; l <= h; ++l) lam3d(i, l) = out.lambda[i];
114 std::vector<std::vector<Matrix<T> > > Rcost(1, std::vector<Matrix<T> >());
115 if (!ch.accost.empty() && !ch.accost[jobin - 1].empty()) {
116 Rcost[0] = ch.accost[jobin - 1];
117 } else {
118 // default linear cache: item flows from list l to l+1, absorbs at h.
119 Rcost[0].resize(n, Matrix<T>(h + 1, h + 1, zero));
120 for (std::size_t k = 0; k < n; ++k) {
121 for (std::size_t l = 0; l < h; ++l) Rcost[0][k](l, l + 1) = num_traits<T>::from_int(1);
122 Rcost[0][k](h, h) = num_traits<T>::from_int(1);
123 }
124 }
125 out.gamma = cache::cache_gamma_lp(std::vector<Matrix<T> >(1, lam3d), Rcost).gamma;
126
127 // -- station types ------------------------------------------------------
128 std::vector<RetrievalStationType> stype(S);
129 for (std::size_t s = 0; s < S; ++s) {
130 const std::size_t st = sn.nodes[qn[s] - 1].station;
131 switch (sn.stations[st - 1].sched) {
132 case qn::SchedStrategy::INF: stype[s] = RetrievalStationType::IS; break;
133 case qn::SchedStrategy::PS: stype[s] = RetrievalStationType::PS; break;
134 case qn::SchedStrategy::SIRO: stype[s] = RetrievalStationType::SIRO; break;
135 case qn::SchedStrategy::FCFS: stype[s] = RetrievalStationType::FCFS; break;
136 case qn::SchedStrategy::LCFSPR: stype[s] = RetrievalStationType::LCFSPR; break;
137 default:
138 throw UnsupportedError(
139 "cache_retrieval_inputs: a retrieval station uses an unsupported scheduling "
140 "policy (only IS/PS/SIRO/FCFS/LCFSPR)");
141 }
142 }
143
144 // -- per-item PH service (alpha, T) per station, routing R --------------
145 out.station.resize(S);
146 for (std::size_t s = 0; s < S; ++s) out.station[s].type = stype[s];
147 std::vector<std::size_t> fsz(S, 0);
148 for (std::size_t s = 0; s < S; ++s) {
149 const std::size_t st = sn.nodes[qn[s] - 1].station;
150 const std::size_t rc0 = ch.retrieval_classes[0][jobin - 1]; // item-1 retrieval class
151 const lang::Distrib<T> d0 = sn.service[st - 1][rc0 - 1];
152 fsz[s] = lang::dist_to_map(d0).D0.rows();
153 if ((stype[s] == RetrievalStationType::SIRO || stype[s] == RetrievalStationType::FCFS) &&
154 fsz[s] > 1)
155 throw UnsupportedError(
156 "cache_retrieval_inputs: SIRO/FCFS retrieval stations need exponential service");
157 out.station[s].alpha = Matrix<T>(n, fsz[s], zero);
158 out.station[s].sub.assign(n, Matrix<T>(fsz[s], fsz[s], zero));
159 }
160
161 out.R.assign(n, Matrix<T>(S + 1, S + 1, zero));
162 auto lin = [&](std::size_t node, std::size_t cls) { return (node - 1) * K + (cls - 1); };
163 for (std::size_t i = 0; i < n; ++i) {
164 const std::size_t rcls = ch.retrieval_classes[i][jobin - 1];
165 for (std::size_t s = 0; s < S; ++s) {
166 const std::size_t st = sn.nodes[qn[s] - 1].station;
167 const lang::Distrib<T> d = sn.service[st - 1][rcls - 1];
168 const std::vector<T> pie = lang::dist_pie(d);
169 const Matrix<T> D0 = lang::dist_to_map(d).D0;
170 for (std::size_t a = 0; a < fsz[s]; ++a) {
171 out.station[s].alpha(i, a) = pie[a];
172 for (std::size_t b = 0; b < fsz[s]; ++b) out.station[s].sub[i](a, b) = D0(a, b);
173 }
174 }
175 for (std::size_t s = 0; s < S; ++s) {
176 out.R[i](0, s + 1) = sn.rtnodes(lin(ci, rcls), lin(qn[s], rcls));
177 out.R[i](s + 1, 0) = sn.rtnodes(lin(qn[s], rcls), lin(ci, rcls));
178 for (std::size_t sp = 0; sp < S; ++sp)
179 out.R[i](s + 1, sp + 1) = sn.rtnodes(lin(qn[s], rcls), lin(qn[sp], rcls));
180 }
181 }
182
183 // -- eta: IS column 0, PS-family columns 1..r ---------------------------
184 std::vector<std::size_t> isIdx, psIdx;
185 for (std::size_t s = 0; s < S; ++s)
186 (stype[s] == RetrievalStationType::IS ? isIdx : psIdx).push_back(s);
187 const std::size_t r = psIdx.size();
188 out.eta = Matrix<T>(n, r + 1, zero);
189 for (std::size_t i = 0; i < n; ++i) {
190 // visits = a (I - Pmat)^-1 over the S stations
191 Matrix<T> ImP(S, S, zero);
192 std::vector<T> a(S, zero);
193 for (std::size_t s = 0; s < S; ++s) {
194 a[s] = out.R[i](0, s + 1);
195 for (std::size_t sp = 0; sp < S; ++sp)
196 ImP(s, sp) = T((s == sp ? num_traits<T>::from_int(1) : zero) - out.R[i](s + 1, sp + 1));
197 }
198 const Matrix<T> F = inverse(ImP);
199 std::vector<T> visits(S, zero);
200 for (std::size_t s = 0; s < S; ++s) {
201 T acc = zero;
202 for (std::size_t sp = 0; sp < S; ++sp) acc = T(acc + a[sp] * F(sp, s));
203 visits[s] = acc;
204 }
205 std::vector<T> tau(S, zero);
206 for (std::size_t s = 0; s < S; ++s) {
207 Matrix<T> arow(1, fsz[s], zero);
208 for (std::size_t a = 0; a < fsz[s]; ++a) arow(0, a) = out.station[s].alpha(i, a);
209 tau[s] = detail::ph_mean(arow, out.station[s].sub[i]);
210 }
211 T is_sum = zero;
212 for (std::size_t s : isIdx) is_sum = T(is_sum + visits[s] * tau[s]);
213 out.eta(i, 0) = is_sum;
214 for (std::size_t p = 0; p < r; ++p) out.eta(i, 1 + p) = T(visits[psIdx[p]] * tau[psIdx[p]]);
215 }
216 return out;
217}
218
219} // namespace retrieval
220} // namespace line
221
222#endif // LINE_API_RETRIEVAL_CACHE_RETRIEVAL_INPUTS_H
Access factors of a tree-structured multi-list cache.
InputError(const std::string &what)
Definition error.h:39
UnsupportedError(const std::string &what)
Definition error.h:51
A network plus its refreshed NetworkStruct.
What refreshProcessRepresentations and refreshLST compute FROM a distribution: the (D0,...
The exception types the port throws.
Dense linear algebra over the templated number type: products, identity, inverse, and powers.
Dense matrix and non-owning view.
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.
mam::Map< T > dist_to_map(const Distrib< T > &d)
std::vector< T > dist_pie(const Distrib< T > &d)
sn.pie: the phase distribution seen by an arriving job.
RetrievalInputs< T > cache_retrieval_inputs(const qn::NetworkStruct< T > &sn, double lambda_override=-1.0)
Extract the delayed-hit retrieval-algorithm inputs from a NetworkStruct, a port of matlab/src/api/ret...
Matrix< T > inverse(const Matrix< T > &A)
Inverse by LU with one factorization and n back substitutions.
Definition linalg.h:72
A queueing network and its refreshed NetworkStruct.
Number-type abstraction for the templated API port.
FPI-based approximation of the delayed-hit count and the expected latency of a list-based cache with ...
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::vector< T > > pread
(u) x (n), empty row = NaN
The [m, lambda, gamma, eta, alpha/T (station), R] the retrieval algorithms read.
std::vector< int > m
(h) list capacities
std::vector< Matrix< T > > R
(n) routing over cache+stations, (S+1)x(S+1)
std::size_t read_class
1-based read (job-in) class
Matrix< T > gamma
(n x h) access factors
std::vector< std::size_t > queue_nodes
1-based retrieval station nodes
std::vector< T > lambda
(n) per-item arrival rates
std::vector< RetrievalStationPH< T > > station
(S) per-station PH service + type
Matrix< T > eta
(n x (r+1)) fetching demands