Taskflow Algorithms » Parallel Transforms | Taskflow QuickStart

# Taskflow Algorithms » Parallel Transforms

Taskflow provides template functions for constructing tasks to perform parallel transforms over ranges of items.

## Include the Header

You need to include the header file, `taskflow/algorithm/transform.hpp`, for creating a parallel-transform task.

    #include <taskflow/algorithm/transform.hpp>

## Create a Unary Parallel-Transform Task

Parallel-transform transforms a range of items, possibly with a different type for the transformed data, and stores the result in another range. The task created by tf::Taskflow::transform(B first1, E last1, O d_first, C c, P&& part) is equivalent to a parallel execution of the following loop:

    while (first1 != last1) {
      *d_first++ = c(*first1++);
    }

tf::Taskflow::transform simultaneously applies the callable `c` to the object obtained by dereferencing every iterator in the range `[first1, last1)` and stores the result in another range beginning at `d_first`. It is user's responsibility for ensuring the range is valid within the execution of the parallel-transform task.

    std::vector<int> src = {1, 2, 3, 4, 5};
    std::vector<int> tgt(src.size());
    taskflow.transform(src.begin(), src.end(), tgt.begin(), [](int i){
      std::cout << "transforming item " << i << " to " << i + 1 << '\n';
      return i + 1;
    });

## Capture Iterators by Reference

You can pass iterators by reference using std::ref to marshal parameter update between dependent tasks. This is especially useful when the range is unknown at the time of creating a parallel-transform task, but needs initialization from another task.

    std::vector<int> src, tgt;
    std::vector<int>::iterator first, last, d_first;

    tf::Task init = taskflow.emplace([&](){
      src.resize(1000);
      tgt.resize(1000);
      first   = src.begin();
      last    = src.end();
      d_first = tgt.begin();
    });

    tf::Task transform = taskflow.transform(
      std::ref(first), std::ref(last), std::ref(d_first),
      [&](int i) {
        std::cout << "transforming item " << i << " to " << i + 1 << '\n';
        return i+1;
      }
    );

    init.precede(transform);

When `init` finishes, the parallel-transform task `transform` will see `first` pointing to the beginning of `src` and `last` pointing to the end of `src`. Then, it simultaneously transforms these 1000 items by adding one to each element and stores the result in another range starting at `d_first`.

## Create a Binary Parallel-Transform Task

You can use the overload, tf::Taskflow::transform(B1 first1, E1 last1, B2 first2, O d_first, C c, P&& part), to perform parallel transforms on two source ranges pointed by `first1` and `first2` using the binary operator `c` and store the result in another range pointed by `d_first`. This method is equivalent to the parallel execution of the following loop:

    while (first1 != last1) {
      *d_first++ = c(*first1++, *first2++);
    }

The following example creates a parallel-transform task that adds two ranges of elements one by one and stores the result in a target range:

    std::vector<int> src1 = {1, 2, 3, 4, 5};
    std::vector<int> src2 = {5, 4, 3, 2, 1};
    std::vector<int> tgt(src1.size());
    taskflow.transform(
      src1.begin(), src1.end(), src2.begin(), tgt.begin(),
      [](int i, int j){
        return i + j;
      }
    );

## Configure a Partitioner

You can configure a partitioner for parallel-transform tasks to run with different scheduling methods, such as guided partitioning, dynamic partitioning, and static partitioning. The following example creates two parallel-transform tasks using two different partitioners, one with the static partitioning algorithm and another one with the guided partitioning algorithm:

    tf::StaticPartitioner static_partitioner;
    tf::GuidedPartitioner guided_partitioner;

    std::vector<int> src1 = {1, 2, 3, 4, 5};
    std::vector<int> src2 = {5, 4, 3, 2, 1};
    std::vector<int> tgt1(src1.size());
    std::vector<int> tgt2(src2.size());

    // create a parallel-transform task with static execution partitioner
    taskflow.transform(
      src1.begin(), src1.end(), src2.begin(), tgt1.begin(),
      [](int i, int j){
        return i + j;
      },
      static_partitioner
    );

    // create a parallel-transform task with guided execution partitioner
    taskflow.transform(
      src1.begin(), src1.end(), src2.begin(), tgt2.begin(),
      [](int i, int j){
        return i + j;
      },
      guided_partitioner
    );

#### Attention

By default, parallel-transform tasks use tf::DefaultPartitioner if no partitioner is specified.

Tab / T to search, Esc to close
…

Search for symbols, directories, files, pages or modules. You can omit any prefix from the symbol or file path; adding a `:` or `/` suffix lists all members of given symbol or directory.

Use ↓ / ↑ to navigate through the list, Enter to go. Tab autocompletes common prefix, you can copy a link to the result using ⌘ L while ⌘ M produces a Markdown link.

Sorry, nothing was found.