Add new known issue about oneapi::dpl::ranges algorithms - #2811
SergeyKopienko merged 8 commits into
Conversation
…_device_copyable values for hetero policies
|
Detailed analysis after using
|
…_device_copyable values for hetero policies
| - Some algorithms in the ``oneapi::dpl::ranges`` family have known implementation issues where the implementation | ||
| relies on operations that are not guaranteed to be supported by the types satisfying the requirements | ||
| specified in the ``requires`` clauses. | ||
| With host policies, ``min``, ``max``, and ``minmax`` require a default-initializable value type and an | ||
| addressable comparator, while ``min_element``, ``max_element``, and ``minmax_element`` also require a | ||
| copyable value type, and ``minmax_element`` requires construction/assignment from iterator reference types. | ||
| With host and device policies, ``set_difference``, ``set_intersection``, ``set_symmetric_difference``, and | ||
| ``set_union`` require an output value type constructible from input reference types and a non-proxy output | ||
| iterator. | ||
|
|
There was a problem hiding this comment.
Note, there other places where we have such notes:
- "Known Limitations" from
introduction.rst - "Difference with Standard C++ Parallel Algorithms" from
introduction.rst
Should the note (or its parts) go to these sections instead? If you think that effective implementation of the parallel algorithms is impossible given the restrictions, it's worth moving a note to "Difference with Standard C++ Parallel Algorithms". If you think it is unfeasible to fix in near-term, you can move a note to "Known Limitations".
Co-authored-by: Dmitriy Sobolev <Dmitriy.Sobolev@intel.com>
| - ``set_difference``, ``set_intersection``, ``set_symmetric_difference``, ``set_union`` require | ||
| an output value type constructible from input reference types and a non-proxy output iterator. |
There was a problem hiding this comment.
Do we want to call out zip_iterator here specifically? This would be the most common and relevant one I think. Presumably this does not work?
There was a problem hiding this comment.
I do not think we should mention zip iterators here - these algorithm have only ranges as arguments. We may mention views::zip, though, but the note may become too complicated.
Upd. suggestion: #2811 (comment)
Co-authored-by: Dan Hoeflinger <109972525+danhoeflinger@users.noreply.github.com>
Co-authored-by: Dan Hoeflinger <109972525+danhoeflinger@users.noreply.github.com>
Co-authored-by: Dmitriy Sobolev <Dmitriy.Sobolev@intel.com>
Co-authored-by: Dmitriy Sobolev <Dmitriy.Sobolev@intel.com>
| the type obtained by dereferencing the range's iterator. | ||
| * ``set_difference``, ``set_intersection``, ``set_symmetric_difference``, ``set_union`` with both host | ||
| and device policies require an output value type constructible from input reference types and | ||
| a non-proxy output iterator. |
There was a problem hiding this comment.
I'm not sure it is correct (it should be confirmed), but it highlights a "by key" case. This is what Dan was asking above, I think:
| a non-proxy output iterator. | |
| a non-proxy output iterator. For instance, proxy iterators are provided by | |
| ``dpl::experimental::ranges::zip_view`` and possibly by ``std::ranges::zip_view``. |
danhoeflinger
left a comment
There was a problem hiding this comment.
This seems reasonable to me. The mention of zip_view may be nice to clarify what might be most relevant but its optional Id say
Summary
Adds a known-issue entry to
documentation/release_notes.rststating that severaloneapi::dpl::rangesalgorithms rely on operations that are not guaranteed by the types satisfying their declaredrequiresclauses.This description documents the detailed analysis behind that entry: for each algorithm, which extra requirements the implementation imposes beyond the declared constraints, and where in the sources they originate.
Detailed analysis
oneapi::dpl::ranges::min/oneapi::dpl::ranges::maxAffected implementations: host.
Additional requirements imposed by the
__simd_min_element()implementation. Both algorithms already declarestd::indirectly_copyable_storable<iterator_t<_R>, range_value_t<_R>*>(glue_algorithm_ranges_impl.h:750), which covers copy construction and copy assignment; therefore only the following remain extra:std::ranges::range_value_t<_R>must be default initializable —unseq_backend_simd.h:635unseq_backend_simd.h:655oneapi::dpl::ranges::min_element/oneapi::dpl::ranges::max_elementAffected implementations: host.
Additional requirements imposed by the
__simd_min_element()implementation, beyond the declared constraints (random_access_range,sized_range,indirect_strict_weak_order):std::ranges::range_value_t<_R>must be default initializable —_ComplexType::__min_val{},unseq_backend_simd.h:635std::ranges::range_value_t<_R>must be copy constructible and copy assignable —unseq_backend_simd.h:636-640,662-666; note that these algorithms do not declarestd::indirectly_copyable_storable, so this is genuinely extraoperator&must not be overloaded —&__comp,unseq_backend_simd.h:655oneapi::dpl::ranges::minmaxAffected implementations: host.
Additional requirements imposed by the
__simd_minmax_element()implementation.minmaxdeclaresstd::indirectly_copyable_storable(glue_algorithm_ranges_impl.h:789), so copy construction/assignment are already part of the contract:std::ranges::range_value_t<_R>must be default initializable —unseq_backend_simd.h:695std::ranges::range_value_t<_R>must be assignable fromstd::iter_reference_t<std::ranges::iterator_t<_R>>without an explicit conversion —unseq_backend_simd.h:742unseq_backend_simd.h:733oneapi::dpl::ranges::minmax_elementAffected implementations: host.
Additional requirements imposed by the
__simd_minmax_element()implementation:std::ranges::range_value_t<_R>must be default initializable —_ComplexType::__min_val{}, __max_val{},unseq_backend_simd.h:695std::ranges::range_value_t<_R>must be copy constructible and copy assignable —unseq_backend_simd.h:696-701,710-750;minmax_elementdoes not declarestd::indirectly_copyable_storableeitherstd::ranges::range_value_t<_R>must be constructible and assignable fromstd::iter_reference_t<std::ranges::iterator_t<_R>>without an explicit conversion —auto __current = __first[__i];,unseq_backend_simd.h:742; unlike__simd_min_element()(line 663) the type is deduced from the reference type, which additionally breaks for proxy iterators&__comp,unseq_backend_simd.h:733oneapi::dpl::ranges::set_union/set_intersection/set_difference/set_symmetric_differenceAffected implementations: host + hetero.
Additional requirements imposed by the implementation:
std::ranges::range_value_t<_OutRange>must be constructible fromiter_reference_tof both input iterators — the implementation copy-constructs into raw buffer memory:set_algorithms_utils.h:91,new (std::addressof(*__it_out)) _OutValueType(*__it_in);— whereasstd::mergeableonly guarantees*out = *in.std::ranges::iterator_t<_OutRange>must not be a proxy iterator:std::addressof(*__it_out)requires a real lvalue (set_algorithms_utils.h:91).Summary table
min,maxmin_element,max_elementminmaxiter_reference_t; addressable comparatorminmax_elementiter_reference_t; addressable comparatorset_union,set_intersection,set_difference,set_symmetric_differenceiter_reference_t; non-proxy output iterator