1#ifndef WEIGHTEDLOWESS_WINDOW_HPP
2#define WEIGHTEDLOWESS_WINDOW_HPP
40template<
typename Data_>
41Data_ derive_delta(
size_t num_anchors,
size_t num_points,
const Data_* x) {
42 size_t points_m1 = num_points - 1;
43 std::vector<Data_> diffs(points_m1);
44 for (
size_t i = 0; i < points_m1; ++i) {
45 diffs[i] = x[i + 1] - x[i];
48 std::sort(diffs.begin(), diffs.end());
49 for (
size_t i = 1; i < points_m1; ++i) {
50 diffs[i] += diffs[i-1];
53 Data_ lowest_delta = diffs.back();
54 if (num_anchors > 1) {
55 size_t max_skips = std::min(points_m1, num_anchors - 1);
56 for (
size_t nskips = 0; nskips < max_skips; ++nskips) {
57 Data_ candidate_delta = diffs[points_m1 - nskips - 1] / (num_anchors - nskips);
58 lowest_delta = std::min(candidate_delta, lowest_delta);
74template<
typename Data_>
75void find_anchors(
size_t num_points,
const Data_* x, Data_ delta, std::vector<size_t>& anchors) {
80 size_t points_m1 = num_points - 1;
81 for (
size_t pt = 1; pt < points_m1; ++pt) {
82 if (x[pt] - x[last_pt] > delta) {
83 anchors.push_back(pt);
88 anchors.push_back(points_m1);
92template<
typename Data_>
108template<
typename Data_>
109std::vector<Window<Data_> > find_limits(
110 const std::vector<size_t>& anchors,
114 const Data_* weights,
116 [[maybe_unused]]
int nthreads = 1)
118 const size_t nanchors = anchors.size();
119 std::vector<Window<Data_> > limits(nanchors);
120 auto half_min_width = min_width / 2;
121 auto points_m1 = num_points - 1;
123 parallelize(nthreads, nanchors, [&](
int,
size_t start,
size_t length) {
124 for (
size_t s = start, end = start + length; s < end; ++s) {
125 auto curpt = anchors[s], left = curpt, right = curpt;
126 auto curx = x[curpt];
127 Data_ curw = (weights == NULL ? 1 : weights[curpt]);
131 if (curpt > 0 && curpt < points_m1) {
132 auto next_ldist = curx - x[left - 1];
133 auto next_rdist = x[right + 1] - curx;
135 while (curw < span_weight) {
136 if (next_ldist < next_rdist) {
138 curw += (weights == NULL ? 1 : weights[left]);
142 next_ldist = curx - x[left - 1];
144 }
else if (next_ldist > next_rdist) {
146 curw += (weights == NULL ? 1 : weights[right]);
147 if (right == points_m1) {
150 next_rdist = x[right + 1] - curx;
158 curw += (weights == NULL ? 2 : weights[left] + weights[right]);
159 if (left == 0 || right == points_m1) {
162 next_ldist = curx - x[left - 1];
163 next_rdist = x[right + 1] - curx;
169 while (left > 0 && curw < span_weight) {
171 curw += (weights == NULL ? 1 : weights[left]);
174 while (right < points_m1 && curw < span_weight) {
176 curw += (weights == NULL ? 1 : weights[right]);
180 while (left > 0 && x[left] == x[left - 1]) {
184 while (right < points_m1 && x[right] == x[right + 1]) {
191 auto mdist = std::max(curx - x[left], x[right] - curx);
192 if (mdist < half_min_width) {
193 left = std::lower_bound(x, x + left, curx - half_min_width) - x;
202 right = std::upper_bound(x + right + 1, x + num_points, curx + half_min_width) - x;
205 mdist = std::max(curx - x[left], x[right] - curx);
208 limits[s].left = left;
209 limits[s].right = right;
210 limits[s].distance = mdist;
229template<
typename Data_>
234 std::vector<size_t> anchors;
235 const Data_* freq_weights = NULL;
236 Data_ total_weight = 0;
237 std::vector<internal::Window<Data_> > limits;
262template<
typename Data_>
267 if (!std::is_sorted(x, x + num_points)) {
268 throw std::runtime_error(
"'x' should be sorted");
272 auto& anchors = output.anchors;
274 anchors.resize(num_points);
275 std::iota(anchors.begin(), anchors.end(), 0);
276 }
else if (opt.
delta < 0) {
277 Data_ eff_delta = internal::derive_delta(opt.
anchors, num_points, x);
278 internal::find_anchors(num_points, x, eff_delta, anchors);
280 internal::find_anchors(num_points, x, opt.
delta, anchors);
285 output.total_weight = (output.freq_weights != NULL ? std::accumulate(output.freq_weights, output.freq_weights + num_points,
static_cast<Data_
>(0)) : num_points);
287 output.limits = internal::find_limits(anchors, span_weight, num_points, x, output.freq_weights, opt.
minimum_width, opt.
num_threads);
Namespace for LOWESS functions.
Definition compute.hpp:14
PrecomputedWindows< Data_ > define_windows(size_t num_points, const Data_ *x, const Options< Data_ > &opt)
Definition window.hpp:263
void parallelize(int num_workers, Task_ num_tasks, Run_ run_task_range)
Definition parallelize.hpp:28
Definitions for parallelization.
Options for compute().
Definition Options.hpp:17
Data_ * weights
Definition Options.hpp:78
bool frequency_weights
Definition Options.hpp:85
Data_ delta
Definition Options.hpp:71
Data_ span
Definition Options.hpp:28
Data_ minimum_width
Definition Options.hpp:42
size_t anchors
Definition Options.hpp:55
bool span_as_proportion
Definition Options.hpp:35
int num_threads
Definition Options.hpp:92
Precomputed windows for LOWESS smoothing.
Definition window.hpp:230