Skip to content
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

MAINT: Cleanup vecdot's signature, typing, and importing #26313

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

mtsokol
Copy link
Member

@mtsokol mtsokol commented Apr 19, 2024

This PR cleans up vecdot typing, importing, and gufunc's signature. It also specifies array-api-tests vecdot failure.

@mtsokol mtsokol self-assigned this Apr 19, 2024
@ngoldbaum ngoldbaum marked this pull request as draft April 19, 2024 20:24
@ngoldbaum
Copy link
Member

(converted to draft since this looks incomplete)

@mtsokol mtsokol changed the title BUG: vecdot signature [WIP] BUG: vecdot signature Apr 29, 2024
@mtsokol mtsokol force-pushed the vecdot-signature branch 3 times, most recently from a2d2d5f to 37568cf Compare May 9, 2024 12:26
Comment on lines +55 to +56
'full', 'full_like', 'matmul', 'vecdot', 'shares_memory',
'may_share_memory', '_get_promotion_state', '_set_promotion_state']
Copy link
Member Author

Choose a reason for hiding this comment

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

I wanted vecdot to be closer to matmul in imports/__all__ as they are both gufuncs.

@mtsokol mtsokol changed the title [WIP] BUG: vecdot signature MAINT: Cleanup vecdot's signature, typing, and importing May 9, 2024
@mtsokol
Copy link
Member Author

mtsokol commented May 9, 2024

Hi @ngoldbaum,

I think I finally figured out why vecdot array-api signature test was failing with an incorrect signature.

On my macos inspect.signature(np.vecdot) (and for all ufuncs) results in:

ValueError: callable <ufunc 'vecdot'> is not supported by signature

which skips array-api signature tests. Therefore I couldn't reproduce it locally.

But when running it on a linux machine, it turns out that for all ufuncs inspect.signature(ufunc) returns:

<Signature (*args, **kwargs)>

and CI job array-api-tests suite runs on ubuntu-latest.

It turns out that the array-api-test signature test pays more attention to keyword arguments rather than positional ones. This caused np.vecdot failure, because the test expected axis keyword argument where the signature <Signature (*args, **kwargs)> is missing it. And why only np.vecdot failed out of all (g)ufuncs? Because np.vecdot is the only (g)ufunc with at least one keyword only argument 😄.

If I figured it out correctly then the test skip must stay (I updated the note explaining why it's skipped) until ufuncs have proper signatures for inspect.signature.

CC @mhvk I updated typing stubs for np.vecdot and gufunc class.

@mtsokol mtsokol marked this pull request as ready for review May 9, 2024 14:13
@mhvk
Copy link
Contributor

mhvk commented May 9, 2024

Sounds like some nice sleuthing was involved here. I'm afraid I don't understand the typing sufficiently well to comment further, though!

Copy link
Member

@ngoldbaum ngoldbaum left a comment

Choose a reason for hiding this comment

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

Ping @BvB93 for review of changes for the vecdot type hints, if you have some time.

assert_type(np.vecdot.nargs, Literal[3])
assert_type(np.vecdot.signature, Literal["(n),(n)->()"])
assert_type(np.vecdot.identity, None)
assert_type(np.vecdot(AR_f8, AR_f8), Any)
Copy link
Member

Choose a reason for hiding this comment

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

There are a bunch of other tests like this that got deleted. Why only this one now? Or just an oversight?

Copy link
Member

Choose a reason for hiding this comment

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

It would improve my confidence that the typing changes are correct if all the tests that used to be in reveal/numeric.pyi were reproduced here.

Copy link
Member Author

Choose a reason for hiding this comment

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

Tests from reveal/numeric.pyi were associated with the removed typing stubs (numpy/_core/numeric.pyi) that I added when vecdot was implemented in pure Python. Later, when vecdot was reimplemented as a gufunc the stubs should have been removed.

As of now vecdot typing stub is coming from _GUFunc_Nin2_Nout1 only, and this: assert_type(np.vecdot(AR_f8, AR_f8), Any) is the only test that is valid with the current typing (same for matmul).
I wanted to mimic matmul implementation, as they are both gufuncs.

If we want to keep removed tests then there's a question how we want to proceed: Remove GUFunc based typing stub and restore numpy/_core/numeric.pyi typing stubs (but then the same refactoring could apply to matmul and others) or do we want to stick to GUFunc typing stub.

Copy link
Member

Choose a reason for hiding this comment

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

assert_type(np.vecdot(AR_f8, AR_f8), Any) is the only test that is valid with the current typing

Can you explain a little more why e.g. assert_type(np.vecdot(AR_i8, AR_i8), npt.NDArray[np.signedinteger[Any]]) isn't valid? Is this a limitation of the automatically generated typing for gufuncs?

If so, it sounds like the hand-written type overrides for vecdot should be used and similar overrides should be written for matmul, or the automatically generated typing should be improved to capture the semantics of the old hand-written types. Users might write types using those in numpy 2.0 (unless you're looking to backport this to 2.0, which might not be possible given timing) so we shouldn't make the types less expressive or possibly break typing tests by changing semantics.

I'll defer to @BvB93 or others who are more experienced dealing with types about all this though.

Copy link
Member Author

Choose a reason for hiding this comment

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

IIUC it's a limitation of GUFunc typing stub. For me we can keep vecdot overrides as before.

@overload
def vecdot(
x1: _ArrayLikeObject_co, x2: _ArrayLikeObject_co, axis: int = ...
) -> NDArray[object_]: ...
Copy link
Member

Choose a reason for hiding this comment

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

Why can these type annotations be deleted?

Copy link
Member

Choose a reason for hiding this comment

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

Ah because vecdot is a ufunc now and ufunc.pyi handles it for us, right?

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes! For example there is no def matmul(...) in pyi files.

# TODO: check why in CI `inspect.signature(np.vecdot)` returns (*arg, **kwarg)
# instead of raising ValueError. mtsokol: couldn't reproduce locally
# ufuncs signature on linux is always <Signature (*args, **kwargs)>
# np.vecdot is the only ufunc with a keyword argument which causes a failure
Copy link
Member

Choose a reason for hiding this comment

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

Do the array API tests also check that vecdot's signature is correct using duck typing? Probably worth doing both - check the signature and validate that the signature is correct!

Copy link
Member Author

Choose a reason for hiding this comment

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

There is test_signatures.py in array-api-tests suite for testing signatures. Separately, functions are tested by calling them with args+kwargs, like test_vecdot in test_linalg.py.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants