31template <OperationReadyData DataType>
36 for (
auto& span : target_data) {
37 std::ranges::transform(span, span.begin(),
38 [a, b](
double x) { return a * x + b; });
41 auto reconstructed_data = target_data
42 | std::views::transform([](
const auto& span) {
43 return std::vector<double>(span.begin(), span.end());
45 | std::ranges::to<std::vector>();
47 return OperationHelper::reconstruct_from_double<DataType>(reconstructed_data, structure_info);
59template <OperationReadyData DataType>
60DataType
transform_linear(DataType& input,
double a,
double b, std::vector<std::vector<double>>& working_buffer)
64 for (
auto& span : target_data) {
65 std::ranges::transform(span, span.begin(),
66 [a, b](
double x) { return a * x + b; });
69 return OperationHelper::reconstruct_from_double<DataType>(working_buffer, structure_info);
79template <OperationReadyData DataType>
84 for (
auto& span : target_data) {
85 std::ranges::transform(span, span.begin(),
86 [exponent](
double x) { return std::pow(x, exponent); });
89 auto reconstructed_data = target_data
90 | std::views::transform([](
const auto& span) {
91 return std::vector<double>(span.begin(), span.end());
93 | std::ranges::to<std::vector>();
95 return OperationHelper::reconstruct_from_double<DataType>(reconstructed_data, structure_info);
106template <OperationReadyData DataType>
107DataType
transform_power(DataType& input,
double exponent, std::vector<std::vector<double>>& working_buffer)
111 for (
auto& span : target_data) {
112 std::ranges::transform(span, span.begin(),
113 [exponent](
double x) { return std::pow(x, exponent); });
116 return OperationHelper::reconstruct_from_double<DataType>(working_buffer, structure_info);
126template <OperationReadyData DataType>
131 auto polynomial_gen = std::make_shared<Nodes::Generator::Polynomial>(coefficients);
133 for (
auto& span : target_data) {
134 std::ranges::transform(span, span.begin(),
135 [&polynomial_gen](
double x) {
136 return polynomial_gen->process_sample(x);
140 auto reconstructed_data = target_data
141 | std::views::transform([](
const auto& span) {
142 return std::vector<double>(span.begin(), span.end());
144 | std::ranges::to<std::vector>();
146 return OperationHelper::reconstruct_from_double<DataType>(reconstructed_data, structure_info);
157template <OperationReadyData DataType>
158DataType
transform_polynomial(DataType& input,
const std::vector<double>& coefficients, std::vector<std::vector<double>>& working_buffer)
162 auto polynomial_gen = std::make_shared<Nodes::Generator::Polynomial>(coefficients);
164 for (
auto& span : target_data) {
165 std::ranges::transform(span, span.begin(),
166 [&polynomial_gen](
double x) {
167 return polynomial_gen->process_sample(x);
171 return OperationHelper::reconstruct_from_double<DataType>(working_buffer, structure_info);
183template <OperationReadyData DataType>
188 for (
auto& span : target_data) {
189 std::ranges::transform(span, span.begin(),
190 [a, b, base](
double x) {
191 if (base == std::numbers::e) {
192 return a * std::exp(b * x);
194 return a * std::pow(base, b * x);
198 auto reconstructed_data = target_data
199 | std::views::transform([](
const auto& span) {
200 return std::vector<double>(span.begin(), span.end());
202 | std::ranges::to<std::vector>();
204 return OperationHelper::reconstruct_from_double<DataType>(reconstructed_data, structure_info);
217template <OperationReadyData DataType>
218DataType
transform_exponential(DataType& input,
double a,
double b, std::vector<std::vector<double>>& working_buffer,
double base = std::numbers::e)
220 auto [target_data, structure_info] = OperationHelper::setup_operation_buffer(input, working_buffer);
222 for (
auto& span : target_data) {
223 std::ranges::transform(span, span.begin(),
224 [a, b, base](
double x) {
225 if (base == std::numbers::e) {
226 return a * std::exp(b * x);
228 return a * std::pow(base, b * x);
232 return OperationHelper::reconstruct_from_double<DataType>(working_buffer, structure_info);
245template <OperationReadyData DataType>
248 auto [target_data, structure_info] = OperationHelper::extract_structured_double(input);
250 double log_base_factor = (base == std::numbers::e) ? 1.0 : (1.0 / std::log(base));
252 for (
auto& span : target_data) {
253 std::ranges::transform(span, span.begin(),
254 [a, b, c, log_base_factor](
double x) {
255 double arg = b * x + c;
258 return a * std::log(arg) * log_base_factor;
262 auto reconstructed_data = target_data
263 | std::views::transform([](
const auto& span) {
264 return std::vector<double>(span.begin(), span.end());
266 | std::ranges::to<std::vector>();
268 return OperationHelper::reconstruct_from_double<DataType>(reconstructed_data, structure_info);
281template <OperationReadyData DataType>
282DataType
transform_logarithmic(DataType& input,
double a,
double b,
double c, std::vector<std::vector<double>>& working_buffer,
double base = std::numbers::e)
284 auto [target_data, structure_info] = OperationHelper::setup_operation_buffer(input, working_buffer);
286 double log_base_factor = (base == std::numbers::e) ? 1.0 : (1.0 / std::log(base));
288 for (
auto& span : target_data) {
289 std::ranges::transform(span, span.begin(),
290 [a, b, c, log_base_factor](
double x) {
291 double arg = b * x + c;
294 return a * std::log(arg) * log_base_factor;
298 return OperationHelper::reconstruct_from_double<DataType>(working_buffer, structure_info);
312template <OperationReadyData DataType,
typename TrigFunc>
313 requires std::invocable<TrigFunc, double>
316 double frequency = 1.0,
317 double amplitude = 1.0,
320 auto [target_data, structure_info] = OperationHelper::extract_structured_double(input);
322 for (
auto& span : target_data) {
323 std::ranges::transform(span, span.begin(),
324 [trig_func, frequency, amplitude, phase](
double x) {
325 return amplitude * trig_func(frequency * x + phase);
329 auto reconstructed_data = target_data
330 | std::views::transform([](
const auto& span) {
331 return std::vector<double>(span.begin(), span.end());
333 | std::ranges::to<std::vector>();
335 return OperationHelper::reconstruct_from_double<DataType>(reconstructed_data, structure_info);
350template <OperationReadyData DataType,
typename TrigFunc>
351 requires std::invocable<TrigFunc, double>
357 std::vector<std::vector<double>>& working_buffer)
359 auto [target_data, structure_info] = OperationHelper::setup_operation_buffer(input, working_buffer);
361 for (
auto& span : target_data) {
362 std::ranges::transform(span, span.begin(),
363 [trig_func, frequency, amplitude, phase](
double x) {
364 return amplitude * trig_func(frequency * x + phase);
368 return OperationHelper::reconstruct_from_double<DataType>(working_buffer, structure_info);
378template <OperationReadyData DataType>
381 auto [target_data, structure_info] = OperationHelper::extract_structured_double(input);
383 const double levels = std::pow(2.0, bits) - 1.0;
385 for (
auto& span : target_data) {
386 std::ranges::transform(span, span.begin(),
388 double clamped = std::clamp(x, -1.0, 1.0);
389 return std::round(clamped * levels) / levels;
393 auto reconstructed_data = target_data
394 | std::views::transform([](
const auto& span) {
395 return std::vector<double>(span.begin(), span.end());
397 | std::ranges::to<std::vector>();
399 return OperationHelper::reconstruct_from_double<DataType>(reconstructed_data, structure_info);
410template <OperationReadyData DataType>
411DataType
transform_quantize(DataType& input, uint8_t bits, std::vector<std::vector<double>>& working_buffer)
413 auto [target_data, structure_info] = OperationHelper::setup_operation_buffer(input, working_buffer);
415 const double levels = std::pow(2.0, bits) - 1.0;
417 for (
auto& span : target_data) {
418 std::ranges::transform(span, span.begin(),
420 double clamped = std::clamp(x, -1.0, 1.0);
421 return std::round(clamped * levels) / levels;
425 return OperationHelper::reconstruct_from_double<DataType>(working_buffer, structure_info);
436template <OperationReadyData DataType>
439 auto [target_data, structure_info] = OperationHelper::extract_structured_double(input);
441 for (
auto& span : target_data) {
442 std::ranges::transform(span, span.begin(),
443 [min_val, max_val](
double x) { return std::clamp(x, min_val, max_val); });
446 auto reconstructed_data = target_data
447 | std::views::transform([](
const auto& span) {
448 return std::vector<double>(span.begin(), span.end());
450 | std::ranges::to<std::vector>();
452 return OperationHelper::reconstruct_from_double<DataType>(reconstructed_data, structure_info);
464template <OperationReadyData DataType>
465DataType
transform_clamp(DataType& input,
double min_val,
double max_val, std::vector<std::vector<double>>& working_buffer)
467 auto [target_data, structure_info] = OperationHelper::setup_operation_buffer(input, working_buffer);
469 for (
auto& span : target_data) {
470 std::ranges::transform(span, span.begin(),
471 [min_val, max_val](
double x) { return std::clamp(x, min_val, max_val); });
474 return OperationHelper::reconstruct_from_double<DataType>(working_buffer, structure_info);
484template <OperationReadyData DataType>
487 auto [target_data, structure_info] = OperationHelper::extract_structured_double(input);
489 for (
auto& span : target_data) {
490 std::ranges::transform(span, span.begin(),
491 [wrap_range](
double x) {
492 return x - wrap_range * std::floor(x / wrap_range);
496 auto reconstructed_data = target_data
497 | std::views::transform([](
const auto& span) {
498 return std::vector<double>(span.begin(), span.end());
500 | std::ranges::to<std::vector>();
502 return OperationHelper::reconstruct_from_double<DataType>(reconstructed_data, structure_info);
513template <OperationReadyData DataType>
514DataType
transform_wrap(DataType& input,
double wrap_range, std::vector<std::vector<double>>& working_buffer)
516 auto [target_data, structure_info] = OperationHelper::setup_operation_buffer(input, working_buffer);
518 for (
auto& span : target_data) {
519 std::ranges::transform(span, span.begin(),
520 [wrap_range](
double x) {
521 return x - wrap_range * std::floor(x / wrap_range);
525 return OperationHelper::reconstruct_from_double<DataType>(working_buffer, structure_info);
535template <OperationReadyData DataType>
536DataType
transform_normalize(DataType& input,
const std::pair<double, double>& target_range = { -1.0, 1.0 })
538 auto [target_data, structure_info] = OperationHelper::extract_structured_double(input);
540 for (
auto& span : target_data) {
541 auto [min_it, max_it] = std::ranges::minmax_element(span);
542 double current_min = *min_it;
543 double current_max = *max_it;
545 if (current_max == current_min)
548 double current_range = current_max - current_min;
549 double target_min = target_range.first;
550 double target_max = target_range.second;
551 double target_span = target_max - target_min;
553 std::ranges::transform(span, span.begin(),
554 [current_min, current_range, target_span, target_min](
double x) {
555 return ((x - current_min) / current_range) * target_span + target_min;
559 auto reconstructed_data = target_data
560 | std::views::transform([](
const auto& span) {
561 return std::vector<double>(span.begin(), span.end());
563 | std::ranges::to<std::vector>();
565 return OperationHelper::reconstruct_from_double<DataType>(reconstructed_data, structure_info);
576template <OperationReadyData DataType>
577DataType
transform_normalize(DataType& input,
const std::pair<double, double>& target_range, std::vector<std::vector<double>>& working_buffer)
579 auto [target_data, structure_info] = OperationHelper::setup_operation_buffer(input, working_buffer);
581 for (
auto& span : target_data) {
582 auto [min_it, max_it] = std::ranges::minmax_element(span);
583 double current_min = *min_it;
584 double current_max = *max_it;
586 if (current_max == current_min)
589 double current_range = current_max - current_min;
590 double target_min = target_range.first;
591 double target_max = target_range.second;
592 double target_span = target_max - target_min;
594 std::ranges::transform(span, span.begin(),
595 [current_min, current_range, target_span, target_min](
double x) {
596 return ((x - current_min) / current_range) * target_span + target_min;
600 return OperationHelper::reconstruct_from_double<DataType>(working_buffer, structure_info);
603inline void interpolate(std::span<double> input, std::vector<double>& output, uint32_t target_size)
605 auto indices = std::views::iota(
size_t { 0 }, target_size);
607 std::ranges::transform(indices, output.begin(),
608 [&input, target_size](
size_t i) {
609 double pos = static_cast<double>(i) * double(input.size() - 1) / (target_size - 1);
610 auto idx = static_cast<size_t>(pos);
611 double frac = pos - (double)idx;
613 if (idx + 1 < input.size()) {
614 return input[idx] * (1.0 - frac) + input[idx + 1] * frac;
628template <OperationReadyData DataType>
631 auto [data_span, structure_info] = OperationHelper::extract_structured_double(input);
633 std::vector<std::vector<double>> interpolated;
634 for (
auto& span : data_span) {
635 if (target_size != span.size()) {
636 std::vector<double> sub_data(target_size);
637 interpolate(span, std::ref(sub_data), target_size);
638 interpolated.push_back(std::move(sub_data));
640 interpolated.emplace_back(span.begin(), span.end());
644 input = OperationHelper::reconstruct_from_double<DataType>(interpolated, structure_info);
656template <OperationReadyData DataType>
657DataType
interpolate_linear(DataType& input,
size_t target_size, std::vector<std::vector<double>>& working_buffer)
659 auto [target_data, structure_info] = OperationHelper::setup_operation_buffer(input, working_buffer);
661 for (
size_t i = 0; i < target_data.size(); i++) {
662 if (target_size != target_data[i].size()) {
663 working_buffer[i].resize(target_size);
664 interpolate(target_data[i], working_buffer[i], target_size);
668 return OperationHelper::reconstruct_from_double<DataType>(working_buffer, structure_info);
678template <OperationReadyData DataType>
681 auto [target_data, structure_info] = OperationHelper::extract_structured_double(input);
683 bool needs_resize =
false;
684 for (
const auto& span : target_data) {
685 if (target_size != span.size()) {
695 std::vector<std::vector<double>> result(target_data.size());
697 for (
size_t ch = 0; ch < target_data.size(); ++ch) {
698 const auto& data_span = target_data[ch];
699 auto& interpolated = result[ch];
700 interpolated.resize(target_size);
702 if (target_size <= 1 || data_span.size() <= 1) {
703 std::fill(interpolated.begin(), interpolated.end(),
704 data_span.empty() ? 0.0 : data_span[0]);
708 auto indices = std::views::iota(
size_t { 0 }, target_size);
709 std::ranges::transform(indices, interpolated.begin(),
710 [&data_span, target_size](
size_t i) {
711 double pos = static_cast<double>(i) * (data_span.size() - 1) / (target_size - 1);
712 int idx = static_cast<int>(pos);
713 double frac = pos - idx;
715 auto get_sample = [&data_span](int i) {
716 return data_span[std::clamp(i, 0, static_cast<int>(data_span.size() - 1))];
719 double y0 = get_sample(idx - 1);
720 double y1 = get_sample(idx);
721 double y2 = get_sample(idx + 1);
722 double y3 = get_sample(idx + 2);
724 double a = -0.5 * y0 + 1.5 * y1 - 1.5 * y2 + 0.5 * y3;
725 double b = y0 - 2.5 * y1 + 2.0 * y2 - 0.5 * y3;
726 double c = -0.5 * y0 + 0.5 * y2;
729 return ((a * frac + b) * frac + c) * frac + d;
733 return OperationHelper::reconstruct_from_double<DataType>(result, structure_info);
744template <OperationReadyData DataType>
745DataType
interpolate_cubic(DataType& input,
size_t target_size, std::vector<std::vector<double>>& working_buffer)
747 auto [target_data, structure_info] = OperationHelper::setup_operation_buffer(input, working_buffer);
749 bool needs_resize =
false;
750 for (
const auto& span : target_data) {
751 if (target_size != span.size()) {
758 return OperationHelper::reconstruct_from_double<DataType>(working_buffer, structure_info);
761 for (
size_t ch = 0; ch < target_data.size(); ++ch) {
762 const auto& data_span = target_data[ch];
763 working_buffer[ch].resize(target_size);
765 if (target_size <= 1 || data_span.size() <= 1) {
766 std::fill(working_buffer[ch].begin(), working_buffer[ch].end(),
767 data_span.empty() ? 0.0 : data_span[0]);
771 auto indices = std::views::iota(
size_t { 0 }, target_size);
772 std::ranges::transform(indices, working_buffer[ch].begin(),
773 [&data_span, target_size](
size_t i) {
774 double pos =
static_cast<double>(i) * (data_span.size() - 1) / (target_size - 1);
775 int idx =
static_cast<int>(pos);
776 double frac = pos - idx;
778 auto get_sample = [&data_span](
int i) {
779 return data_span[std::clamp(i, 0,
static_cast<int>(data_span.size() - 1))];
782 double y0 = get_sample(idx - 1);
783 double y1 = get_sample(idx);
784 double y2 = get_sample(idx + 1);
785 double y3 = get_sample(idx + 2);
787 double a = -0.5 * y0 + 1.5 * y1 - 1.5 * y2 + 0.5 * y3;
788 double b = y0 - 2.5 * y1 + 2.0 * y2 - 0.5 * y3;
789 double c = -0.5 * y0 + 0.5 * y2;
792 return ((a * frac + b) * frac + c) * frac + d;
796 return OperationHelper::reconstruct_from_double<DataType>(working_buffer, structure_info);
static std::tuple< std::vector< std::span< double > >, DataStructureInfo > extract_structured_double(T &compute_data)
Extract structured double data from IO container or direct ComputeData with automatic container handl...
static auto setup_operation_buffer(T &input, std::vector< std::vector< double > > &working_buffer)
Setup operation buffer from IO or ComputeData type.
void interpolate(std::span< double > input, std::vector< double > &output, uint32_t target_size)
DataType transform_wrap(DataType &input, double wrap_range)
Wrap transformation (modulo operation) using C++20 ranges (IN-PLACE)
DataType interpolate_cubic(DataType &input, size_t target_size)
Cubic interpolation between data points using C++20 ranges (IN-PLACE)
DataType interpolate_linear(DataType &input, size_t target_size)
Linear interpolation between data points using C++20 ranges (IN-PLACE)
DataType transform_polynomial(DataType &input, const std::vector< double > &coefficients)
Polynomial transformation using existing Generator::Polynomial (IN-PLACE)
DataType transform_linear(DataType &input, double a, double b)
Linear transformation y = ax + b using C++20 ranges (IN-PLACE)
DataType transform_logarithmic(DataType &input, double a, double b, double c=1.0, double base=std::numbers::e)
Logarithmic transformation y = a * log_base(b * x + c) (IN-PLACE)
DataType transform_normalize(DataType &input, const std::pair< double, double > &target_range={ -1.0, 1.0 })
Normalize transformation using existing infrastructure (IN-PLACE)
DataType transform_exponential(DataType &input, double a, double b, double base=std::numbers::e)
Exponential transformation y = a * base^(b * x) (IN-PLACE)
DataType transform_power(DataType &input, double exponent)
Power transformation y = x^exponent (IN-PLACE)
DataType transform_quantize(DataType &input, uint8_t bits)
Quantization transformation (bit reduction) using C++20 features (IN-PLACE)
DataType transform_clamp(DataType &input, double min_val, double max_val)
Clamp transformation using C++20 ranges (IN-PLACE)
DataType transform_trigonometric(DataType &input, TrigFunc trig_func, double frequency=1.0, double amplitude=1.0, double phase=0.0)
Trigonometric transformation using specified function (IN-PLACE)