-
-
Notifications
You must be signed in to change notification settings - Fork 1.7k
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
Cosmo: allow broadcasting in z_at_value
#11778
Conversation
👋 Thank you for your draft pull request! Do you know that you can use |
2e22891
to
f95450d
Compare
I won't have time to provide an actual code review this week, but can you describe how this would be placed in the context of #11361? Specifically, in the scheme of #11361 (comment) Also there is probably some overhead in repeatedly calling |
I think it's more in the vein of #11361 (comment) and #11361 (comment), where it was suggested that the implementation in #11361 is sufficiently different that it should be in a separate function "z_at_array", and that "z_at_value"� should just be vectorized to a fancy for-loop. No speed increase. Just a lot more convenient.
I clocked ``z_at_value` as 0.5 ms slower for a single calculation and 4 ms slower for an array of 50 |
Ah, I think I had missed that part of the discussion or did not realise that it was still pertinent for wrapping up #11361.
That's actually not measuring the overhead I had in mind – I was rather thinking about doing the setup for the minimiser method only once (when using the same method for all values) and/or vectorising the |
@dhomeier. The more I think about it, the more I agree that 'method' should not be broadcasted. I've excluded it from the broadcast. I also add a test to check whether |
6ca0935
to
f3958d8
Compare
This PR is premised on the assumption that @mhvk as a resident expert on numpy... |
@nstarman - it would definitely be good to get |
👍 See #11893 for a semi-functional example implementation. |
5f8aff7
to
b7a8b96
Compare
6920943
to
f4173a6
Compare
Ok, if all this passes, I still need to do a full docstring for |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Somewhat random comments. Does look good generally.
d1ef77b
to
4ec1bda
Compare
b9519a3
to
7daf75e
Compare
If it's approved, I'm going to squash some of my commit history. So don't merge, thanks! |
Might be safer to turn this into draft then, but up to you. Thanks! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good! Two very small comments that are easy to implement, and a question whether you even want to expose z_at_scalar_value
.
raise TypeError(f"`bracket` has dtype {bracket.dtype}, not 'O'") | ||
|
||
# make multi-dimensional iterator for all but `method`, `verbose` | ||
# TODO: figure out 'reduce_ok', so scalar returns scalar |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I thought this was now OK!?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's fixed in that I manually check for a scalar and correct the output. I think there's some way to get 'reduce_ok' to do this automatically, but I can't get the examples in the numpy documentation to work here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hence the note for myself or an enterprising contributor. Low priority, but it would be nice.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, I thought it was the problem that the code returned a 1-D array rather than an array scalar. I think reduce_ok
is really meant for dimensions that are reduced over (i.e., it tells the iterator that it is OK for a dimension to be missing or be unity in the output).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In the first example in https://numpy.org/doc/stable/reference/arrays.nditer.html#reduction-iteration it seems to work for degrading to a scalar.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Indeed, and I did not know that. But I think it is not directly relevant, since you are not actually reducing over any dimension..
docs/changes/cosmology/11778.api.rst
Outdated
@@ -0,0 +1,5 @@ | |||
Rename ``z_at_value`` to ``z_at_scalar_value`` and add a wrapper function |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The overhead from setting up the iterator is likely small compared to the actual function call, so might it make sense to just state that z_at_value
can now handle arrays? I.e., not mention z_at_scalar_value
at all?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The overhead from setting up the iterator is likely small compared to the actual function call,
That was the one clocked in #11778 (comment), right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That was a previous implementation. I'll reclock.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The extra overhead from calling z_at_value
on an array is expected? Not a serious difference, just wondering where that additional time comes in...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking at the above, I'm inclined to agree.
The point of z_at_scalar_value
public is that it's more performant. Except it basically isn't. I'm going to make it a private function. The interpolated case (#11361) should introduce a new function, perhaps z_at_interp_value
. If I can make z_at_scalar_value
more performant relative to z_at_value
, I'll make it public.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@dhomeier - list comprehension is really quite fast, hard to np.nditer
to match, with all the broadcasting etc.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The point of
z_at_scalar_value
public is that it's more performant. Except it basically isn't. I'm going to
Well, 12-15 % faster is still faster, even if perhaps not enough to justify keeping it public. What was more surprising to me was that even looping over it 100 times is still 15 % faster than calling z_at_value
directly on the value. Unless you are seeing some caching artefacts in timeit
, but I can't really see where they'd come in.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@dhomeier - list comprehension is really quite fast, hard to
np.nditer
to match, with all the broadcasting etc.
Sounds sensible – I had not looked at the internals since my early incomplete review, so I thought there was still some code that the vectorised version did not execute on every single element of fval
; but seeing now that there is also a bunch of extras included for accepting sequences of bracket
etc.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's probably from the fact that z_at_value
needs to consider how to broadcast all the values. I think if I were to do array nesting and so forth we would see that the manual implementation is equivalent to z_at_value
. z_at_value
just doesn't know when it can simplify. If python allowed for multiple dispatch..
aa1badb
to
1a1515b
Compare
Ok. Tests should pass and I've cleaned the commit history. |
1a1515b
to
d9e1ad8
Compare
d9e1ad8
to
b44fe2b
Compare
Nice! |
Signed-off-by: Nathaniel Starkman (@nstarman) nstarkman@protonmail.com
Description
z_at_value
only works on scalars.numpy.vectorize
cannot be used for broadcasting because it does not preserve units.This PR renames the current
z_at_value
toscalar_z_at_value
and the newz_at_value
correctly broadcasts inputs, callingscalar_z_at_value
for each element.Edit: this does NOT obviate the need for #11361. There is definitely good reason to have an interpolated approach for large arrays. This PR just enables broadcasting on the current function.
Fixes: #11949