8000 BUG: np.cross() warns about arrays of vectors when used with two simple 2-d vectors · Issue #26620 · numpy/numpy · GitHub
[go: up one dir, main page]

Skip to content

BUG: np.cross() warns about arrays of vectors when used with two simple 2-d vectors #26620

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

Open
megies opened this issue Jun 5, 2024 · 9 comments

Comments

@megies
Copy link
Contributor
megies commented Jun 5, 2024

Describe the issue:

np.cross() warns about arrays of vectors when used with simply two 2-d vectors (this use case is even in the "Examples" section of np.cross() docstring). I believe, that check whether a warning should be shown is missing a check for number of dimensions of the input.

numpy/numpy/_core/numeric.py

Lines 1645 to 1653 in 42e9aa2

if a.shape[-1] not in (2, 3) or b.shape[-1] not in (2, 3):
raise ValueError(msg)
if a.shape[-1] == 2 or b.shape[-1] == 2:
# Deprecated in NumPy 2.0, 2023-09-26
warnings.warn(
"Arrays of 2-dimensional vectors are deprecated. Use arrays of "
"3-dimensional vectors instead. (deprecated in NumPy 2.0)",
DeprecationWarning, stacklevel=2
)

I feel like there should be a change, either

  • change the warning message to something like '2-dimensional vectors are deprecated. Use 3-dimensional vectors instead.' without the 'Arrays of..' parts, or..
  • the check whether the warning should be shown or not should also check if a.ndim > 1 or b.ndim > 1

Tbh, I'm a bit confused what that warning is implying as recommended usage anyway. Is the user supposed to add an all-zero third dimension for 2-d vectors and then calculate cross product in 3-d and then extract the valid part from it? That seems kinda odd-looking, I guess if that really is the case it looks like this prompts to look at #13718 again potentially?

So instead of..

x = [[1, 2], [1, 2]]
y = [[4, 5], [4, 5]]
result = np.cross(x, y)

user should do something like..?

x = [[1, 2, 0], [1, 2, 0]]
y = [[4, 5, 0], [4, 5, 0]]
result = np.cross(x, y)[:, -1]

Reproduce the code example:

import numpy as np

x = [1, 2]
y = [4, 5]
# the next line shows a warning, even though it's even from the docstring examples section
np.cross(x, y)

Error message:

DeprecationWarning: Arrays of 2-dimensional vectors are deprecated. Use arrays of 3-dimensional vectors instead. (deprecated in NumPy 2.0)

Python and NumPy Versions:

2.0.0rc2
3.10.14 | packaged by conda-forge | (main, Mar 20 2024, 12:45:18) [GCC 12.3.0]

Runtime Environment:

[{'numpy_version': '2.0.0rc2',
  'python': '3.10.14 | packaged by conda-forge | (main, Mar 20 2024, 12:45:18) '
            '[GCC 12.3.0]',
  'uname': uname_result(system='Linux', node='mother', release='5.10.0-25-amd64', version='#1 SMP Debian 5.10.191-1 (2023-08-16)', machine='x86_64')},
 {'simd_extensions': {'baseline': ['SSE', 'SSE2', 'SSE3'],
                      'found': ['SSSE3',
                                'SSE41',
                                'POPCNT',
                                'SSE42',
                                'AVX',
                                'F16C',
                                'FMA3',
                                'AVX2',
                                'AVX512F',
                                'AVX512CD',
                                'AVX512_SKX',
                                'AVX512_CLX',
                                'AVX512_CNL',
                                'AVX512_ICL'],
                      'not_found': ['AVX512_KNL', 'AVX512_KNM', 'AVX512_SPR']}},
 {'architecture': 'SkylakeX',
  'filepath': '/home/megies/miniconda3/envs/np2/lib/libopenblasp-r0.3.27.so',
  'internal_api': 'openblas',
  'num_threads': 8,
  'prefix': 'libopenblas',
  'threading_layer': 'pthreads',
  'user_api': 'blas',
  'version': '0.3.27'}]

Context for the issue:

In our testsuite, we also have a test runner with pytest -W error to make sure our code is not causing deprecation warnings in order to keep our code base work with upcoming releases of dependencies. And that's where this deprecation warning came up.

@megies megies added the 00 - Bug label Jun 5, 2024
@seberg seberg added this to the 2.0.0 release milestone Jun 5, 2024
@seberg
Copy link
Member
seberg commented Jun 5, 2024

Ref #24818, does anyone know what the argument/reasoning for this was?

  • Avoid variable number of result dimensions?
  • Deprecated cross([0, 1], [1, 2, 3]) from working?

@seberg
Copy link
Member
seberg commented Jun 5, 2024

OK, since I missed it there. The issue is the first thing and the reasoning is in #13718 which suggested a cross2d, though.

@seberg
Copy link
Member
seberg commented Jun 5, 2024

We had a bit of a discussing, we should definitely tell people to use this (I think it is right):

cross2d = arr1[..., 0] * arr2[..., 1] - arr1[..., 1] * arr2[..., 0]

And maybe even document it in the text. The original issue had cross2d, and if a lot of people use the 2d version, then it might be nice to have it as np.linalg.cross2d. If that was clear now, I might prefer to not do the deprecation as quickly, because you cannot use cross2d until it exists (and is established).

bmwoodruff added a commit to bmwoodruff/numpy that referenced this issue Jun 7, 2024
This PR stems from the community meeting on Jun 5, 2024.
This implements a new function cross2d that accepts (a stack of)
2-element vectors, in the same manner that cross currently does.
Both np.cross2d and np.linalg.cross2d are added.
The np.linalg.cross2d is API compatible.
This PR closes numpy#13718 and closes numpy#26620.
Units tests for cross2d are included.
A new test_ValueError is added for cross.
Updated doc links for both funtions.
Added examples for cross2d. Cleaned up whitespace on both functions.
bmwoodruff added a commit to bmwoodruff/numpy that referenced this issue Jun 7, 2024
This PR stems from the community meeting on Jun 5, 2024.
This implements a new function cross2d that accepts (a stack of)
2-element vectors, in the same manner that cross currently does.
Both np.cross2d and np.linalg.cross2d are added.
The function np.linalg.cross2d is Array API compatible.
This PR closes numpy#13718 and closes numpy#26620.
Units tests for cross2d are included.
A new test_ValueError is added for cross.
Updated doc links for both funtions and linked to .rst.
Added examples for cross2d. Cleaned up whitespace on both functions.
Adjusted examples in cross to show how to avoid deprecation warning.
Adds an example to compare cross2d with (floating point) det.
Includes a release note.
@rgommers
Copy link
Member

The original issue had cross2d, and if a lot of people use the 2d version, then it might be nice to have it as np.linalg.cross2d. If that was clear now, I might prefer to not do the deprecation as quickly, because you cannot use cross2d until it exists (and is established).

It looks like linalg.cross2d is moving ahead, although the need is still slightly on the thin side. I'm -1 on changing our mind on the deprecation at the very last moment, since that has downsides and since clearly this isn't used a lot - it took ~6 months after gh-25145 got merged and almost 3 months after 2.0.0b1 was out for someone to notice.

Let's verify the one-liner above as a workaround (it seems right), and add that to the docstring as a compat note, and backport it to the 2.0.x branch. That should be easy and safe to do in the next few days.

rgommers added a commit to rgommers/numpy that referenced this issue Jun 14, 2024
This addresses a part of numpygh-26620. The one-liner was verified and
is likely to be used in a future `np.linalg.cross2d` function
implementation, in numpygh-26640.

[skip actions] [skip azp] [skip cirrus]
@rgommers
Copy link
Member

Once gh-26692 is backported to the 2.0.x branch, the milestone on this can be removed.

rgommers added a commit to rgommers/numpy that referenced this issue Jun 14, 2024
This addresses a part of numpygh-26620. The one-liner was verified and
is likely to be used in a future `np.linalg.cross2d` function
implementation, in numpygh-26640.

[skip actions] [skip azp] [skip cirrus]
charris pushed a commit to charris/numpy that referenced this issue Jun 14, 2024
This addresses a part of numpygh-26620. The one-liner was verified and
is likely to be used in a future `np.linalg.cross2d` function
implementation, in numpygh-26640.

[skip actions] [skip azp] [skip cirrus]
@charris charris removed this from the 2.0.0 release milestone Jun 15, 2024
@Daniel63656
Copy link

Having the same issue. Why wouldn't cross() be abstract enough to handle 2d and 3d without the user having to differentiate

@leycec
Copy link
leycec commented Sep 13, 2024

lol. So, numpy.linalg.cross2d() never happened. Now numpy.linalg.cross() emits unhelpful deprecation warnings for the previously valid two-dimensional use case that fail to actually inform the end user of how to resolve the deprecation. If a use case requires two dimensions, telling end users to "just use three dimensions instead" isn't really a useful recommendation. In short, this is basically useless:

DeprecationWarning: Arrays of 2-dimensional vectors are deprecated.
Use arrays of 3-dimensional vectors instead. (deprecated in NumPy 2.0)

That's a hard UX fail. Simply hand-waving that away as "fine for certain definitions of fine" because users failed to test against NumPy pre-releases like 2.0.0b1 isn't a reasonable justification, either. Of course users failed to test against NumPy pre-releases. They're pre-releases! Without compelling reasons to install third-party pre-releases, users (...waitforit) do not install third-party pre-releases. Why would they? It's needless work for no real-world gain and significant pain.

tl;dr

In short, the existing DeprecationWarning:

  • (A) Is less than useless. 2D code doesn't magically become 3D code just because you tell it to become 3D code. Yes, that's exactly what the existing DeprecationWarning is telling everybody. </facepalm>
  • (B) Should be entirely rewritten to reflect the trivial one-liner identified above by @seberg. Something resembling the following would actually be useful: e.g.,
DeprecationWarning: np.cross() no longer supports 2-dimensional vectors.
Replace all np.cross() calls over 2-dimensional vectors with one-liners:
    cross2d = arr1[..., 0] * arr2[..., 1] - arr1[..., 1] * arr2[..., 0]

I shake my head, fam. I shake it hard. 😮‍💨

stefmolin added a commit to stefmolin/data-morph that referenced this issue Oct 5, 2024
* Address numpy 2.0 warning: numpy/numpy#26620
* Address issue with codecov uploading: codecov/codecov-action#1274
ArvidJB pushed a commit to ArvidJB/numpy that referenced this issue Nov 1, 2024
This addresses a part of numpygh-26620. The one-liner was verified and
is likely to be used in a future `np.linalg.cross2d` function
implementation, in numpygh-26640.

[skip actions] [skip azp] [skip cirrus]
@burnpanck
Copy link

Pity that np.linalg.cross2d never happened. While the oneliner is trivial to write when the inputs are arrays, if the inputs are expressions, the one-liner becomes a three-liner! Its of course doable, but having a true one-liner for the "2d cross product" around is a great nice-to-have for any 2D geometry task.

@cslotboom
Copy link

This has also affected me. Converting all my 2D vectors to 3D vectors with an empty row just to cross multiply feels like a pretty clunky work around, I'd strongly prefer not to do that if it's in the cards.

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

Successfully merging a pull request may close this issue.

9 participants
0