50constexpr std::array<double, n_classes> class_umin = {2.0, 3.0, 5.0, 10.0};
51constexpr std::array<Index, n_classes> class_nodes = {48, 32, 24, 16};
189 const Eigen::VectorXd& w,
const double* mode_factors) {
191 if (
F < min_batch_for_split) {
194 const double lo = w.minCoeff();
195 const double hi = w.maxCoeff();
196 const double c = 0.5 * (lo + hi);
197 const double h = 0.5 * (hi - lo);
201 const double eta2 = poles.
eta * poles.
eta;
203 const double inv_h = 1.0 / h;
206 std::array<std::array<double, max_nodes>, n_classes> node{};
207 std::array<std::array<double, max_nodes>, n_classes> theta{};
208 for (
int k = 0; k < n_classes; ++k) {
209 const Index n = class_nodes[std::size_t(k)];
210 for (
Index j = 0; j < n; ++j) {
211 theta[std::size_t(k)][std::size_t(j)] =
212 M_PI * (double(j) + 0.5) /
double(n);
213 node[std::size_t(k)][std::size_t(j)] =
214 c + h * std::cos(theta[std::size_t(k)][std::size_t(j)]);
217 std::array<std::array<double, max_nodes>, n_classes> far{};
218 Eigen::VectorXd acc = Eigen::VectorXd::Zero(
F);
219 double* out = acc.data();
220 const double* x = w.data();
222 const double factor = (mode_factors ==
nullptr) ? 1.0 : mode_factors[s];
226 const double omega = poles.
omegas(s);
227 const double* r = residues + B * s;
228 for (
Index m = 0; m < B; ++m) {
229 const double a = factor * r[m] * r[m];
230 const double z = poles.
energies(m) + PoleSign(m, poles.
n_occ) * omega;
231 const double u = std::abs(z - c) * inv_h;
232 if (u < class_umin[0]) {
234 for (
Index f = 0; f <
F; ++f) {
235 out[f] += a * Kernel(x[f] - z, eta2);
239 const int k = (u >= class_umin[3]) ? 3
240 : (u >= class_umin[2]) ? 2
241 : (u >= class_umin[1]) ? 1
243 const Index n = class_nodes[std::size_t(k)];
244 const double* nk = node[std::size_t(k)].data();
245 double* fk = far[std::size_t(k)].data();
247 for (
Index j = 0; j < n; ++j) {
248 fk[j] += a * Kernel(nk[j] - z, eta2);
254 std::array<double, max_nodes> coef{};
255 for (
int k = 0; k < n_classes; ++k) {
256 const Index n = class_nodes[std::size_t(k)];
257 for (
Index j = 0; j < n; ++j) {
259 for (
Index i = 0; i < n; ++i) {
260 sum += far[std::size_t(k)][std::size_t(i)] *
261 std::cos(
double(j) * theta[std::size_t(k)][std::size_t(i)]);
263 coef[std::size_t(j)] += 2.0 * sum / double(n) * ((j == 0) ? 0.5 : 1.0);
266 for (
Index f = 0; f <
F; ++f) {
267 const double u = (x[f] - c) * inv_h;
270 for (
Index j = max_nodes - 1; j >= 1; --j) {
271 const double b0 = 2.0 * u * b1 - b2 + coef[std::size_t(j)];
275 out[f] += u * b1 - b2 + coef[0];
281 const Eigen::MatrixXd& residues_all,
282 const Eigen::VectorXd& w) {
283 const Index P = residues_all.rows();
284 const Index Q = residues_all.cols();
286 const double eta2 = poles.
eta * poles.
eta;
289 std::max<Index>(256,
Index(4e6 /
double(std::max<Index>(Q, 1))));
290 const Index nchunks = (
P + chunk - 1) / chunk;
291 Eigen::MatrixXd T = Eigen::MatrixXd::Zero(Q, Q);
294 Eigen::MatrixXd T_local = Eigen::MatrixXd::Zero(Q, Q);
295 Eigen::MatrixXd weighted;
296#pragma omp for schedule(dynamic)
297 for (
Index ic = 0; ic < nchunks; ++ic) {
298 const Index p0 = ic * chunk;
299 const Index np = std::min(chunk,
P - p0);
301 weighted.resize(np, Q);
302 for (
Index b = 0; b < Q; ++b) {
303 const double wb = w(b);
304 for (
Index i = 0; i < np; ++i) {
305 const Index p = p0 + i;
306 const Index m = p % B;
307 const Index s = p / B;
310 weighted(i, b) = residues_all(p, b) * Kernel(wb - z, eta2);
315 residues_all.middleRows(p0, np).transpose() * weighted;
320 Eigen::MatrixXd result = T + T.transpose();
321 result.diagonal().setZero();