ここでは、拡張 API アルゴリズムと機能ユーティリティー・クラスの一覧を提供します。
現在、拡張 API にはアルゴリズム、イテレーター、および関数オブジェクト・クラスが含まれます。アルゴリズムには、セグメント化されたレデュース、セグメント化されたスキャン、およびベクトル化された検索アルゴリズムが含まれます。イテレーターは、ほかのイテレーターに対する zip、変換、置換操作を実装し、カウントイテレーターとディスカード・イテレーターを含みます。関数オブジェクト・クラスは、レデュースや変換などのアルゴリズムに渡すことができる minimum、maximum、および identity 操作を提供します。拡張 API には、範囲ベースのアルゴリズムの実験的な実装と、それを使用するために必要な範囲が含まれています。
拡張 API で提供されるアルゴリズムは、oneapi/dpl/algorithm ヘッダーで定義されています。すべてのアルゴリズムは、oneapi::dpl 名前空間で実装されています。
reduce_by_segment アルゴリズムは、シーケンスの値とキーの部分リダクションを実行します。各リダクションは、プレディケートによりキーが等しいと判断された値の連続するサブシーケンスのリダクション操作を計算します。戻り値は、キーと値の出力シーケンスの最後を保持するイテレーターのペアです。
正しく計算するため、リダクション操作は結合側を満たしていなければなりません。操作を指定しない場合、デフォルトのリダクション操作は std::plus、デフォルトのプレディケートは std::equal_to になります。このアルゴリズムでは、値に使用される要素の型がデフォルトで構成可能でなければなりません。次に例を示します。
keys: [0,0,0,1,1,1] values: [1,2,3,4,5,6] output_keys: [0,1] output_values: [1+2+3=6,4+5+6=15]
inclusive_scan_by_segment アルゴリズムは、シーケンスの値に対して部分的なプリフィクス・スキャンを実行します。各スキャンは、キーが等しいと判断された値の連続するサブシーケンスに適用されます。戻り値は、結果シーケンスの最後を示すイテレーターです。
正しく計算するため、プリフィクス・スキャン操作は結合側を満たしていなければなりません。操作を指定しない場合、デフォルトの操作は std::plus、デフォルトのプレディケートは std::equal_to になります。このアルゴリズムでは、値に使用される要素の型がデフォルトで構成可能でなければなりません。次に例を示します。
keys: [0,0,0,1,1,1] values: [1,2,3,4,5,6] result: [1,1+2=3,1+2+3=6,4,4+5=9,4+5+6=15]
exclusive_scan_by_segment アルゴリズムは、シーケンスの値に対して部分的なプリフィクス・スキャンを実行します。各スキャンは、キーが等しいと判断された値の連続するサブシーケンスに適用され、最初の要素を提供された初期値に設定します。戻り値は、結果シーケンスの最後を示すイテレーターです。
正しく計算するため、プリフィクス・スキャン操作は結合側を満たしていなければなりません。操作を指定しない場合、デフォルトの操作は std::plus、デフォルトのプレディケートは std::equal_to になります。次に例を示します。
keys: [0,0,0,1,1,1] values: [1,2,3,4,5,6] initial value: [0] result: [0,0+1=1,0+1+2=3,0,0+4=4,0+4+5=9]
binary_search アルゴリズムは、提供された検索シーケンスの各値について、入力シーケンスのバイナリー検索を実行します。検索シーケンスの各要素に対して、アルゴリズムは、入力シーケンスで検索値が見つかったかどうかを示す結果シーケンスにブール値を書き込みます。戻り値は、結果シーケンスの最後の値の 1 つ後を示すイテレーターです。このアルゴリズムは、入力シーケンスが比較子によってソートされていると仮定します。比較子が提供されない場合、operator< を使用して要素を比較する関数オブジェクトが使用されます。次に例を示します。
input sequence: [0, 2, 2, 2, 3, 3, 3, 3, 6, 6] search sequence: [0, 2, 4, 7, 6] result sequence: [true, true, false, false, true]
lower_bound アルゴリズムは、検索シーケンスの各値について、入力シーケンスのバイナリー検索を実行します。これは、入力シーケンスのソートされた順序に違反することなく検索値を入力できるように、入力シーケンスの最小インデックスを特定します。各検索値の最小インデックスが結果シーケンスに書き込まれ、アルゴリズムは結果シーケンスに書き込まれた最後の値の 1 つ後を示すイテレーターを返します。比較子が提供されない場合、operator< を使用して要素を比較する関数オブジェクトが使用されます。次に例を示します。
input sequence: [0, 2, 2, 2, 3, 3, 3, 3, 6, 6] search sequence: [0, 2, 4, 7, 6] result sequence: [0, 1, 8, 10, 8]
upper_bound アルゴリズムは、検索シーケンスの各値について、入力シーケンスのバイナリー検索を実行します。これは、入力シーケンスのソートされた順序に違反することなく検索値を入力できるように、入力シーケンスの最大インデックスを特定します。各検索値の最大インデックスが結果シーケンスに書き込まれ、アルゴリズムは結果シーケンスに書き込まれた最後の値の 1 つ後を示すイテレーターを返します。比較子が提供されない場合、operator< を使用して要素を比較する関数オブジェクトが使用されます。次に例を示します。
input sequence: [0, 2, 2, 2, 3, 3, 3, 3, 6, 6] search sequence: [0, 2, 4, 7, 6] result sequence: [1, 4, 8, 10, 10]
拡張 API で提供されるイテレーターは、oneapi/dpl/iterator ヘッダーで定義されています。すべてのイテレーターは、oneapi::dpl 名前空間で実装されています。
counting_iterator は、逆参照値が整数カウンターであるランダム・アクセス・イテレーターのような型です。counting_iterator のインスタンスは、読み取り専用の逆参照操作を提供します。counting_iterator インスタンスのカウンターは、ランダム・アクセス・イテレーター型の演算に応じて変化します。次に例を示します。
using namespace oneapi; dpl::counting_iterator<int> count_a(0); dpl::counting_iterator<int> count_b = count_a + 10; int init = count_a[0]; // OK: init == 0 *count_b = 7; // エラー: counting_iterator は書き込み操作を提供しません auto sum = std::reduce(dpl::execution::dpcpp_default, count_a, count_b, init); // sum は (0 + 0 + 1 + ...+ 9) = 45
discard_iterator は、渡された値を破棄する書き込み専用の逆参照操作を提供するランダム・アクセス・イテレーターのような型です。
このイテレーターは、ステンシルが出力の一部ではないステンシル・アルゴリズムの実装に役立ちます。一例として、入力イテレーターの範囲とステンシル・イテレーターの範囲を受け取り、ステンシル値が 1 の入力要素をコピーする copy_if アルゴリズムが挙げられます。ステンシルのコピーを格納する一時割り当てを宣言しなくても済むように、discard_iterator を使用する必要があります。次に例を示します。
using namespace oneapi; auto zipped_first = dpl::make_zip_iterator(first, stencil); std::copy_if(dpl::execution::dpcpp_default, zipped_first, zipped_first + (last - first), dpl::make_zip_iterator(result, dpl::discard_iterator()), [](auto t){return get<1>(t) == 1;}
transform_iterator は、逆参照値がオリジナルのイテレーターの対応する要素に関数を適用した結果である、別のイテレーター上で定義されるイテレーターです。元のイテレーターの型と逆参照操作中に適用される単項関数の型は、どちらも transform_iterator クラスのテンプレート・パラメーターでなければなりません。また、transform_iterator のコンストラクターは、オリジナルのイテレーターと単項変換操作のインスタンスの両方を受け取ります。
イテレーターを簡単に構築できるように、oneapi::dpl::make_transform_iterator が提供されています。この関数は、引数としてオリジナルのイテレーターと変換操作のインスタンスを受け取り、transform_iterator インスタンスを構築します。次に例を示します。
using namespace oneapi; dpl::counting_iterator<int> first(0); dpl::counting_iterator<int> last(10); auto transform_first = dpl::make_transform_iterator(first, std::negate<int>()); auto transform_last = transform_first + (last - first); auto sum = std::reduce(dpl::execution::dpcpp_default, transform_first, transform_last); // sum は (0 + -1 + ...+ -9) = -45
permutation_iterator は、逆参照値のセットが提供されるソース・イテレーターによって定義されるイテレーターです。逆参照値のセットの反復順序は、別のイテレーター、またはインデックス演算子が permutation_iterator インデックスからソース・イテレーターのインデックスへのマップを定義するファンクターのいずれかによって定義されます。permutation_iterator は、イテレーターで表されるデータの非連続要素を、連続しているかのようにアルゴリズムで処理する必要があるアプリケーションを実装するのに役立ちます。一例として、出力イテレーターに 1 つおきに要素をコピーする場合があります。
イテレーター・インスタンスを容易に構築できるように、make_permutation_iterator が提供されています。この関数は、ソース・イテレーターとインデックス・マップを表すイテレーター (関数オブジェクト) を受け取ります。次に例を示します。
struct multiply_index_by_two { template <typename Index> Index operator()(const Index& i) { return i*2; } }; // 最初と最後は入力要素の連続する範囲を定義するイテレーター // 置換イテレーターによってアクセスされる、最初と最後の間の範囲内の // 要素数を計算する size_t num_elements = std::distance(first, last) / 2 + std::distance(first, last) % 2; using namespace oneapi; auto permutation_first = dpl::make_permutation_iterator(first, multiply_index_by_two()); auto permutation_last = permutation_first + num_elements; std::copy(dpl::execution::dpcpp_default, permutation_first, permutation_last, result);
zip_iterator は、1 つ以上のイテレーターを入力として構築されるイテレーターです。逆参照時にイテレーターによって返される値は、zip_iterator が定義されているメンバー・イテレーターの逆参照によって返される値のタプルです。zip_iterator インスタンスに対して実行された算術演算は、各メンバー・イテレーターに適用されます。
zip_iterator インスタンスを容易に構築できるように、make_zip_iterator 関数が提供されています。この関数は、構築する zip_iterator がメンバー・イテレーターとして保持する各イテレーターを受け取ります。
discard_iterator の例では、zip_iterator を使用してステンシル・アルゴリズムを定義します。zip_iterator は、キーと値を表す入力イテレーターがキーと値のペアとして処理されるキー・アルゴリズムの定義にも役立ちます。以下の例は、キーのみを比較してキーと値の両方をスワップする、安定したキーによるソートです。次に例を示します。
using namespace oneapi; auto zipped_begin = dpl::make_zip_iterator(keys_begin, vals_begin); std::stable_sort(dpl::execution::dpcpp_default, zipped_begin, zipped_begin + n, [](auto lhs, auto rhs) { return get<0>(lhs) < get<0>(rhs); });
拡張 API で提供される関数オブジェクトは、oneapi/dpl/functional で定義されています。すべての関数オブジェクトは、oneapi::dpl 名前空間で実装されています。
C++20 では「範囲」ライブラリーが導入されました。С++20 標準は、範囲を「factory (ファクトリー)」と「adaptor (アダプター)」の 2 つのカテゴリーに分割します。範囲ファクトリーにはデータがありません。要素は、成功した場合、インデックスによって、またはイテレーターを逆参照して生成されます。インテル® oneDPL にとって範囲アダプターは、ベース範囲や別の適用範囲をカスタム動作のビューに変換するユーティリティーです。インテル® oneDPL は iota_view 範囲ファクトリーをサポートしています。all_view でラップされた sycl::buffer は範囲として使用できます。インテル® oneDPl は、サポートされているファクトリーと all_view をベース範囲と見なします。範囲アダプターは、ベース範囲を先頭にしてパイプラインに結合することができます。次に例を示します。
cl::sycl::buffer<int> buf(data, cl::sycl::range<1>(10)); auto range_1 = iota_view(0, 10) | views::reverse(); auto range_2 = all_view(buf) | views::reverse();
all_view ファクトリー・ベースの範囲では、データアクセスはデバイス上でのみ許可されます。size() および empty() メソッドは、ホストまたはデバイスのいずれかで呼び出すことができます。範囲では次のアルゴリズムを使用できます。
以下は、2 つのイテレーターの代わりに source を使用して入力を表現する範囲ベースのアルゴリズムの特徴的な例です。destination は出力を表します。
template <typename ExecutionPolicy, typename Range1, typename Range2> void copy(ExecutionPolicy&& exec, Range1&& source, Range2&& destination);
これらのアルゴリズムは、oneapi::dpl::experimental::ranges 名前空間で宣言されており、DPC++ ポリシー用にのみ実装されています。これらのアルゴリズムを利用できるようにするには、 <oneapi/dpl/ranges> ヘッダーをインクルードする必要があります。範囲ベースの API を使用するには、gcc 8.1 以降または Clang 7 以降に同梱の C++17 および C++ 標準ライブラリーが必要です。
次の表示可能な範囲は、oneapi::dpl::experimental::ranges 名前空間で宣言されています。範囲ベースのアルゴリズムでは、次の値のみ範囲として使用できます。
以下は、範囲ベースの API の使用例です。
using namespace oneapi::dpl::experimental::ranges; { cl::sycl::buffer<int> A(data, cl::sycl::range<1>(max_n)); cl::sycl::buffer<int> B(data2, cl::sycl::range<1>(max_n)); auto view = all_view(A) | views::reverse(); auto range_res = all_view<int, cl::sycl::access::mode::write>(B); copy(oneapi::dpl::execution::dpcpp_default, view, range_res); }