-
Notifications
You must be signed in to change notification settings - Fork 0
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
Use `permute' or operator[] as the name of permutation functions? #55
Comments
I hope we'll get a void f(std::vector<float> const& data, simd<float> v, simd<int> idxs) {
simd x = data[idxs];
simd y = v[idxs];
} So OTOH, do we want the following? void f(std::vector<float> const& data, simd<float> v, simd_mask<float> mask) {
simd x = data[mask];
simd y = v[mask];
} Subscripting a contiguous range with a I have a question that your paper doesn't appear to address: What about inserting zeros into the output? Like if I want to permute [1, 2, 3, 4] into [2, 0, 4, 0]? I can always blend with a mask. But it's not uncommon that the positions of the zeros is an intrinsic property of the algorithm and could trivially be specified in the index mapping function. E.g. Another question: Have you considered indexing from the end? E.g. |
I think subscripting a contiguous_iterator with a mask should be handled by an overload with a better name, like std::copy_if. At the moment I handle the insertion of zeros likes this:
I don't like making the indexes have special values to mean different things, like insert-a-zero or index-from-the-end. |
For convenience, is it worth also having a C++-23 multi-index overload of operator[] to allow this to be written:
This would be equivalent to:
(or with variables in there too) |
This is a good question and belongs into the paper. As well as an exploration and your/our recommendation. At this point |
In order to write generic permutation mappings the mapping function needs the constexpr auto broadcast_last = [](unsigned idx) { return size - 1; }; But |
I had thought about doing that, but generally I've found that the size of the first parameter is often readily available in the context of its use anyway. For example, my reverse function:
To start with I think we leave it without a size parameter and get more user feedback. |
Right, but how do you write a generic / named index mapping function for reverse? Like the |
I've just prototyped the |
Oh, and for good measure, I also implemented setting negative indexing (from the end) and setting values to zero via the mapping. It comes at no runtime cost, so it's really just a question of usefulness / complexity. |
Just realized: since I allow negative indexing, the |
Do we want to provide pre-defined utility lambdas that we can hand over to permute:
or do we define a top-level function which does invokes permute with a local lambda which can get the information about size from its own context:
If we want the former, than having the size parameter is useful, and gives something very flexible. But the second creates a much tighter interface which makes it more obvious how to use it, and consequently harder for mistakes to creep in (e.g., getEven needs an output size which is no greater than half the input size, but a stand-alone lambda couldn't enforce that). The function called getEven might not be a good example. Maybe better examples would be if we created functions which mirror their existing counterparts, like std::reverse, std::shift_left, std::rotate, and so on, overloaded for simd, and which are implemented using permute with a local lambda. I think that most users would want something which does the whole job (i.e., named functions), rather than a pre-defined utility lambda that they need to figure out how to call properly. |
This is what is in P2664R3, but I have had users feed back that they don't like negative indexes. Errors in computing the index (e.g., off-by-one) can result in apparently valid negative indexes which don't get flagged up at compile time and have to be caught with run-time testing. Also, having the size passed in (also in P2664R3) means redundancy in having two mechanisms for getting indexes from the end. I propose that we keep the optional size parameter but drop negative indexes. Indexes will only ever be in the range [0..size), or the special zero and uninitialised constants, which is easy to check at compile time. |
Re: https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2023/p2664r1.pdf
The basic proposal is to add 3 permute overloads to cover the common permutation cases:
The first use probably has to stay since there needs to be some way of passing in the size of the desired output simd.
Should the other two uses overload operator[]?
If they do change operator[] then the changes would need to be rolled into std::simd, but providing permute instead would make this an extension on top of std::simd.
The text was updated successfully, but these errors were encountered: