Parallel Find
Taskflow provides template functions for constructing tasks to perform parallel iterations over ranges of items.
Include the Header
You need to include the header file, taskflow/algorithm/find.hpp
, for using parallel-find algorithms.
#include <taskflow/algorithm/find.hpp>
What is a Find Algorithm?
A find algorithm allows you to find an element in a range [first, last)
that satisfies a specific criteria. The algorithm returns an iterator to the first found element in the range or returns last
if there is no such iterator. Taskflow provides the following parallel-find algorithms:
- tf::Taskflow::find_if(B first, E last, T& result, UOP predicate, P&& part)
- tf::Taskflow::find_if_not(B first, E last, T& result, UOP predicate, P&& part)
- tf::Taskflow::min_element(B first, E last, T& result, C comp, P&& part)
- tf::Taskflow::max_element(B first, E last, T& result, C comp, P&& part)
Create a Parallel Find-If Task
tf::[first, last)
that makes the given predicate return true
. It resembles a parallel implementation of the following loop:
template<typename InputIt, typename UnaryPredicate> InputIt find_if(InputIt first, InputIt last, UnaryPredicate predicate) { for(; first != last; ++first) { if(predicate(*first)) { return first; } } return last; }
The example below creates a task to find the element that is equal to 22 from an input range of 10 elements. The result will be stored in the forth argument passed by reference:
std::vector<int> input = {1, 9, 22, 3, -6, 13, 12, 0, 9, 11}; std::vector<int>::iterator result; taskflow.find_if( input.begin(), input.end(), [](int i){ return i == 22; }, result ); executor.run(taskflow); assert(*result == 22);
Capture Iterators by Reference
You can pass iterators by reference using std::
std::vector<int> input; std::vector<int>::iterator result, first, last; // task to set up the range iterators tf::Task init = taskflow.emplace([&](){ input = {1, 9, 22, 3, -6, 13, 12, 0, 9, 11}; first = input.begin(), last = input.end(); }); // task to perform parallel find tf::Task task = taskflow.find_if( std::ref(first), std::ref(last), result, [](int i){ return i == 22; } ); init.precede(task); executor.run(taskflow); assert(*result == 22);
In the above example, when init
finishes, input
has been initialized to 10 elements with first
and last
pointing to the data range of input
. The find-if task will then work on this initialized range as a result of passing iterators by reference.
Create a Parallel Find-If-Not Task
tf::[first, last)
that makes the given predicate return false
. It resembles a parallel implementation of the following loop:
template<typename InputIt, typename UnaryPredicate> InputIt find_if(InputIt first, InputIt last, UnaryPredicate predicate) { for(; first != last; ++first) { if(!predicate(*first)) { return first; } } return last; }
The example below creates a task to find the element that is NOT equal to 22 from an input range of 10 elements. The result will be stored in the forth argument passed by reference:
std::vector<int> input = {1, 1, 22, 1, 1, 1, 1, 1, 1, 1}; std::vector<int>::iterator result; taskflow.find_if_not( input.begin(), input.end(), result, [](int i){ return i == 1; } ); executor.run(taskflow); assert(*result == 22);
Similar to Capture Iterators by Reference, iterators of tf::
Find the Smallest and the Largest Elements
tf::[first, last)
using the given comparison function object. The example below finds the smallest element, i.e., -1, from an input range of 10 elements and stores the iterator to that smallest element in result:
std::vector<int> input = {1, 1, 1, 1, 1, -1, 1, 1, 1, 1}; std::vector<int>::iterator result; taskflow.min_element( input.begin(), input.end(), std::less<int>(), result ); executor.run(taskflow).wait(); assert(*result == -1);
Similarly, tf::[first, last)
using the given comparison function object. The example below finds the largest element, i.e., 2, from an input range of 10 elements and stores the iterator to that largest element in result:
std::vector<int> input = {1, 1, 1, 1, 1, 2, 1, 1, 1, 1}; std::vector<int>::iterator result; taskflow.max_element( input.begin(), input.end(), std::less<int>(), result ); executor.run(taskflow).wait(); assert(*result == 2);
Configure a Partitioner
You can configure a partitioner for parallel-find tasks (tf::
std::vector<int> vec(1024, -1); std::vector<int>::iterator result; tf::ExecutionPolicy<tf::StaticPartitioner> static_partitioner; tf::ExecutionPolicy<tf::GuidedPartitioner> guided_partitioner; // create a parallel-find task with a static partitioner taskflow.find_if( vec.begin(), vec.end(), result, [&](int i) { return i == -1; }, static_partitioner ); // create a parallel-find task with a guided partitioner taskflow.find_if( vec.begin(), vec.end(), result, [&](int i) { return i == -1; }, guided_partitioner );