#include "wayy_db/ops/window.hpp" #include #include #include namespace wayy_db::ops { // Moving average std::vector mavg(const ColumnView& col, size_t window) { if (col.empty() || window == 0) return {}; std::vector result(col.size()); double sum = 0.0; for (size_t i = 0; i < col.size(); ++i) { sum += col[i]; if (i >= window) { sum -= col[i - window]; result[i] = sum / static_cast(window); } else { result[i] = sum / static_cast(i + 1); } } return result; } std::vector mavg(const ColumnView& col, size_t window) { if (col.empty() || window == 0) return {}; std::vector result(col.size()); int64_t sum = 0; for (size_t i = 0; i < col.size(); ++i) { sum += col[i]; if (i >= window) { sum -= col[i - window]; result[i] = static_cast(sum) / static_cast(window); } else { result[i] = static_cast(sum) / static_cast(i + 1); } } return result; } // Moving sum std::vector msum(const ColumnView& col, size_t window) { if (col.empty() || window == 0) return {}; std::vector result(col.size()); double sum = 0.0; for (size_t i = 0; i < col.size(); ++i) { sum += col[i]; if (i >= window) { sum -= col[i - window]; } result[i] = sum; } return result; } std::vector msum(const ColumnView& col, size_t window) { if (col.empty() || window == 0) return {}; std::vector result(col.size()); int64_t sum = 0; for (size_t i = 0; i < col.size(); ++i) { sum += col[i]; if (i >= window) { sum -= col[i - window]; } result[i] = sum; } return result; } // Moving standard deviation (Welford's online algorithm) std::vector mstd(const ColumnView& col, size_t window) { if (col.empty() || window == 0) return {}; std::vector result(col.size()); for (size_t i = 0; i < col.size(); ++i) { size_t start = (i >= window) ? i - window + 1 : 0; size_t count = i - start + 1; double mean = 0.0; double m2 = 0.0; size_t n = 0; for (size_t j = start; j <= i; ++j) { ++n; double delta = col[j] - mean; mean += delta / static_cast(n); double delta2 = col[j] - mean; m2 += delta * delta2; } result[i] = (n > 1) ? std::sqrt(m2 / static_cast(n)) : 0.0; } return result; } std::vector mstd(const ColumnView& col, size_t window) { if (col.empty() || window == 0) return {}; std::vector result(col.size()); for (size_t i = 0; i < col.size(); ++i) { size_t start = (i >= window) ? i - window + 1 : 0; double mean = 0.0; double m2 = 0.0; size_t n = 0; for (size_t j = start; j <= i; ++j) { ++n; double val = static_cast(col[j]); double delta = val - mean; mean += delta / static_cast(n); double delta2 = val - mean; m2 += delta * delta2; } result[i] = (n > 1) ? std::sqrt(m2 / static_cast(n)) : 0.0; } return result; } // Moving min/max using monotonic deque for O(n) complexity template std::vector monotonic_window(const ColumnView& col, size_t window, Compare cmp) { if (col.empty() || window == 0) return {}; std::vector result(col.size()); std::deque dq; // Indices for (size_t i = 0; i < col.size(); ++i) { // Remove elements outside window while (!dq.empty() && dq.front() + window <= i) { dq.pop_front(); } // Remove elements that won't be min/max while (!dq.empty() && cmp(col[i], col[dq.back()])) { dq.pop_back(); } dq.push_back(i); result[i] = col[dq.front()]; } return result; } std::vector mmin(const ColumnView& col, size_t window) { return monotonic_window(col, window, std::less{}); } std::vector mmin(const ColumnView& col, size_t window) { return monotonic_window(col, window, std::less{}); } std::vector mmax(const ColumnView& col, size_t window) { return monotonic_window(col, window, std::greater{}); } std::vector mmax(const ColumnView& col, size_t window) { return monotonic_window(col, window, std::greater{}); } // Exponential moving average std::vector ema(const ColumnView& col, double alpha) { if (col.empty()) return {}; if (alpha <= 0.0 || alpha > 1.0) { throw std::invalid_argument("EMA alpha must be in (0, 1]"); } std::vector result(col.size()); result[0] = col[0]; for (size_t i = 1; i < col.size(); ++i) { result[i] = alpha * col[i] + (1.0 - alpha) * result[i - 1]; } return result; } std::vector ema(const ColumnView& col, double alpha) { if (col.empty()) return {}; if (alpha <= 0.0 || alpha > 1.0) { throw std::invalid_argument("EMA alpha must be in (0, 1]"); } std::vector result(col.size()); result[0] = static_cast(col[0]); for (size_t i = 1; i < col.size(); ++i) { result[i] = alpha * static_cast(col[i]) + (1.0 - alpha) * result[i - 1]; } return result; } std::vector ema_span(const ColumnView& col, size_t span) { double alpha = 2.0 / (static_cast(span) + 1.0); return ema(col, alpha); } // Diff std::vector diff(const ColumnView& col, size_t periods) { if (col.empty() || periods >= col.size()) return std::vector(col.size(), 0.0); std::vector result(col.size()); for (size_t i = 0; i < periods; ++i) { result[i] = std::numeric_limits::quiet_NaN(); } for (size_t i = periods; i < col.size(); ++i) { result[i] = col[i] - col[i - periods]; } return result; } std::vector diff(const ColumnView& col, size_t periods) { if (col.empty() || periods >= col.size()) return std::vector(col.size(), 0); std::vector result(col.size(), 0); for (size_t i = periods; i < col.size(); ++i) { result[i] = col[i] - col[i - periods]; } return result; } // Percent change std::vector pct_change(const ColumnView& col, size_t periods) { if (col.empty() || periods >= col.size()) { return std::vector(col.size(), std::numeric_limits::quiet_NaN()); } std::vector result(col.size()); for (size_t i = 0; i < periods; ++i) { result[i] = std::numeric_limits::quiet_NaN(); } for (size_t i = periods; i < col.size(); ++i) { if (col[i - periods] != 0.0) { result[i] = (col[i] - col[i - periods]) / col[i - periods]; } else { result[i] = std::numeric_limits::quiet_NaN(); } } return result; } // Shift std::vector shift(const ColumnView& col, int64_t n) { if (col.empty()) return {}; std::vector result(col.size(), std::numeric_limits::quiet_NaN()); if (n >= 0) { size_t offset = static_cast(n); for (size_t i = offset; i < col.size(); ++i) { result[i] = col[i - offset]; } } else { size_t offset = static_cast(-n); for (size_t i = 0; i + offset < col.size(); ++i) { result[i] = col[i + offset]; } } return result; } std::vector shift(const ColumnView& col, int64_t n) { if (col.empty()) return {}; std::vector result(col.size(), 0); if (n >= 0) { size_t offset = static_cast(n); for (size_t i = offset; i < col.size(); ++i) { result[i] = col[i - offset]; } } else { size_t offset = static_cast(-n); for (size_t i = 0; i + offset < col.size(); ++i) { result[i] = col[i + offset]; } } return result; } } // namespace wayy_db::ops