CodeNebula
C++17stladvanced

std::transform_inclusive_scan

C++17 · Practical Modern · Compiler flag: -std=c++17

Explanation

Applies a unary transformation to each element and then computes an inclusive prefix sum of the transformed values. Supports parallel execution for large datasets.

Real-World Scenario

Compute cumulative squared distances for a GPS trajectory analysis tool.

Quick Snippet

snippet.cpp
#include <numeric>
#include <vector>

std::vector<int> values = {1, 2, 3, 4};
std::vector<int> result(values.size());
std::transform_inclusive_scan(values.begin(), values.end(), result.begin(),
    std::plus<>{}, [](int x) { return x * x; });
// result: {1, 5, 14, 30}  (1, 1+4, 1+4+9, 1+4+9+16)

Full Example

transform_inclusive_scan.cpp
// CodeNebula - C++17 Example: std::transform_inclusive_scan
// Compile: g++ -std=c++17 -Wall -Wextra -o example transform_inclusive_scan.cpp

// Demonstrates std::transform_inclusive_scan, which fuses a unary transform
// with an inclusive prefix scan. Each element is first transformed, then
// accumulated with previous results. More efficient than separate
// transform + inclusive_scan calls.

#include <iostream>
#include <numeric>
#include <vector>
#include <functional>
#include <string>
#include <cmath>

void print(const std::string& label, const std::vector<int>& v) {
    std::cout << "  " << label << ": ";
    for (int x : v) std::cout << x << " ";
    std::cout << std::endl;
}

void print_d(const std::string& label, const std::vector<double>& v) {
    std::cout << "  " << label << ": ";
    for (double x : v) std::cout << x << " ";
    std::cout << std::endl;
}

int main()
{
    // ------------------------------------------------------------------
    // 1. Running sum of squares
    // ------------------------------------------------------------------
    std::cout << "=== running sum of squares ===" << std::endl;
    std::vector<int> v = {1, 2, 3, 4, 5};
    std::vector<int> result(v.size());

    // For each i: result[i] = v[0]^2 + v[1]^2 + ... + v[i]^2
    std::transform_inclusive_scan(
        v.begin(), v.end(), result.begin(),
        std::plus<>{},                  // reduce: sum
        [](int x) { return x * x; }    // transform: square
    );

    print("input  ", v);
    print("sq_scan", result);
    // {1, 1+4, 1+4+9, 1+4+9+16, 1+4+9+16+25} = {1, 5, 14, 30, 55}

    // ------------------------------------------------------------------
    // 2. Running sum of absolute values
    // ------------------------------------------------------------------
    std::cout << "\n=== running sum of absolute values ===" << std::endl;
    std::vector<int> mixed = {3, -1, 4, -1, 5, -9};
    std::vector<int> abs_scan(mixed.size());

    std::transform_inclusive_scan(
        mixed.begin(), mixed.end(), abs_scan.begin(),
        std::plus<>{},
        [](int x) { return std::abs(x); }
    );

    print("input   ", mixed);
    print("abs_scan", abs_scan);
    // {3, 3+1, 3+1+4, 3+1+4+1, 3+1+4+1+5, 3+1+4+1+5+9} = {3, 4, 8, 9, 14, 23}

    // ------------------------------------------------------------------
    // 3. With initial value
    // ------------------------------------------------------------------
    std::cout << "\n=== with initial value ===" << std::endl;
    std::vector<int> data = {1, 2, 3};
    std::vector<int> with_init(data.size());

    std::transform_inclusive_scan(
        data.begin(), data.end(), with_init.begin(),
        std::plus<>{},
        [](int x) { return x * 10; },  // transform: multiply by 10
        100                              // initial value
    );

    print("input    ", data);
    print("scan+100 ", with_init);
    // {100+10, 100+10+20, 100+10+20+30} = {110, 130, 160}

    // ------------------------------------------------------------------
    // 4. Cumulative doubled values
    // ------------------------------------------------------------------
    std::cout << "\n=== cumulative doubled values ===" << std::endl;
    std::vector<int> nums = {5, 3, 8, 2, 7};
    std::vector<int> doubled_scan(nums.size());

    std::transform_inclusive_scan(
        nums.begin(), nums.end(), doubled_scan.begin(),
        std::plus<>{},
        [](int x) { return x * 2; }
    );

    print("input  ", nums);
    print("2x_scan", doubled_scan);
    // {10, 10+6, 10+6+16, 10+6+16+4, 10+6+16+4+14} = {10, 16, 32, 36, 50}

    // ------------------------------------------------------------------
    // 5. Running product of incremented values
    // ------------------------------------------------------------------
    std::cout << "\n=== running product of (x+1) ===" << std::endl;
    std::vector<int> base = {1, 2, 3, 4};
    std::vector<int> prod_scan(base.size());

    std::transform_inclusive_scan(
        base.begin(), base.end(), prod_scan.begin(),
        std::multiplies<>{},
        [](int x) { return x + 1; }
    );

    print("input    ", base);
    print("prod(x+1)", prod_scan);
    // {2, 2*3, 2*3*4, 2*3*4*5} = {2, 6, 24, 120}

    // ------------------------------------------------------------------
    // 6. Practical: running total of discounted prices
    // ------------------------------------------------------------------
    std::cout << "\n=== running total (10% discount) ===" << std::endl;
    std::vector<double> prices = {100.0, 50.0, 75.0, 200.0};
    std::vector<double> running(prices.size());

    std::transform_inclusive_scan(
        prices.begin(), prices.end(), running.begin(),
        std::plus<>{},
        [](double p) { return p * 0.9; }  // 10% discount
    );

    print_d("prices ", prices);
    print_d("running", running);
    // {90, 90+45, 90+45+67.5, 90+45+67.5+180} = {90, 135, 202.5, 382.5}

    return 0;
}

/*
Expected output:

=== running sum of squares ===
  input  : 1 2 3 4 5
  sq_scan: 1 5 14 30 55

=== running sum of absolute values ===
  input   : 3 -1 4 -1 5 -9
  abs_scan: 3 4 8 9 14 23

=== with initial value ===
  input    : 1 2 3
  scan+100 : 110 130 160

=== cumulative doubled values ===
  input  : 5 3 8 2 7
  2x_scan: 10 16 32 36 50

=== running product of (x+1) ===
  input    : 1 2 3 4
  prod(x+1): 2 6 24 120

=== running total (10% discount) ===
  prices : 100 50 75 200
  running: 90 135 202.5 382.5
*/
Run command
g++ -std=c++17 -Wall -Wextra -o example transform_inclusive_scan.cpp