112 "retrieval_fpi requires transcendental arithmetic: it is a successive "
113 "substitution stopped on a relative tolerance, so its answer is the fixed "
114 "point only to within tol whatever the arithmetic");
115 const std::size_t n = lambda.size();
116 const std::size_t h = m.size();
117 if (eta.
rows() != n || gamma.
rows() != n)
118 throw InputError(
"retrieval_fpi: eta/gamma and lambda disagree on the item count");
119 if (gamma.
cols() != h)
120 throw InputError(
"retrieval_fpi: gamma and m disagree on the number of lists");
121 if (eta.
cols() == 0)
throw InputError(
"retrieval_fpi: eta has no columns");
122 const std::size_t r = eta.
cols() - 1;
132 std::vector<T> pi0(n, one);
135 for (std::size_t i = 0; i < n; ++i) {
137 for (std::size_t j = 0; j < h; ++j) {
138 pij(j, i) = c0.
pij(i, j);
139 sum_pij += pij(j, i);
141 pi0[i] = one - sum_pij;
146 double last_delta = 0.0;
147 for (std::size_t t = 1; t <= options.max_iter; ++t) {
152 for (std::size_t s = 0; s < r; ++s) {
154 for (std::size_t i = 0; i < n; ++i) tot += phi(s + 1, i);
155 for (std::size_t i = 0; i < n; ++i) F(s, i) = one + (tot - phi(s + 1, i));
159 for (std::size_t i = 0; i < n; ++i) {
160 D[i] = one + lambda[i] * eta(i, 0);
161 for (std::size_t s = 0; s < r; ++s) D[i] += lambda[i] * eta(i, s + 1) * F(s, i);
165 for (std::size_t i = 0; i < n; ++i)
166 for (std::size_t j = 0; j < h; ++j) theta(i, j) = gamma(i, j) / D[i];
172 std::vector<T> pi0_new(n);
174 for (std::size_t i = 0; i < n; ++i) {
176 for (std::size_t l = 0; l < h; ++l) denom += theta(i, l) * xi[l];
177 const T A = one / denom;
178 for (std::size_t j = 0; j < h; ++j) pij_new(j, i) = theta(i, j) * xi[j] * A;
179 pi0_new[i] = A / D[i];
180 phi_new(0, i) = A * lambda[i] * eta(i, 0) / D[i];
181 for (std::size_t s = 0; s < r; ++s)
182 phi_new(s + 1, i) = A * lambda[i] * eta(i, s + 1) * F(s, i) / D[i];
185 const std::vector<T> pij_flat(pij_new.
data(), pij_new.
data() + pij_new.
size());
186 const std::vector<T> pij_old(pij.
data(), pij.
data() + pij.
size());
187 const std::vector<T> phi_flat(phi_new.
data(), phi_new.
data() + phi_new.
size());
188 const std::vector<T> phi_old(phi.
data(), phi.
data() + phi.
size());
189 double delta = detail::fpi_reldiff(pi0_new, pi0);
190 const double d2 = detail::fpi_reldiff(pij_flat, pij_old);
191 const double d3 = detail::fpi_reldiff(phi_flat, phi_old);
192 if (d2 > delta) delta = d2;
193 if (d3 > delta) delta = d3;
200 if (!std::isfinite(delta)) {
202 out.
warning =
"FPI diverged (non-finite iterate) at iteration " + std::to_string(t) +
".";
206 if (delta < options.tol || r == 0) {
214 std::snprintf(buf,
sizeof(buf),
"%.2e", last_delta);
215 out.
warning =
"FPI did not converge within " + std::to_string(options.max_iter) +
216 " iterations (last rel. change " + buf +
").";
220 std::cerr <<
"[LINE] Warning: retrieval_fpi: " << out.
warning << std::endl;
RetrievalFpiResult< T > retrieval_fpi(const std::vector< int > &m, const std::vector< T > &lambda, const Matrix< T > &eta, const Matrix< T > &gamma, const FpiOptions &options=FpiOptions())
Fixed-point heuristic for a delayed-hit (list-based) cache.