82 const std::vector<int>& N,
const Matrix<T>& Z,
const T& atol) {
83 const std::size_t R = N.size();
85 throw InputError(
"pfqn_nc_sanitize: L and N disagree on the class count");
87 throw InputError(
"pfqn_nc_sanitize: Z and N disagree on the class count");
88 if (!lambda.empty() && lambda.size() != R)
89 throw InputError(
"pfqn_nc_sanitize: lambda and N disagree on the class count");
93 const std::size_t M = L.
empty() ? 0 : L.
rows();
94 const std::size_t D = Z.
empty() ? 0 : Z.
rows();
97 const auto colsum = [](
const Matrix<T>& A, std::size_t r,
const T& z) {
99 for (std::size_t i = 0; i < A.
rows(); ++i) s += A(i, r);
107 std::vector<std::size_t> keep;
108 for (std::size_t r = 0; r < R; ++r) {
109 if (N[r] == 0)
continue;
110 const T tot = colsum(L, r, zero) + colsum(Z, r, zero);
111 if (tot < atol)
continue;
117 std::vector<std::size_t> retained;
118 for (std::size_t k = 0; k < keep.size(); ++k) {
119 const std::size_t r = keep[k];
120 const T ldem = colsum(L, r, zero);
121 if (M > 0 && ldem < atol) {
122 const T zr = colsum(Z, r, zero);
127 retained.push_back(r);
130 const std::size_t Rk = retained.size();
133 std::vector<T> scale(Rk, one);
134 for (std::size_t k = 0; k < Rk; ++k) {
135 const std::size_t r = retained[k];
136 if (M == 0)
continue;
138 for (std::size_t i = 1; i < M; ++i)
139 if (L(i, r) > mx) mx = L(i, r);
140 if (mx > zero) scale[k] = mx;
142 for (std::size_t k = 0; k < Rk; ++k)
146 std::vector<std::size_t> ord(Rk);
147 std::iota(ord.begin(), ord.end(),
static_cast<std::size_t
>(0));
148 std::vector<T> zsum(Rk, zero);
149 for (std::size_t k = 0; k < Rk; ++k) zsum[k] = colsum(Z, retained[k], zero) / scale[k];
152 std::stable_sort(ord.begin(), ord.end(),
153 [&](std::size_t a, std::size_t b) { return zsum[a] < zsum[b]; });
155 std::stable_partition(ord.begin(), ord.end(),
156 [&](std::size_t a) { return !(zsum[a] >= atol); });
162 if (!lambda.empty()) res.
lambda.assign(Rk, zero);
163 for (std::size_t k = 0; k < Rk; ++k) {
164 const std::size_t src = retained[ord[k]];
165 const T& sc = scale[ord[k]];
166 for (std::size_t i = 0; i < M; ++i) res.
L(i, k) = L(i, src) / sc;
167 for (std::size_t i = 0; i < D; ++i) res.
Z(i, k) = Z(i, src) / sc;
170 if (!lambda.empty()) res.
lambda[k] = lambda[src];
NcSanitizeResult< T > pfqn_nc_sanitize(const std::vector< T > &lambda, const Matrix< T > &L, const std::vector< int > &N, const Matrix< T > &Z, const T &atol)
Preprocessing shared by the normalizing-constant solvers: drop the classes that cannot contribute,...