97 const std::vector<int>& N,
const Matrix<T>& Z,
const T& atol) {
98 const std::size_t R = N.size();
100 throw InputError(
"pfqn_nc_sanitize: L and N disagree on the class count");
102 throw InputError(
"pfqn_nc_sanitize: Z and N disagree on the class count");
103 if (!lambda.empty() && lambda.size() != R)
104 throw InputError(
"pfqn_nc_sanitize: lambda and N disagree on the class count");
108 const std::size_t M = L.
empty() ? 0 : L.
rows();
109 const std::size_t D = Z.
empty() ? 0 : Z.
rows();
112 const auto colsum = [](
const Matrix<T>& A, std::size_t r,
const T& z) {
114 for (std::size_t i = 0; i < A.
rows(); ++i) s += A(i, r);
122 std::vector<std::size_t> keep;
123 for (std::size_t r = 0; r < R; ++r) {
124 if (N[r] == 0)
continue;
125 const T tot = colsum(L, r, zero) + colsum(Z, r, zero);
126 if (tot < atol)
continue;
132 std::vector<std::size_t> retained;
133 for (std::size_t k = 0; k < keep.size(); ++k) {
134 const std::size_t r = keep[k];
135 const T ldem = colsum(L, r, zero);
136 if (M > 0 && ldem < atol) {
137 const T zr = colsum(Z, r, zero);
142 retained.push_back(r);
145 const std::size_t Rk = retained.size();
148 std::vector<T> scale(Rk, one);
149 for (std::size_t k = 0; k < Rk; ++k) {
150 const std::size_t r = retained[k];
151 if (M == 0)
continue;
153 for (std::size_t i = 1; i < M; ++i)
154 if (L(i, r) > mx) mx = L(i, r);
155 if (mx > zero) scale[k] = mx;
157 for (std::size_t k = 0; k < Rk; ++k)
161 std::vector<std::size_t> ord(Rk);
162 std::iota(ord.begin(), ord.end(),
static_cast<std::size_t
>(0));
163 std::vector<T> zsum(Rk, zero);
164 for (std::size_t k = 0; k < Rk; ++k) zsum[k] = colsum(Z, retained[k], zero) / scale[k];
167 std::stable_sort(ord.begin(), ord.end(),
168 [&](std::size_t a, std::size_t b) { return zsum[a] < zsum[b]; });
170 std::stable_partition(ord.begin(), ord.end(),
171 [&](std::size_t a) { return !(zsum[a] >= atol); });
177 if (!lambda.empty()) res.
lambda.assign(Rk, zero);
178 for (std::size_t k = 0; k < Rk; ++k) {
179 const std::size_t src = retained[ord[k]];
180 const T& sc = scale[ord[k]];
181 for (std::size_t i = 0; i < M; ++i) res.
L(i, k) = L(i, src) / sc;
182 for (std::size_t i = 0; i < D; ++i) res.
Z(i, k) = Z(i, src) / sc;
185 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,...