Skip to content
项目
群组
代码片段
帮助
当前项目
正在载入...
登录 / 注册
切换导航面板
P
pytensor
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
图表
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
日程
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
图像
聊天
创建新问题
作业
提交
问题看板
Open sidebar
testgroup
pytensor
Commits
ae388840
提交
ae388840
authored
7月 02, 2025
作者:
Allen Downey
提交者:
Ricardo Vieira
7月 03, 2025
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Add full_like, ones_like, and zeros_like for XTensorVariable (#1514)
上级
815671d5
隐藏空白字符变更
内嵌
并排
正在显示
4 个修改的文件
包含
271 行增加
和
3 行删除
+271
-3
__init__.py
pytensor/xtensor/__init__.py
+1
-1
shape.py
pytensor/xtensor/shape.py
+98
-0
test_shape.py
tests/xtensor/test_shape.py
+151
-0
util.py
tests/xtensor/util.py
+21
-2
没有找到文件。
pytensor/xtensor/__init__.py
浏览文件 @
ae388840
...
@@ -3,7 +3,7 @@ import warnings
...
@@ -3,7 +3,7 @@ import warnings
import
pytensor.xtensor.rewriting
import
pytensor.xtensor.rewriting
from
pytensor.xtensor
import
linalg
,
random
from
pytensor.xtensor
import
linalg
,
random
from
pytensor.xtensor.math
import
dot
from
pytensor.xtensor.math
import
dot
from
pytensor.xtensor.shape
import
broadcast
,
concat
from
pytensor.xtensor.shape
import
broadcast
,
concat
,
full_like
,
ones_like
,
zeros_like
from
pytensor.xtensor.type
import
(
from
pytensor.xtensor.type
import
(
as_xtensor
,
as_xtensor
,
xtensor
,
xtensor
,
...
...
pytensor/xtensor/shape.py
浏览文件 @
ae388840
...
@@ -13,6 +13,7 @@ from pytensor.tensor.exceptions import NotScalarConstantError
...
@@ -13,6 +13,7 @@ from pytensor.tensor.exceptions import NotScalarConstantError
from
pytensor.tensor.type
import
integer_dtypes
from
pytensor.tensor.type
import
integer_dtypes
from
pytensor.tensor.utils
import
get_static_shape_from_size_variables
from
pytensor.tensor.utils
import
get_static_shape_from_size_variables
from
pytensor.xtensor.basic
import
XOp
from
pytensor.xtensor.basic
import
XOp
from
pytensor.xtensor.math
import
cast
,
second
from
pytensor.xtensor.type
import
XTensorVariable
,
as_xtensor
,
xtensor
from
pytensor.xtensor.type
import
XTensorVariable
,
as_xtensor
,
xtensor
from
pytensor.xtensor.vectorization
import
combine_dims_and_shape
from
pytensor.xtensor.vectorization
import
combine_dims_and_shape
...
@@ -565,3 +566,100 @@ def broadcast(
...
@@ -565,3 +566,100 @@ def broadcast(
raise
TypeError
(
f
"exclude must be None, str, or Sequence, got {type(exclude)}"
)
raise
TypeError
(
f
"exclude must be None, str, or Sequence, got {type(exclude)}"
)
# xarray broadcast always returns a tuple, even if there's only one tensor
# xarray broadcast always returns a tuple, even if there's only one tensor
return
tuple
(
Broadcast
(
exclude
=
exclude
)(
*
args
,
return_list
=
True
))
# type: ignore
return
tuple
(
Broadcast
(
exclude
=
exclude
)(
*
args
,
return_list
=
True
))
# type: ignore
def
full_like
(
x
,
fill_value
,
dtype
=
None
):
"""Create a new XTensorVariable with the same shape and dimensions, filled with a specified value.
Parameters
----------
x : XTensorVariable
The tensor to fill.
fill_value : scalar or XTensorVariable
The value to fill the new tensor with.
dtype : str or np.dtype, optional
The data type of the new tensor. If None, uses the dtype of the input tensor.
Returns
-------
XTensorVariable
A new tensor with the same shape and dimensions as self, filled with fill_value.
Examples
--------
>>> from pytensor.xtensor import xtensor, full_like
>>> x = xtensor(dtype="float64", dims=("a", "b"), shape=(2, 3))
>>> y = full_like(x, 5.0)
>>> assert y.dims == ("a", "b")
>>> assert y.type.shape == (2, 3)
"""
x
=
as_xtensor
(
x
)
fill_value
=
as_xtensor
(
fill_value
)
# Check that fill_value is a scalar (ndim=0)
if
fill_value
.
type
.
ndim
!=
0
:
raise
ValueError
(
f
"fill_value must be a scalar, got ndim={fill_value.type.ndim}"
)
# Handle dtype conversion
if
dtype
is
not
None
:
# If dtype is specified, cast the fill_value to that dtype
fill_value
=
cast
(
fill_value
,
dtype
)
else
:
# If dtype is None, cast the fill_value to the input tensor's dtype
# This matches xarray's behavior where it preserves the original dtype
fill_value
=
cast
(
fill_value
,
x
.
type
.
dtype
)
# Use the xtensor second function
return
second
(
x
,
fill_value
)
def
ones_like
(
x
,
dtype
=
None
):
"""Create a new XTensorVariable with the same shape and dimensions, filled with ones.
Parameters
----------
x : XTensorVariable
The tensor to fill.
dtype : str or np.dtype, optional
The data type of the new tensor. If None, uses the dtype of the input tensor.
Returns:
XTensorVariable
A new tensor with the same shape and dimensions as self, filled with ones.
Examples
--------
>>> from pytensor.xtensor import xtensor, full_like
>>> x = xtensor(dtype="float64", dims=("a", "b"), shape=(2, 3))
>>> y = ones_like(x)
>>> assert y.dims == ("a", "b")
>>> assert y.type.shape == (2, 3)
"""
return
full_like
(
x
,
1.0
,
dtype
=
dtype
)
def
zeros_like
(
x
,
dtype
=
None
):
"""Create a new XTensorVariable with the same shape and dimensions, filled with zeros.
Parameters
----------
x : XTensorVariable
The tensor to fill.
dtype : str or np.dtype, optional
The data type of the new tensor. If None, uses the dtype of the input tensor.
Returns:
XTensorVariable
A new tensor with the same shape and dimensions as self, filled with zeros.
Examples
--------
>>> from pytensor.xtensor import xtensor, full_like
>>> x = xtensor(dtype="float64", dims=("a", "b"), shape=(2, 3))
>>> y = zeros_like(x)
>>> assert y.dims == ("a", "b")
>>> assert y.type.shape == (2, 3)
"""
return
full_like
(
x
,
0.0
,
dtype
=
dtype
)
tests/xtensor/test_shape.py
浏览文件 @
ae388840
...
@@ -11,13 +11,19 @@ import numpy as np
...
@@ -11,13 +11,19 @@ import numpy as np
from
xarray
import
DataArray
from
xarray
import
DataArray
from
xarray
import
broadcast
as
xr_broadcast
from
xarray
import
broadcast
as
xr_broadcast
from
xarray
import
concat
as
xr_concat
from
xarray
import
concat
as
xr_concat
from
xarray
import
full_like
as
xr_full_like
from
xarray
import
ones_like
as
xr_ones_like
from
xarray
import
zeros_like
as
xr_zeros_like
from
pytensor.tensor
import
scalar
from
pytensor.tensor
import
scalar
from
pytensor.xtensor.shape
import
(
from
pytensor.xtensor.shape
import
(
broadcast
,
broadcast
,
concat
,
concat
,
full_like
,
ones_like
,
stack
,
stack
,
unstack
,
unstack
,
zeros_like
,
)
)
from
pytensor.xtensor.type
import
xtensor
from
pytensor.xtensor.type
import
xtensor
from
tests.xtensor.util
import
(
from
tests.xtensor.util
import
(
...
@@ -633,3 +639,148 @@ class TestBroadcast:
...
@@ -633,3 +639,148 @@ class TestBroadcast:
]
]
for
res
,
expected_res
in
zip
(
results
,
expected_results
,
strict
=
True
):
for
res
,
expected_res
in
zip
(
results
,
expected_results
,
strict
=
True
):
xr_assert_allclose
(
res
,
expected_res
)
xr_assert_allclose
(
res
,
expected_res
)
def
test_full_like
():
"""Test full_like function, comparing with xarray's full_like."""
# Basic functionality with scalar fill_value
x
=
xtensor
(
"x"
,
dims
=
(
"a"
,
"b"
),
shape
=
(
2
,
3
),
dtype
=
"float64"
)
x_test
=
xr_arange_like
(
x
)
y1
=
full_like
(
x
,
5.0
)
fn1
=
xr_function
([
x
],
y1
)
result1
=
fn1
(
x_test
)
expected1
=
xr_full_like
(
x_test
,
5.0
)
xr_assert_allclose
(
result1
,
expected1
,
check_dtype
=
True
)
# Other dtypes
x_3d
=
xtensor
(
"x_3d"
,
dims
=
(
"a"
,
"b"
,
"c"
),
shape
=
(
2
,
3
,
4
),
dtype
=
"float32"
)
x_3d_test
=
xr_arange_like
(
x_3d
)
y7
=
full_like
(
x_3d
,
-
1.0
)
fn7
=
xr_function
([
x_3d
],
y7
)
result7
=
fn7
(
x_3d_test
)
expected7
=
xr_full_like
(
x_3d_test
,
-
1.0
)
xr_assert_allclose
(
result7
,
expected7
,
check_dtype
=
True
)
# Integer dtype
y3
=
full_like
(
x
,
5.0
,
dtype
=
"int32"
)
fn3
=
xr_function
([
x
],
y3
)
result3
=
fn3
(
x_test
)
expected3
=
xr_full_like
(
x_test
,
5.0
,
dtype
=
"int32"
)
xr_assert_allclose
(
result3
,
expected3
,
check_dtype
=
True
)
# Different fill_value types
y4
=
full_like
(
x
,
np
.
array
(
3.14
))
fn4
=
xr_function
([
x
],
y4
)
result4
=
fn4
(
x_test
)
expected4
=
xr_full_like
(
x_test
,
3.14
)
xr_assert_allclose
(
result4
,
expected4
,
check_dtype
=
True
)
# Integer input with float fill_value
x_int
=
xtensor
(
"x_int"
,
dims
=
(
"a"
,
"b"
),
shape
=
(
2
,
3
),
dtype
=
"int32"
)
x_int_test
=
DataArray
(
np
.
arange
(
6
,
dtype
=
"int32"
)
.
reshape
(
2
,
3
),
dims
=
(
"a"
,
"b"
))
y5
=
full_like
(
x_int
,
2.5
)
fn5
=
xr_function
([
x_int
],
y5
)
result5
=
fn5
(
x_int_test
)
expected5
=
xr_full_like
(
x_int_test
,
2.5
)
xr_assert_allclose
(
result5
,
expected5
,
check_dtype
=
True
)
# Symbolic shapes
x_sym
=
xtensor
(
"x_sym"
,
dims
=
(
"a"
,
"b"
),
shape
=
(
None
,
3
))
x_sym_test
=
DataArray
(
np
.
arange
(
6
,
dtype
=
x_sym
.
type
.
dtype
)
.
reshape
(
2
,
3
),
dims
=
(
"a"
,
"b"
)
)
y6
=
full_like
(
x_sym
,
7.0
)
fn6
=
xr_function
([
x_sym
],
y6
)
result6
=
fn6
(
x_sym_test
)
expected6
=
xr_full_like
(
x_sym_test
,
7.0
)
xr_assert_allclose
(
result6
,
expected6
,
check_dtype
=
True
)
# Boolean dtype
x_bool
=
xtensor
(
"x_bool"
,
dims
=
(
"a"
,
"b"
),
shape
=
(
2
,
3
),
dtype
=
"bool"
)
x_bool_test
=
DataArray
(
np
.
array
([[
True
,
False
,
True
],
[
False
,
True
,
False
]]),
dims
=
(
"a"
,
"b"
)
)
y8
=
full_like
(
x_bool
,
True
)
fn8
=
xr_function
([
x_bool
],
y8
)
result8
=
fn8
(
x_bool_test
)
expected8
=
xr_full_like
(
x_bool_test
,
True
)
xr_assert_allclose
(
result8
,
expected8
,
check_dtype
=
True
)
# Complex dtype
x_complex
=
xtensor
(
"x_complex"
,
dims
=
(
"a"
,
"b"
),
shape
=
(
2
,
3
),
dtype
=
"complex64"
)
x_complex_test
=
DataArray
(
np
.
arange
(
6
,
dtype
=
"complex64"
)
.
reshape
(
2
,
3
),
dims
=
(
"a"
,
"b"
)
)
y9
=
full_like
(
x_complex
,
1
+
2
j
)
fn9
=
xr_function
([
x_complex
],
y9
)
result9
=
fn9
(
x_complex_test
)
expected9
=
xr_full_like
(
x_complex_test
,
1
+
2
j
)
xr_assert_allclose
(
result9
,
expected9
,
check_dtype
=
True
)
# Symbolic fill value
x_sym_fill
=
xtensor
(
"x_sym_fill"
,
dims
=
(
"a"
,
"b"
),
shape
=
(
2
,
3
),
dtype
=
"float64"
)
fill_val
=
xtensor
(
"fill_val"
,
dims
=
(),
shape
=
(),
dtype
=
"float64"
)
x_sym_fill_test
=
xr_arange_like
(
x_sym_fill
)
fill_val_test
=
DataArray
(
3.14
,
dims
=
())
y10
=
full_like
(
x_sym_fill
,
fill_val
)
fn10
=
xr_function
([
x_sym_fill
,
fill_val
],
y10
)
result10
=
fn10
(
x_sym_fill_test
,
fill_val_test
)
expected10
=
xr_full_like
(
x_sym_fill_test
,
3.14
)
xr_assert_allclose
(
result10
,
expected10
,
check_dtype
=
True
)
# Test dtype conversion to bool when neither input nor fill_value are bool
x_float
=
xtensor
(
"x_float"
,
dims
=
(
"a"
,
"b"
),
shape
=
(
2
,
3
),
dtype
=
"float64"
)
x_float_test
=
xr_arange_like
(
x_float
)
y11
=
full_like
(
x_float
,
5.0
,
dtype
=
"bool"
)
fn11
=
xr_function
([
x_float
],
y11
)
result11
=
fn11
(
x_float_test
)
expected11
=
xr_full_like
(
x_float_test
,
5.0
,
dtype
=
"bool"
)
xr_assert_allclose
(
result11
,
expected11
,
check_dtype
=
True
)
# Verify the result is actually boolean
assert
result11
.
dtype
==
"bool"
assert
expected11
.
dtype
==
"bool"
def
test_full_like_errors
():
"""Test full_like function errors."""
x
=
xtensor
(
"x"
,
dims
=
(
"a"
,
"b"
),
shape
=
(
2
,
3
),
dtype
=
"float64"
)
x_test
=
xr_arange_like
(
x
)
with
pytest
.
raises
(
ValueError
,
match
=
"fill_value must be a scalar"
):
full_like
(
x
,
x_test
)
def
test_ones_like
():
"""Test ones_like function, comparing with xarray's ones_like."""
x
=
xtensor
(
"x"
,
dims
=
(
"a"
,
"b"
),
shape
=
(
2
,
3
),
dtype
=
"float64"
)
x_test
=
xr_arange_like
(
x
)
y1
=
ones_like
(
x
)
fn1
=
xr_function
([
x
],
y1
)
result1
=
fn1
(
x_test
)
expected1
=
xr_ones_like
(
x_test
)
xr_assert_allclose
(
result1
,
expected1
)
assert
result1
.
dtype
==
expected1
.
dtype
def
test_zeros_like
():
"""Test zeros_like function, comparing with xarray's zeros_like."""
x
=
xtensor
(
"x"
,
dims
=
(
"a"
,
"b"
),
shape
=
(
2
,
3
),
dtype
=
"float64"
)
x_test
=
xr_arange_like
(
x
)
y1
=
zeros_like
(
x
)
fn1
=
xr_function
([
x
],
y1
)
result1
=
fn1
(
x_test
)
expected1
=
xr_zeros_like
(
x_test
)
xr_assert_allclose
(
result1
,
expected1
)
assert
result1
.
dtype
==
expected1
.
dtype
tests/xtensor/util.py
浏览文件 @
ae388840
...
@@ -37,11 +37,30 @@ def xr_function(*args, **kwargs):
...
@@ -37,11 +37,30 @@ def xr_function(*args, **kwargs):
return
xfn
return
xfn
def
xr_assert_allclose
(
x
,
y
,
*
args
,
**
kwargs
):
def
xr_assert_allclose
(
x
,
y
,
check_dtype
=
False
,
*
args
,
**
kwargs
):
# Assert that two xarray DataArrays are close, ignoring coordinates
"""Assert that two xarray DataArrays are close, ignoring coordinates.
Mostly a wrapper around xarray.testing.assert_allclose,
but with the option to check the dtype.
Parameters
----------
x : xarray.DataArray
The first xarray DataArray to compare.
y : xarray.DataArray
The second xarray DataArray to compare.
check_dtype : bool, optional
If True, check that the dtype of the two DataArrays is the same.
*args :
Additional arguments to pass to xarray.testing.assert_allclose.
**kwargs :
Additional keyword arguments to pass to xarray.testing.assert_allclose.
"""
x
=
x
.
drop_vars
(
x
.
coords
)
x
=
x
.
drop_vars
(
x
.
coords
)
y
=
y
.
drop_vars
(
y
.
coords
)
y
=
y
.
drop_vars
(
y
.
coords
)
assert_allclose
(
x
,
y
,
*
args
,
**
kwargs
)
assert_allclose
(
x
,
y
,
*
args
,
**
kwargs
)
if
check_dtype
:
assert
x
.
dtype
==
y
.
dtype
def
xr_arange_like
(
x
):
def
xr_arange_like
(
x
):
...
...
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论