-
Notifications
You must be signed in to change notification settings - Fork 2.5k
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
[0.46] Finalise support for Numpy 2.0 #12189
Merged
Merged
Conversation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This commit brings the Qiskit test suite to a passing state (with all optionals installed) with Numpy 2.0.0b1, building on previous commits that handled much of the rest of the changing requirements: - Qiskitgh-10890 - Qiskitgh-10891 - Qiskitgh-10892 - Qiskitgh-10897 - Qiskitgh-11023 Notably, this commit did not actually require a rebuild of Qiskit, despite us compiling against Numpy; it seems to happen that the C API stuff we use via `rust-numpy` (which loads the Numpy C extensions dynamically during module initialisation) hasn't changed. The main changes are: - adapting to the changed `copy=None` and `copy=False` semantics in `array` and `asarray`. - making sure all our implementers of `__array__` accept both `dtype` and `copy` arguments. Co-authored-by: Lev S. Bishop <18673315+levbishop@users.noreply.github.com>
As of Numpy 2.0, implementers of `__array__` are expected and required to have a signature def __array__(self, dtype=None, copy=None): ... In Numpys before 2.0, the `copy` argument will never be passed, and the expected signature was def __array__(self, dtype=None): ... Because of this, we have latitude to set `copy` in our implementations to anything we like if we're running against Numpy 1.x, but we should default to `copy=None` if we're running against Numpy 2.0. The semantics of the `copy` argument to `np.array` changed in Numpy 2.0. Now, `copy=False` means "raise a `ValueError` if a copy is required" and `copy=None` means "copy only if required". In Numpy 1.x, `copy=False` meant "copy only if required". In _both_ Numpy 1.x and 2.0, `ndarray.astype` takes a `copy` argument, and in both, `copy=False` means "copy only if required". In Numpy 2.0 only, `np.asarray` gained a `copy` argument with the same semantics as the `np.array` copy argument from Numpy 2.0. Further, the semantics of the `__array__` method changed in Numpy 2.0, particularly around copying. Now, Numpy will assume that it can pass `copy=True` and the implementer will handle this. If `copy=False` is given and a copy or calculation is required, then the implementer is required to raise `ValueError`. We have a few places where the `__array__` method may (or always does) calculate the array, so in all these, we must forbid `copy=False`. With all this in mind: this PR sets up all our implementers of `__array__` to either default to `copy=None` if they will never actually need to _use_ the `copy` argument within themselves (except perhaps to test if it was set by Numpy 2.0 to `False`, as Numpy 1.x will never set it), or to a compatibility shim `_numpy_compat.COPY_ONLY_IF_NEEDED` if they do naturally want to use it with those semantics. The pattern def __array__(self, dtype=None, copy=_numpy_compat.COPY_ONLY_IF_NEEDED): dtype = self._array.dtype if dtype is None else dtype return np.array(self._array, dtype=dtype, copy=copy) using `array` instead of `asarray` lets us achieve all the desired behaviour between the interactions of `dtype` and `copy` in a way that is compatible with both Numpy 1.x and 2.x.
One or more of the the following people are requested to review this:
|
raynelfss
approved these changes
Jun 18, 2024
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.
LGTM, thank you for working on this.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Labels
Changelog: New Feature
Include in the "Added" section of the changelog
dependencies
Pull requests that update a dependency file
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Summary
This commit brings the Qiskit test suite to a passing state (with all optionals installed) with Numpy 2.0.0b1, building on previous commits that handled much of the rest of the changing requirements:
numpy.lib.scimath
with preferrednumpy.emath
#10892NormalizeRXAngles
#11023Notably, this commit did not actually require a rebuild of Qiskit, despite us compiling against Numpy; it seems to happen that the C API stuff we use via
rust-numpy
(which loads the Numpy C extensions dynamically during module initialisation) hasn't changed.The main changes are:
copy=None
andcopy=False
semantics inarray
andasarray
.__array__
accept bothdtype
andcopy
arguments.Co-authored-by: Lev S. Bishop 18673315+levbishop@users.noreply.github.com
Update
__array__
methods for Numpy 2.0 compatibilityAs of Numpy 2.0, implementers of
__array__
are expected and required to have a signatureIn Numpys before 2.0, the
copy
argument will never be passed, and the expected signature wasBecause of this, we have latitude to set
copy
in our implementations to anything we like if we're running against Numpy 1.x, but we should default tocopy=None
if we're running against Numpy 2.0.The semantics of the
copy
argument tonp.array
changed in Numpy 2.0. Now,copy=False
means "raise aValueError
if a copy is required" andcopy=None
means "copy only if required". In Numpy 1.x,copy=False
meant "copy only if required". In both Numpy 1.x and 2.0,ndarray.astype
takes acopy
argument, and in both,copy=False
means "copy only if required". In Numpy 2.0 only,np.asarray
gained acopy
argument with the same semantics as thenp.array
copy argument from Numpy 2.0.Further, the semantics of the
__array__
method changed in Numpy 2.0, particularly around copying. Now, Numpy will assume that it can passcopy=True
and the implementer will handle this. Ifcopy=False
is given and a copy or calculation is required, then the implementer is required to raiseValueError
. We have a few places where the__array__
method may (or always does) calculate the array, so in all these, we must forbidcopy=False
.With all this in mind: this PR sets up all our implementers of
__array__
to either default tocopy=None
if they will never actually need to use thecopy
argument within themselves (except perhaps to test if it was set by Numpy 2.0 toFalse
, as Numpy 1.x will never set it), or to a compatibility shim_numpy_compat.COPY_ONLY_IF_NEEDED
if they do naturally want to use it with those semantics. The patternusing
array
instead ofasarray
lets us achieve all the desired behaviour between the interactions ofdtype
andcopy
in a way that is compatible with both Numpy 1.x and 2.x.Details and comments
This is the spiritual backport of #11999.