ENH: add a segmented_reduce method to ufuncs - #32243
Conversation
Signed-off-by: Iason Krommydas <iason.krom@gmail.com>
jorenham
left a comment
There was a problem hiding this comment.
sorry if premature, but I left some typing-related comments
|
|
||
| add_newdoc('numpy._core', 'ufunc', ('segmented_reduce', | ||
| """ | ||
| segmented_reduce($self, array, /, starts, stops=None, axis=0, dtype=None, out=None, **kwargs) |
There was a problem hiding this comment.
Can we make anything after stops=None keyword-only?
There was a problem hiding this comment.
I will actually make stops required btw. I don't like the None case. Regarding keyword-only, there's no precedent for that in ufunc methods. No other ufunc methods have keyword-only args as far as I can see. We have to follow what reduce, reduceat and accumulate do here regarding their signature.
There was a problem hiding this comment.
It's what the stubs enforce though, because I checked, and axis is rarely ever used as positional argument in practice for e.g. reduce.
there's no precedent for that in ufunc methods
Personally I don't think that consistency is worth repeating the mistakes of the past (even though I think consistency is pretty important).
Signed-off-by: Iason Krommydas <iason.krom@gmail.com>
This comment has been minimized.
This comment has been minimized.
Signed-off-by: Iason Krommydas <iason.krom@gmail.com>
|
Diff from mypy_primer, showing the effect of this PR on type check results on a corpus of open source code: optuna (https://github.com/optuna/optuna)
./optuna/study/_multi_objective.py:182: error: INTERNAL ERROR -- Please try using mypy master on GitHub:
|
mhvk
left a comment
There was a problem hiding this comment.
I have not looked in any detail yet, but think it is important that we end up in a state where there is only one function that deals with the internals of both reduceat and segmented_reduce, i.e., we should factor out the innards. Otherwise we're nearly guaranteed that the code will diverge.
Otherwise, only bikeshedding about names and keywords so far...
| over segments (slices) of an axis given by their start and stop offsets:: | ||
|
|
||
| >>> a = np.arange(8) | ||
| >>> np.add.segmented_reduce(a, starts=[0, 5], stops=[3, 8]) |
There was a problem hiding this comment.
I'm not sure about the plural here, since a single value is in principle allowed.
There was a problem hiding this comment.
My idea is that it comes from "start offsets" and "stop offsets" and offsets is always plural so I called them starts and stops. CCCL calls them "start_offsets_inandend_offsets_in`. I don't care much but I'm personally a fan of plural tbh.
There was a problem hiding this comment.
My analogy is with slice, which has start and stop -- at some point I had a branch where for reduceat I let the user give a slice object with start and stop arrays. Also, things like np.linspace have start and stop which can be arrays.
But of course, for linspace, the expectation is that they are scalars, while here it is that you input multiple items with a single one an unusual possibility. Given that, I don't mind so much any more.
p.s. Actually, I think a single item should behave differently than a list of length 1: it should remove axis unless keepdims=True. If we do that, we can pass ufunc.reduce trivially through your new code... Relatedly, if the start and stop are >=2D arrays, one might want to insert multiple axes... For this PR, I suggest we insist on 1D arrays so that we do not prevent exploring use cases for different dimensions...
There was a problem hiding this comment.
I was planning on doing ONLY 1D starts/stops anyways here. If somebody wants to expand that sure but indices in reduceat is also 1D only. I had only thought of segmentes along axis and nothing more than that. I'm haven't even thought about more than 1D 🤣
There was a problem hiding this comment.
Excellent. The main thing is not to get starts and stops with something like the C-side equivalent of np.asanyarray(starts, ndmin=1), but rather explicitly check that they are 1D.
|
|
||
| add_newdoc('numpy._core', 'ufunc', ('segmented_reduce', | ||
| """ | ||
| segmented_reduce($self, array, /, starts, stops, axis=0, dtype=None, out=None, **kwargs) |
There was a problem hiding this comment.
I'm with @jorenham in thinking we should make everything starting with axis keyword only.
There was a problem hiding this comment.
Generally I agree. My disagreement here is that this this feels like an improved version of reduceat to me and it feels nicer to maintain the way arguments are parsed consistent between them. Happy to do what the maintainers think of course. If I was designing the API from scratch I'd go keyword only for sure.
Yes I started this by copying the reduceat code exactly as is. There's definitely a ton of duplicated code here overall. Reduceat also duplicates a lot of code from accumulate as well and there's a TODO in the code to fix that. I'd be willing to tackle this as well but I want to do this after the upgrade to handle reduction loops comes in. |
|
Yes, good to get the reduction, etc., loops in first -- they're a very nice improvement! |
Yeah treat this PR as "ready for design comments" basically 🤣. The generalization of the reduction loops to reduceat and accumulate (two PRs are open for this) will definitely come in first and this will be heavily rebased afterwards. |
|
Great work |
PR summary
Taking over #25476.
Implements a new
segmented_reducemethod to ufuncs as it was discussed on that PR instead of enhancing thereduceatinterface.In its current state, this was mostly developed within the weekend by starting over by copying the whole
reduceatcode into a newsegmented_reducemethod, adding all the boilerplate for it and iterating with AI on making the necessary changes to it to support starts and stops offsets while considering the changes from Marten's PR. This is obviously not in a ready state and I have only skimmed through the code while iterating with AI. I just wanted a proof of concept over the weekend. I'm opening it as draft for visibility and because I wanted a CI run. I will be iterating over it in the next few days to get it in a ready to review state.First time committer introduction
N/A
AI Disclosure
See above for the AI usage in the current state. Will update later.
cc @mhvk since the previous PR was yours