-
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Add support for cross product #5365
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
Changes from 6 commits
1490c16
03db734
c824e36
7ce39c7
916e661
654ad60
a6ac578
e0c1fac
7aebae7
b85e236
2b54a42
be7b2c2
4448006
af8b09c
a135e05
6f17b9b
1fadb5f
57239a4
265ef82
dd60562
a20cb86
7ce9315
d5a0ea8
ef94fa4
1a85147
2ce3dbe
53c84c2
dded720
7058166
cb57a55
e69ca81
4b2fc72
afe572d
e137350
1a26324
531a98b
2146406
0940472
a7cc565
1d1f205
9af7091
14decb3
6f73c32
72330ce
bce2f3e
1636d25
b5b97a0
f77780f
02364ca
e842c75
ed44400
4fe9737
ec05780
36c5956
cbf289c
4cfd5be
658a59f
ab5ae20
d65ca41
20eef03
274af32
f352303
0a773cb
d8da29f
54a76c1
0a2dc2e
b3592f3
06772da
cfd11f7
8451a9e
90553ed
6eed96e
d3648e5
c639aa3
4c636f5
3bea936
4fc7fcb
19e8f93
f71a6f1
d4070ab
12da913
ea062e6
ebd89e6
3c7122b
9af1198
27262e6
cc91e7c
629df59
972c7dc
3c4ace0
49967d4
6ab7d19
20a6cb6
ba3fa9c
8b192f2
a27965c
5ec65d2
b058084
f007ed5
e88ae9d
9aaee2b
5d6ecba
71fc9c1
a98b2e3
c95817b
408eb39
316b935
3b5b030
f9c5404
34b300d
cf13bf9
f2167a6
570a806
6f57ed6
52a986b
fa78e74
f2d98b6
7449cd7
70d2a4b
e6020e3
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -1527,6 +1527,132 @@ def dot(*arrays, dims=None, **kwargs): | |||||
| return result.transpose(*[d for d in all_dims if d in result.dims]) | ||||||
|
|
||||||
|
|
||||||
| def cross(a, b, spatial_dim=None): | ||||||
| """ | ||||||
| Return the cross product of two (arrays of) vectors. | ||||||
Illviljan marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||||||
|
|
||||||
| Parameters | ||||||
| ---------- | ||||||
| a : array_like | ||||||
Illviljan marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||||||
| Components of the first vector(s). | ||||||
| b : array_like | ||||||
| Components of the second vector(s). | ||||||
| spatial_dim : something | ||||||
|
||||||
| spatial_dim : something | |
| dim : hashable or tuple of hashable |
and we could also accept a name for the output dimension (with a default, e.g. "cross")
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.
My intuition for the cross product is lost once we go beyond cartesian dims. But what does it even mean if we do np.cross(a(cartesian), b(something_else))? Or shall I just accept it as math-magics with arrays that have the correct length? I'm used to that too...
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 meant that the 2 or 3 element dimension might be named differently for a and b:
a = xr.DataArray([[0, 1, 2], [3, 4, 5], [7, 5, 3]], dims=("dim_0", "dim_1"))
b = xr.DataArray([[1, 4, 2], [8, 1, 3], [5, 4, 9]], dims=("x", "y"))
xr.cross(a, b, dim=("dim_1", "y"))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.
But are dim_1 and y actually different things or is it a typo made by the user?
I just want to argue that since we have named dims and do all the necessary reshaping behind the scenes we don't need these extra options.
But I suppose I can think of it like this: dim_1 is a alias of y, so dim=(dim_1, y) is basically just adding aliases of the same thing.
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.
Another thing to think about if we want to accept different dims, what to do when they have different values?
a = xr.DataArray(
[[0, 1, 2], [3, 4, 5]],
dims=("dim_0", "dim_1"),
coords=dict(dim_0=(["dim_0", [1, 2]]), dim_1=(["dim_1"], ["u", "v", "w"])),
)
b = xr.DataArray(
[[1, 4, 2], [8, 1, 3]],
dims=("time", "cartesian"),
coords=dict(time=(["time", [0, 1]]), cartesian=(["cartesian"], ["x", "y", "z"])),
)
xr.cross(a, b, dim=("dim_1", "y"))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.
as far as I can tell, this would work with:
In [2]: xr.set_options(keep_attrs=True)
...:
...: ds = xr.tutorial.open_dataset("eraint_uvz")
...:
...: arr = ds.to_stacked_array(variable_dim="cartesian", new_dim="variable", sample_dims=ds.dims).unstack("variable")
...: other_ds = arr.stack(variable=["cartesian"]).to_unstacked_dataset("variable")
...: xr.testing.assert_equal(ds, other_ds)Maybe that would be a fit for
ds.cross()?
Maybe, but usually top-level functions accept both DataArray and Dataset objects (not sure if this can / should be an exception?).
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.
@keewis, found a dataset example here that I'm not sure how to handle, any ideas?
ds = xr.Dataset({0: ("dim_0", [1]), 1: ("dim_0", [2]), 2: ("dim_0", [3])})
arr = ds.to_stacked_array(variable_dim="cartesian", new_dim="variable", sample_dims=ds.dims).unstack("variable")
other_ds = arr.stack(variable=["cartesian"]).to_unstacked_dataset("variable")
xr.testing.assert_equal(ds, other_ds)
AssertionError: Left and right Dataset objects are not equal
Differing dimensions:
(dim_0: 1) != ()
Differing data variables:
L 0 (dim_0) int32 1
R 0 int32 1
L 1 (dim_0) int32 2
R 1 int32 2
L 2 (dim_0) int32 3
R 2 int32 3There 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.
sorry for the late reply.
yes, exactly. I'm somewhat uncomfortable with the big loop over the input objects, but I'm not sure what I would suggest instead.
found a dataset example here that I'm not sure how to handle
yes, 1-sized dimensions can be tricky because they tend to lose their status as a dimension. We can try to use expand_dims to get back the original dims:
other_ds.expand_dims([dim for dim, size in ds.sizes.items() if size == 1])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.
Here's another case I've been pondering about, should different dims be allowed?
a = xr.Dataset({0: ("dim_0", [1]), 1: ("dim_0", [2]), 2: ("dim_0", [3])})
b = xr.Dataset({0: ("dim_1", [4]), 1: ("dim_1", [5]), 2: ("dim_1", [6])})
c = xr.cross(a, b, "temp_dim")How should c look like? Should it behave like a*b?
a*b
Out[25]:
<xarray.Dataset>
Dimensions: (dim_0: 1, dim_1: 1)
Dimensions without coordinates: dim_0, dim_1
Data variables:
0 (dim_0, dim_1) int32 4
1 (dim_0, dim_1) int32 10
2 (dim_0, dim_1) int32 18In bce2f3e it follows the a*b style which is also consistent when size>1.
Uh oh!
There was an error while loading. Please reload this page.