stl-algorithms#

group Algorithms

Functions

template<typename Range>
void fill(
Range &&output,
value_type_of_t<Range> val
)#

Fills the given range with the specified value.

This function fills the elements in the range [begin, end) with the specified value. The range must be a logical store-like object, meaning it supports the necessary operations for storing values. The value to be filled is specified by the val parameter.

Example:
// Declare a 3-dimensional logical store and fill it with the value 42.
stl::logical_store<int, 3> store{{100, 200, 300}};
stl::fill(store, 42);
// store's elements are now all 42

Parameters:
  • output – The range to be filled.

  • val – The value to fill the range with.

template<typename Function, typename ...Inputs>
void for_each_zip(
Function &&fn,
Inputs&&... ins
)#

Applies the given function fn with elements of each of the input sequences ins as function arguments.

This function launches a Legate task that applies the provided function fn element-wise to the pack of ranges ins.

Examples:

// Element-wise addition of two logical stores.
stl::logical_store<int, 2> store1 = {{1, 2, 3, 4},  //
                                     {2, 3, 4, 5},
                                     {3, 4, 5, 6}};
stl::logical_store<int, 2> store2 = {{3, 4, 5, 6},  //
                                     {2, 3, 4, 5},
                                     {1, 2, 3, 4}};

// `a` and `b` refer to the elements of `store1` and `store2`.
auto fn = [] LEGATE_HOST_DEVICE(int& a, int& b) { a += b; };
stl::for_each_zip(fn, store1, store2);

// store1 now contains:
// {
//   {4, 6, 8, 10},
//   {4, 6, 8, 10},
//   {4, 6, 8, 10}
// }
// Row-wise operation on two logical stores.
stl::logical_store<int, 2> store1 = {{1, 2, 3, 4},  //
                                     {2, 3, 4, 5},
                                     {3, 4, 5, 6}};
stl::logical_store<int, 2> store2 = {{3, 4, 5, 6},  //
                                     {2, 3, 4, 5},
                                     {1, 2, 3, 4}};

// `a` and `b` are `mdspan` objects referring to the rows of `store1`
// and `store2`.
auto fn = [] LEGATE_HOST_DEVICE(auto&& a, auto&& b) {
  for (std::ptrdiff_t i = 0; i < a.extent(0); ++i) {
    a(i) += b(i);
  }
};
stl::for_each_zip(fn, stl::rows_of(store1), stl::rows_of(store2));

// store1 now contains:
// {
//   {4, 6, 8, 10},
//   {4, 6, 8, 10},
//   {4, 6, 8, 10}
// }

Parameters:
  • fn – The function object to apply with each set of elements.

  • ins – The input sequences to iterate over.

Pre:

  • The number of input sequences must be greater than 0.

  • The input sequences must satisfy the logical_store_like concept.

  • The input sequences must have the same shape.

  • The function object fn must be callable with the same number of arguments as the number of input sequences.

  • The function object fn must be trivially copyable.

template<typename Input, typename Function>
void for_each(
Input &&input,
Function &&fn
)#

Applies the given function to each element in the input range.

This function launches a Legate task that applies the provided function fn to each element in the input range input.

Examples:

// Element-wise addition of two logical stores.
stl::logical_store<int, 2> store = {{1, 2, 3, 4},  //
                                    {2, 3, 4, 5},
                                    {3, 4, 5, 6}};

// `a` refers to the elements of `store`.
auto fn = [] LEGATE_HOST_DEVICE(int& a) { ++a; };
stl::for_each(store, fn);

// store1 now contains:
// {
//   {2, 3, 4, 5},
//   {3, 4, 5, 6}
//   {4, 5, 6, 7}
// }
// Row-wise operation on two logical stores.
stl::logical_store<int, 2> store = {{1, 2, 3, 4},  //
                                    {2, 3, 4, 5},
                                    {3, 4, 5, 6}};

// `a` is an `mdspan` object referring to the rows of `store`.
auto fn = [] LEGATE_HOST_DEVICE(auto&& a) { a(0) = 42; };
stl::for_each(stl::rows_of(store), fn);

// store1 now contains:
// {
//   {42, 2, 3, 4},
//   {42, 3, 4, 5},
//   {42, 4, 5, 6}
// }

Parameters:
  • input – The input range to iterate over.

  • fn – The function to apply to each element.

Pre:

  • The input range input must satisfy the logical_store_like concept.

  • The function object fn must be callable with the element type of the input range.

  • The function object fn must be trivially copyable.

template<typename InputRange, typename Init, typename ReductionOperation>
logical_store<element_type_of_t<InputRange>, dim_of_v<Init>> reduce(
InputRange &&input,
Init &&init,
ReductionOperation op
)#

Reduces the elements of the input range using the given reduction operation operation.

Examples:

auto store = stl::create_store({5}, std::int64_t{1});
auto init  = stl::create_store({}, std::int64_t{1});

// fill the store with data
auto elems = stl::elements_of(store);
std::iota(elems.begin(), elems.end(), std::int64_t{1});

auto result = stl::reduce(store, init, std::plus<>());

auto result_span = stl::as_mdspan(result);
auto&& value     = result_span();
static_assert(std::is_same_v<decltype(value), const std::int64_t&>);
EXPECT_EQ(16, value);
stl::logical_store<std::int64_t, 2> store = {{0, 0, 0, 0},  //
                                             {1, 1, 1, 1},
                                             {2, 2, 2, 2}};

// Reduce by rows
{
  auto init        = stl::create_store({4}, std::int64_t{0});
  auto result      = stl::reduce(stl::rows_of(store), init, stl::elementwise(std::plus<>()));
  auto result_span = stl::as_mdspan(result);
  EXPECT_EQ(result_span.rank(), 1);
  EXPECT_EQ(result_span.extent(0), 4);
  EXPECT_EQ(result_span(0), 3);
  EXPECT_EQ(result_span(1), 3);
  EXPECT_EQ(result_span(2), 3);
  EXPECT_EQ(result_span(3), 3);
}

// Reduce by columns
{
  auto init        = stl::create_store({3}, std::int64_t{0});
  auto result      = stl::reduce(stl::columns_of(store), init, stl::elementwise(std::plus<>()));
  auto result_span = stl::as_mdspan(result);
  EXPECT_EQ(result_span.rank(), 1);
  EXPECT_EQ(result_span.extent(0), 3);
  EXPECT_EQ(result_span(0), 0);
  EXPECT_EQ(result_span(1), 4);
  EXPECT_EQ(result_span(2), 8);
}

Parameters:
  • input – The input range to reduce.

  • init – The initial value of the reduction.

  • op – The reduction operation to apply to the elements of the input range. op can be a type that satisfies the legate_reduction concept or one of the standard functional objects std::plus, std::minus, std::multiplies, std::divides, etc.; or an elementwise operation created by passing any of the above to stl::elementwise.

Pre:

  • InputRange must satisfy the logical_store_like concept.

  • Init must satisfy the logical_store_like concept.

  • The value type of the input range must be the same as the value type of the initial value.

  • The dimension of the input range must be one greater than the dimension of the initial value.

Returns:

An instance of logical_store with the same value type and shape as init.

template<typename InputRange, typename OutputRange, typename UnaryOperation>
void transform(
InputRange &&input,
OutputRange &&output,
UnaryOperation op
)#

Applies a unary operation to each element in the input range and stores the result in the output range.

The input range and the output range may be the same.

Example:
stl::logical_store<std::int64_t, 2> input = {{0, 1, 2, 3},  //
                                             {4, 5, 6, 7},
                                             {8, 9, 10, 11}};

// Transform by rows
auto result = stl::create_store({3, 4}, std::int64_t{0});
stl::transform(stl::rows_of(input),  //
               stl::rows_of(result),
               stl::elementwise(Square()));

// `result` now contains the squares of the elements:
//     [[0   1   4   9]
//      [16 25  36  49]
//      [64 81 100 121]]

Parameters:
  • input – The input range. Must satisfy the logical_store_like concept.

  • output – The output range. Must satisfy the logical_store_like concept.

  • op – The unary operation to apply.

Pre:

  • The input and output ranges must have the same shape.

  • The unary operation must be trivially relocatable.

template<typename InputRange1, typename InputRange2, typename OutputRange, typename BinaryOperation>
void transform(
InputRange1 &&input1,
InputRange2 &&input2,
OutputRange &&output,
BinaryOperation op
)#

Applies a binary operation to each element in two input ranges and stores the result in the output range.

The output range may be the same as one of the input ranges.

Example:
std::size_t extents[] = {4, 5};
auto store1           = stl::create_store<std::int64_t>(extents);
auto store2           = stl::create_store<std::int64_t>(extents);
auto store3           = stl::create_store<std::int64_t>(extents);

// Stateless extended lambdas work with both clang CUDA and nvcc
auto shift = [] LEGATE_HOST_DEVICE(std::int64_t a, std::int64_t b) {  //
  return a << b;
};

stl::fill(store1, 2);
stl::fill(store2, 4);
stl::transform(store1, store2, store3, shift);

// `store3` now contains the elements:
//     [[32 32 32 32 32]
//      [32 32 32 32 32]
//      [32 32 32 32 32]
//      [32 32 32 32 32]]

Parameters:
  • input1 – The first input range. Must satisfy the logical_store_like concept.

  • input2 – The second input range. Must satisfy the logical_store_like concept.

  • output – The output range. Must satisfy the logical_store_like concept.

  • op – The binary operation to apply.

Pre:

  • The input and output ranges must all have the same shape.

  • The binary operation must be trivially relocatable.

template<typename InputRange, typename Init, typename Reduction, typename UnaryTransform>
logical_store<value_type_of_t<Init>, dim_of_v<Init>> transform_reduce(
InputRange &&input,
Init &&init,
Reduction &&reduction_op,
UnaryTransform &&transform_op
)#

Transform the elements of a store with a unary operation and reduce them using a binary operation with an initial value.

stl::transform_reduce(input, init, reduction_op, transform_op) is semantically equivalent (with the caveat noted below) to:

auto result = stl::create_store<TransformResult>( <extents-of-input> );
stl::transform(input, result, transform_op);
return stl::reduce(result, init, reduction_op);

TransformResult is the result type of the unary transform operation. The input store arguments can be legate_store instances, or they can be views created with one of the view adaptors . If the input store is a view, the result store used to hold the results of the transformation step will be a view of the same shape as the input store.

Example
stl::logical_store<std::int64_t, 1> store{{5}};

// fill the store with data. The store will contain {1, 2, 3, 4, 5}
auto elems = stl::elements_of(store);
std::iota(elems.begin(), elems.end(), std::int64_t{1});

// a host/device lambda to square the elements
auto square = [] LEGATE_HOST_DEVICE(std::int64_t x) { return x * x; };

// sum the squared elements
auto result = stl::transform_reduce(store, stl::scalar<std::int64_t>(0), std::plus<>{}, square);

auto result_span  = stl::as_mdspan(result);
auto result_value = result_span();  // index into the 0-D mdspan
// result_value is 55

Parameters:
  • input – The input range to transform.

  • init – The initial value of the reduction.

  • reduction_op – The reduction operation to apply to the transformed elements of the input range. Reduction can be a type that satisfies the legate_reduction concept or one of the standard functional objects std::plus, std::minus, std::multiplies, std::divides, etc.; or an elementwise operation created by passing any of the above to stl::elementwise.

  • transform_op – The unary operation to apply to the elements of the input prior to the reduction step.

Pre:

  • InputRange must satisfy the logical_store_like concept.

  • Init must satisfy the logical_store_like concept.

  • The result type of the unary transform must be the same as the value type of the reduction’s initial value.

  • The dimension of the input range must be one greater than the dimension of the initial value.

Returns:

An instance of logical_store with the same value type and shape as init.

template<typename InputRange1, typename InputRange2, typename Init, typename Reduction, typename BinaryTransform>
logical_store<element_type_of_t<Init>, dim_of_v<Init>> transform_reduce(
InputRange1 &&input1,
InputRange2 &&input2,
Init &&init,
Reduction &&reduction_op,
BinaryTransform &&transform_op
)#

Transform the elements of two stores with a binary operation and reduce them using a binary operation with an initial value.

stl::transform_reduce(input1, input2, init, reduction_op, transform_op) is semantically equivalent (with the caveat noted below) to:

auto result = stl::create_store<TransformResult>( <extents-of-input1> );
stl::transform(input1, input2, result, transform_op);
return stl::reduce(result, init, reduction_op);

TransformResult is the result type of the binary transform operation. The input store arguments can be legate_store instances, or they can be views created with one of the view adaptors . If the input stores are views, the result store used to hold the results of the transformation step will be a view of the same shape as the first input store.

Parameters:
  • input1 – The first input range to transform.

  • input2 – The second input range to transform.

  • init – The initial value of the reduction.

  • reduction_op – The reduction operation to apply to the transformed elements of the input ranges. Reduction can be a type that satisfies the legate_reduction concept or one of the standard functional objects std::plus, std::minus, std::multiplies, std::divides, etc.; or an elementwise operation created by passing any of the above to stl::elementwise.

  • transform_op – The binary operation to apply to the elements of the two input ranges prior to the reduction step.

Pre:

  • InputRange1 and InputRange2 must satisfy the @c logical_store_like concept. @liInit` must satisfy the logical_store_like concept.

  • The shape of the input ranges must be the same.

  • The result type of the binary transform must be the same as the value type of the initial reduction value.

  • The dimensionality of the input ranges must be one greater than the dimension of the reduction initial value.

Returns:

An instance of logical_store with the same value type and shape as init.