Skip to content

[onedpl][ranges] L1 Range based algo API and implementation #2272

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 22 commits into
base: main
Choose a base branch
from

Conversation

MikeDvorskiy
Copy link
Contributor

@MikeDvorskiy MikeDvorskiy commented May 20, 2025

[onedpl][ranges] L1 Range based algo API and implementation, according to RFC proposal #2269

  • reverse

  • reverse_copy; (return values semantic might be changed in the future or this algo will be removed)

  • unique

  • unique_copy

  • swap_ranges (extra algo, also usefull)

@MikeDvorskiy MikeDvorskiy marked this pull request as draft May 20, 2025 12:52
@MikeDvorskiy MikeDvorskiy force-pushed the dev/mdvorski/ranges_algo_L1-origin_UXL branch 8 times, most recently from 6ef1d07 to 3b9fa92 Compare May 20, 2025 14:03
@MikeDvorskiy MikeDvorskiy marked this pull request as ready for review May 21, 2025 15:45
@MikeDvorskiy MikeDvorskiy force-pushed the dev/mdvorski/ranges_algo_L1-origin_UXL branch 2 times, most recently from b02531f to 25b1761 Compare May 23, 2025 15:53
Copy link
Contributor

@dmitriy-sobolev dmitriy-sobolev left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've checked the signatures for their compliance with https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2025/p3179r8.html#modify_copy - everything looks good.

Comment on lines +1150 to +1153
return oneapi::dpl::ranges::copy(std::forward<_ExecutionPolicy>(__exec), std::ranges::reverse_view(__in_r),
std::forward<_OutRange>(__out_r));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

__pattern_reverse_copy from the device backend also uses an optimized __reverse_copy routine. Let's reuse it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, it makes sense for hetero policy.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lets wait an update from C++ committee. There is a chance that ranges::reverse_copy with policy will be removed from the parallel algo set.


namespace __internal
{
struct __reverse_copy_fn
Copy link
Contributor

@dmitriy-sobolev dmitriy-sobolev May 27, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is no a corresponding test. Could you add it?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lets wait an update from C++ committee. There is a chance that ranges::reverse_copy with policy will be removed from the parallel algo set.

@MikeDvorskiy MikeDvorskiy force-pushed the dev/mdvorski/ranges_algo_L1-origin_UXL branch from a53327b to c0d749c Compare May 27, 2025 13:53
Copy link
Contributor

@SergeyKopienko SergeyKopienko left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this changes I see more then one new lambdas like

template <typename _Tag, typename _ExecutionPolicy, typename _R, typename _Comp, typename _Proj>
std::ranges::borrowed_subrange_t<_R>
__pattern_unique(_Tag __tag, _ExecutionPolicy&& __exec, _R&& __r, _Comp __comp, _Proj __proj)
{
    auto __pred_2 = [__comp, __proj](auto&& __val1, auto&& __val2) { return std::invoke(__comp, std::invoke(__proj,
        std::forward<decltype(__val1)>(__val1)), std::invoke(__proj, std::forward<decltype(__val2)>(__val2)));};

    auto __beg = std::ranges::begin(__r);
    auto __end = __beg + std::ranges::size(__r);
    auto __it = oneapi::dpl::__internal::__pattern_unique(__tag, std::forward<_ExecutionPolicy>(__exec),
                                                          __beg, __end, __pred_2);

    return std::ranges::borrowed_subrange_t<_R>(__it, __end);
}

ehich created in some template code, parametriszed by ExecutionPolicy as template parameter.

This mean you again introduce the problem with ExecutionPolicy passed as l-value or r-value.

If all lambda's like that created only in host code. please insert

static_assert(__is_serial_tag_v<_Tag> || __is_parallel_forward_tag_v<_Tag>);

in these functions.

void
operator()(_ReferenceType1 __x, _ReferenceType2 __y) const
operator()(_Type1&& __x, _Type2&& __y) const
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe this change looks not quite correct.
Because now you are using here universal reference : this mean you may pass into this function const reference too.
But it's invalid use case and I believe better to rewrite this like

operator()(_Type1& __x, _Type2& __y) const

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The second moment - now this function ready to swap anything.
So you change semantic, because before this change struct __swap_fn require types in template parameters.
Are you sure that this change is correct?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But it's invalid use case and I believe better to rewrite this like

No.... For example, a proxy type, like tuple<int&, int&> doesn't match to _Type1& __x.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, before swap_range algo did not work with zip_view and zip_iterator.... and other data where dereferenced value is a rvalue (a proxy object).
So, the change fixes such cases.
And yes, it makes sense to add such test cases - oneDPl doesn't have ones.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok

@SergeyKopienko
Copy link
Contributor

Minor comment: not all :: before std in changed lines has been removed.

@SergeyKopienko
Copy link
Contributor

@MikeDvorskiy could you you please check and fix in this PR the issue #2283 ?
Thanks.

Comment on lines 25 to 27
//A checker below modifies a return type; a range based version with policy has another return type.
auto reverse_checker = [](auto&&... args) {
return std::ranges::reverse(std::forward<decltype(args)>(args)...);
};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I do not quite understand why and how the return type is changed.

std::ranges::reverse, when fed with a range, returns ranges::borrowed_iterator_t<R>. The same type is returned by the algorithm with the policy.

Is that checker really needed?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess, the comment is not relevant.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suppose that the checker can be removed as well.

return ret_type{std::ranges::begin(r1) + size, std::ranges::begin(r2) + size};
};

test_range_algo<0, int, data_in_out_lim>{big_sz}(dpl_ranges::swap_ranges, swap_ranges_checker);
Copy link
Contributor

@dmitriy-sobolev dmitriy-sobolev May 27, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

data_in_out_lim checks only "out" range. I expect that a test for swap_ranges should check both.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, data_in_out_lim checks "out" range and :"in' range. Please take a look at the code:

        //test case size of input range is less than size of output and vice-versa
        process_data_in_out(max_n, r_size/2, r_size, exec, algo, checker, args...);
        process_data_in_out(max_n, r_size, r_size/2, exec, algo, checker, args...);

Copy link
Contributor

@dmitriy-sobolev dmitriy-sobolev Jun 9, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These commands run the test with sequences with different sizes:

process_data_in_out(max_n, r_size/2, r_size, exec, algo, checker, args...);
process_data_in_out(max_n, r_size, r_size/2, exec, algo, checker, args...);

I meant the check of the data inside of the sequences. I've found only one such a check, which is performed over the second sequence:

EXPECT_EQ_N(cont_exp().begin(), cont_out().begin(), n, (std::string("wrong effect algo with ranges: ") + typeid(Algo).name()).c_str());

The data in the first sequence is not checked.

@MikeDvorskiy MikeDvorskiy force-pushed the dev/mdvorski/ranges_algo_L1-origin_UXL branch 2 times, most recently from 22e0a8c to 5987bc0 Compare May 30, 2025 14:24
@MikeDvorskiy MikeDvorskiy force-pushed the dev/mdvorski/ranges_algo_L1-origin_UXL branch 2 times, most recently from ea3d9de to aa0ae5b Compare May 30, 2025 15:42
@MikeDvorskiy
Copy link
Contributor Author

This mean you again introduce the problem with ExecutionPolicy passed as l-value or r-value.

Essentially, no. This is a host part of the __pattern_unique implementation.
But yes, we can use oneapi::dpl::__internal::__compare functor instead of introducing new lambda.

@MikeDvorskiy MikeDvorskiy force-pushed the dev/mdvorski/ranges_algo_L1-origin_UXL branch 3 times, most recently from 299a3cc to db5bd13 Compare June 5, 2025 15:35
@MikeDvorskiy MikeDvorskiy force-pushed the dev/mdvorski/ranges_algo_L1-origin_UXL branch from db5bd13 to 6cc066b Compare June 10, 2025 14:13
…Tag> || typename _Tag::__is_vector{}); and usage of some predefined functors
@MikeDvorskiy MikeDvorskiy force-pushed the dev/mdvorski/ranges_algo_L1-origin_UXL branch from 6cc066b to 0c2f14c Compare June 12, 2025 10:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants