diff --git a/swe-paddle/tasks/PaddlePaddle__Paddle-59127/README.md b/swe-paddle/tasks/PaddlePaddle__Paddle-59127/README.md new file mode 100644 index 000000000..8884aafe3 --- /dev/null +++ b/swe-paddle/tasks/PaddlePaddle__Paddle-59127/README.md @@ -0,0 +1,37 @@ +# PaddlePaddle__Paddle-59127 + +This directory converts Paddle PR #59127 into a SWE-Paddle community task candidate. + +## Source + +| Field | Value | +| --- | --- | +| Repo | `PaddlePaddle/Paddle` | +| PR | [59127](https://github.com/PaddlePaddle/Paddle/pull/59127) | +| PR title | 【Hackathon 5th No.31】为 Paddle 新增 column_stack / row_stack / dstack / hstack / vstack API -part | +| Base commit | `cb5ff84d214b86b2409b3aa83ef7cd4ccd06374b` | +| Merged at | `2023-12-12T07:36:50Z` | +| Hackathon | `5th` task `31` | +| Task type | `feature_enhancement` | +| Resource | CPU | + +## Summary + +Add `hstack`, `vstack`, `dstack`, `column_stack`, `row_stack` APIs for Paddle, which join a sequence of tensors along different axes, with NumPy-compatible semantics. + +## Files + +- `proposal.md`: candidate proposal for maintainer triage. +- `instruction.md`: self-contained problem statement for the coding agent. +- `solution/code.patch`: gold patch from the merged PR. +- `tests/test.patch`: test patch exposing the target behavior. +- `tests/test.sh`: minimal target test command. +- `environment/README.md`: environment notes for reproduction. + +## Verification + +```bash +bash tests/test.sh +``` + +Expected behavior: applying `tests/test.patch` to `base_commit` should fail on the target behavior; applying both `tests/test.patch` and `solution/code.patch` should pass the target tests. diff --git a/swe-paddle/tasks/PaddlePaddle__Paddle-59127/environment/README.md b/swe-paddle/tasks/PaddlePaddle__Paddle-59127/environment/README.md new file mode 100644 index 000000000..0e753e62b --- /dev/null +++ b/swe-paddle/tasks/PaddlePaddle__Paddle-59127/environment/README.md @@ -0,0 +1,26 @@ +# Environment Notes + +This candidate is part of the SWE-Paddle task set. + +## Expected Environment + +- Repository: `PaddlePaddle/Paddle` +- Base commit: `cb5ff84d214b86b2409b3aa83ef7cd4ccd06374b` +- Resource: CPU +- Build path: Paddle source checkout at the base commit. This task only involves Python-side changes (stack APIs built on existing `concat`/`atleast_nd` primitives), so a source build with Python tests is sufficient. + +## Run Order + +1. Check out `PaddlePaddle/Paddle` at the base commit. +2. Apply `tests/test.patch`. +3. Run `bash tests/test.sh`; the target behavior should fail before the fix. +4. Apply `solution/code.patch`. +5. Run `bash tests/test.sh` again; the target behavior should pass after the gold patch. + +## Minimal Test Command + +```bash +bash tests/test.sh +``` + +The verifier is responsible for deriving stable F2P and P2P node IDs from repeated runs. diff --git a/swe-paddle/tasks/PaddlePaddle__Paddle-59127/instruction.md b/swe-paddle/tasks/PaddlePaddle__Paddle-59127/instruction.md new file mode 100644 index 000000000..172ce5b0b --- /dev/null +++ b/swe-paddle/tasks/PaddlePaddle__Paddle-59127/instruction.md @@ -0,0 +1,28 @@ +# 新增 column_stack / row_stack / dstack / hstack / vstack API + +## 详细描述 + +为 Paddle 新增 `column_stack`、`row_stack`、`dstack`、`hstack`、`vstack` 五个张量拼接 API,语义对齐 NumPy 同名函数。 + +要求: + +- 新增 `paddle.hstack(x, name=None)`:水平拼接。所有输入先 `atleast_1d`;若为 1-D 输入沿 axis=0 拼接,否则沿 axis=1 拼接 +- 新增 `paddle.vstack(x, name=None)`:垂直拼接。输入先 `atleast_2d`,沿 axis=0 拼接 +- 新增 `paddle.dstack(x, name=None)`:深度拼接。输入先 `atleast_3d`,沿 axis=2 拼接 +- 新增 `paddle.column_stack(x, name=None)`:将 1-D 输入先转成 2-D 列向量(`[N, 1]`)再沿 axis=1 拼接 +- 新增 `paddle.row_stack(x, name=None)`:等价于 `vstack` +- 输入 `x` 为 Tensor 的 list/tuple,所有 Tensor 必须同 dtype;支持的数据类型:float16, float32, float64, int8, int32, int64, bfloat16 +- 在 `paddle` 顶层命名空间、`paddle.tensor` 命名空间导出,并绑定为 tensor 方法 + +## 验收说明 + +- 五个 API 前向结果与 NumPy 对应函数一致(含 0-D/1-D/2-D 输入的补维行为) +- 拼接结果 shape 正确(沿各自 axis) +- 输入 dtype 不一致或形状不兼容时应按 NumPy 语义报错 +- 静态图与动态图下均可用 + +## Acceptance Criteria + +- The behavior described above should be fixed. +- Existing valid behavior should remain unchanged. +- Do not satisfy the task by deleting tests, weakening assertions, or bypassing validation broadly. diff --git a/swe-paddle/tasks/PaddlePaddle__Paddle-59127/proposal.md b/swe-paddle/tasks/PaddlePaddle__Paddle-59127/proposal.md new file mode 100644 index 000000000..5465c5811 --- /dev/null +++ b/swe-paddle/tasks/PaddlePaddle__Paddle-59127/proposal.md @@ -0,0 +1,54 @@ +# Task Proposal: PaddlePaddle__Paddle-59127 + +## 1. 来源信息 + +- Instance ID:`PaddlePaddle__Paddle-59127` +- PR 链接:https://github.com/PaddlePaddle/Paddle/pull/59127 +- PR 标题:`【Hackathon 5th No.31】为 Paddle 新增 column_stack / row_stack / dstack / hstack / vstack API -part` +- `base_commit`:`cb5ff84d214b86b2409b3aa83ef7cd4ccd06374b` +- merge commit:`0bdee96e8e797cc3d24048b1ee3c0daef8e9f27e` +- merged 时间:`2023-12-12T07:36:50Z` +- 后续联系人:megemini + +## 2. 问题一句话 + +为 Paddle 新增 `column_stack` / `row_stack` / `dstack` / `hstack` / `vstack` API,按 NumPy 语义沿不同轴拼接一组张量。 + +## 3. 为什么适合作为 SWE-Paddle 样本 + +- **真实性**:该任务来自已合入的 Paddle Hackathon 5th 框架开发 PR,关联 RFC(community#684),不是合成任务。 +- **代表性**:它覆盖 Python 层张量拼接 API 的完整落地链路:顶层命名空间与 `paddle.tensor` 命名空间导出、tensor 方法绑定、不同维度输入的补维(`atleast_1d/2d/3d`)与 concat 轴选择逻辑。 +- **边界清楚**:目标行为集中在五个 API 的拼接轴语义与低维输入的补维行为,测试补丁可直接暴露目标行为。 +- **非平凡性**:需要正确处理 0-D/1-D 输入在不同 API 下的补维差异(hstack/vstack/dstack/column_stack 各不相同),并保持与 NumPy 语义一致;非纯配置修改。 + +## 4. 任务类型和标签 + +- 任务类型:`feature_enhancement` +- 执行后端:`cpu` +- 设备范围:`cpu` +- 模块标签:`[python_api, tensor, manipulation]` + +## 5. 验证思路 + +- 目标测试命令:`bash tests/test.sh` +- 目标测试文件:`test/legacy_test/test_stack_extension_api.py` +- 修复前预期:在 `base_commit` 上应用 `tests/test.patch` 后,`test_stack_extension_api.py` 中五个 API 相关测试应 fail(API 不存在)。 +- 修复后预期:继续应用 `solution/code.patch` 后,目标测试应 pass。 +- P2P 候选:`test_stack_extension_api.py` 为 PR 新增文件,无存量测试;可从同模块存量 manipulation 测试中选取回归护栏,由 verifier 自动抽取稳定 nodeid。 + +## 6. 环境与资源 + +- 资源需求:CPU +- Paddle 来源:`PaddlePaddle/Paddle` source checkout at `base_commit` +- 是否能提供 Docker:暂无,建议后续补充 source-build Dockerfile +- patch 类型:纯 Python(基于既有 `concat` / `atleast_nd` 原语实现) +- 环境建议:该样本仅涉及 Python 层改动,source build 后运行 Python 测试即可 +- 最小测试命令:`bash tests/test.sh` +- 是否有 oracle 日志:由 SWE-Paddle verifier 结果另行维护 + +## 7. 风险自查 + +- 泄露风险:正式 `instruction.md` 应描述目标行为和验收标准,不直接指出具体修改行。 +- 环境风险:仅 Python 改动,复现成本低于含 C++ kernel 的样本。 +- flaky 风险:五个 API 为确定性张量操作,flaky 风险低;verifier 仍应重复运行抽取稳定 F2P/P2P nodeid。 +- 拆分风险:该 PR 的目标集中在新增五个拼接 API,适合作为一个样本。 diff --git a/swe-paddle/tasks/PaddlePaddle__Paddle-59127/solution/code.patch b/swe-paddle/tasks/PaddlePaddle__Paddle-59127/solution/code.patch new file mode 100644 index 000000000..7c976d12d --- /dev/null +++ b/swe-paddle/tasks/PaddlePaddle__Paddle-59127/solution/code.patch @@ -0,0 +1,373 @@ +diff --git a/python/paddle/__init__.py b/python/paddle/__init__.py +index 6f1929c642..dc0a84f8ef 100644 +--- a/python/paddle/__init__.py ++++ b/python/paddle/__init__.py +@@ -302,6 +302,11 @@ from .tensor.manipulation import ( # noqa: F401 + squeeze, + squeeze_, + stack, ++ hstack, ++ vstack, ++ dstack, ++ column_stack, ++ row_stack, + strided_slice, + take_along_axis, + tensordot, +@@ -820,6 +825,11 @@ __all__ = [ + 'disable_signal_handler', + 'expand_as', + 'stack', ++ 'hstack', ++ 'vstack', ++ 'dstack', ++ 'column_stack', ++ 'row_stack', + 'sqrt', + 'randperm', + 'linspace', +diff --git a/python/paddle/tensor/__init__.py b/python/paddle/tensor/__init__.py +index 4c453492f1..56b5022b86 100644 +--- a/python/paddle/tensor/__init__.py ++++ b/python/paddle/tensor/__init__.py +@@ -146,8 +146,10 @@ from .manipulation import ( # noqa: F401 + cast, + cast_, + chunk, ++ column_stack, + concat, + diagonal_scatter, ++ dstack, + expand, + expand_as, + flatten, +@@ -156,6 +158,7 @@ from .manipulation import ( # noqa: F401 + flip as reverse, + gather, + gather_nd, ++ hstack, + index_add, + index_add_, + index_fill, +@@ -172,6 +175,7 @@ from .manipulation import ( # noqa: F401 + reshape_, + roll, + rot90, ++ row_stack, + scatter, + scatter_, + scatter_nd, +@@ -198,6 +202,7 @@ from .manipulation import ( # noqa: F401 + view, + view_as, + vsplit, ++ vstack, + ) + from .math import ( # noqa: F401 + abs, +diff --git a/python/paddle/tensor/manipulation.py b/python/paddle/tensor/manipulation.py +index d0d8296bdf..807ad1aae5 100644 +--- a/python/paddle/tensor/manipulation.py ++++ b/python/paddle/tensor/manipulation.py +@@ -2060,6 +2060,301 @@ def stack(x, axis=0, name=None): + return out + + ++def hstack(x, name=None): ++ """ ++ Stacks all the input tensors ``x`` along horizontal axis. ++ All tensors must be of the same dtype. ++ ++ Args: ++ x (list[Tensor]|tuple[Tensor]): Input ``x`` can be a ``list`` or ``tuple`` of tensors, the Tensors in ``x`` must be of the same ++ shape and dtype. Supported data types: ``float16``, ``float32``, ``float64``, ``int8``, ``int32``, ``int64`` or ``bfloat16``. ++ name (str, optional): Name for the operation (optional, default is None). For more information, please refer to :ref:`api_guide_Name`. ++ ++ Returns: ++ Tensor, The stacked tensor with same data type as input. ++ ++ Examples: ++ .. code-block:: python ++ ++ >>> import paddle ++ ++ >>> # hstack with 0-D tensors ++ >>> x1 = paddle.to_tensor(1.0) ++ >>> x2 = paddle.to_tensor(2.0) ++ >>> out = paddle.hstack((x1, x2)) ++ >>> print(out) ++ Tensor(shape=[2], dtype=float32, place=Place(cpu), stop_gradient=True, ++ [1., 2.]) ++ ++ >>> # hstack with 1-D tensors ++ >>> x1 = paddle.to_tensor([1.0, 2.0]) ++ >>> x2 = paddle.to_tensor([3.0, 4.0, 5.0]) ++ >>> out = paddle.hstack((x1, x2)) ++ >>> print(out) ++ Tensor(shape=[5], dtype=float32, place=Place(cpu), stop_gradient=True, ++ [1., 2., 3., 4., 5.]) ++ ++ >>> # hstack mix with 0-D & 1-D tensors ++ >>> x1 = paddle.to_tensor(1.0) ++ >>> x2 = paddle.to_tensor([3.0, 4.0, 5.0]) ++ >>> out = paddle.hstack((x1, x2)) ++ >>> print(out) ++ Tensor(shape=[4], dtype=float32, place=Place(cpu), stop_gradient=True, ++ [1., 3., 4., 5.]) ++ ++ >>> # hstack with 2-D tensors ++ >>> x1 = paddle.to_tensor([[1.0, 2.0]]) ++ >>> x2 = paddle.to_tensor([[3.0, 4.0, 5.0]]) ++ >>> out = paddle.hstack((x1, x2)) ++ >>> print(out) ++ Tensor(shape=[1, 5], dtype=float32, place=Place(cpu), stop_gradient=True, ++ [[1., 2., 3., 4., 5.]]) ++ ++ """ ++ arrays = paddle.atleast_1d(*x) ++ if not isinstance(arrays, list): ++ arrays = [arrays] ++ ++ if arrays and arrays[0].ndim == 1: ++ return paddle.concat(arrays, axis=0, name=name) ++ else: ++ return paddle.concat(arrays, axis=1, name=name) ++ ++ ++def vstack(x, name=None): ++ """ ++ Stacks all the input tensors ``x`` along vertical axis. ++ All tensors must be of the same dtype. ++ ++ Args: ++ x (list[Tensor]|tuple[Tensor]): Input ``x`` can be a ``list`` or ``tuple`` of tensors, the Tensors in ``x`` must be of the same ++ shape and dtype. Supported data types: ``float16``, ``float32``, ``float64``, ``int8``, ``int32``, ``int64`` or ``bfloat16``. ++ name (str, optional): Name for the operation (optional, default is None). For more information, please refer to :ref:`api_guide_Name`. ++ ++ Returns: ++ Tensor, The stacked tensor with same data type as input. ++ ++ Examples: ++ .. code-block:: python ++ ++ >>> import paddle ++ ++ >>> # vstack with 0-D tensors ++ >>> x1 = paddle.to_tensor(1.0) ++ >>> x2 = paddle.to_tensor(2.0) ++ >>> out = paddle.vstack((x1, x2)) ++ >>> print(out) ++ Tensor(shape=[2, 1], dtype=float32, place=Place(cpu), stop_gradient=True, ++ [[1.], ++ [2.]]) ++ ++ >>> # vstack with 1-D tensors ++ >>> x1 = paddle.to_tensor([1.0, 2.0, 3.0]) ++ >>> x2 = paddle.to_tensor([3.0, 4.0, 5.0]) ++ >>> out = paddle.vstack((x1, x2)) ++ >>> print(out) ++ Tensor(shape=[2, 3], dtype=float32, place=Place(cpu), stop_gradient=True, ++ [[1., 2., 3.], ++ [3., 4., 5.]]) ++ ++ >>> # vstack mix with 1-D & 2-D tensors ++ >>> x1 = paddle.to_tensor([1.0, 2.0, 3.0]) ++ >>> x2 = paddle.to_tensor([[3.0, 4.0, 5.0]]) ++ >>> out = paddle.vstack((x1, x2)) ++ >>> print(out) ++ Tensor(shape=[2, 3], dtype=float32, place=Place(cpu), stop_gradient=True, ++ [[1., 2., 3.], ++ [3., 4., 5.]]) ++ ++ >>> # vstack with 2-D tensors ++ >>> x1 = paddle.to_tensor([[1.0, 2.0, 3.0]]) ++ >>> x2 = paddle.to_tensor([[3.0, 4.0, 5.0]]) ++ >>> out = paddle.vstack((x1, x2)) ++ >>> print(out) ++ Tensor(shape=[2, 3], dtype=float32, place=Place(cpu), stop_gradient=True, ++ [[1., 2., 3.], ++ [3., 4., 5.]]) ++ ++ """ ++ arrays = paddle.atleast_2d(*x) ++ if not isinstance(arrays, list): ++ arrays = [arrays] ++ ++ return paddle.concat(arrays, axis=0, name=name) ++ ++ ++def dstack(x, name=None): ++ """ ++ Stacks all the input tensors ``x`` along depth axis. ++ All tensors must be of the same dtype. ++ ++ Args: ++ x (list[Tensor]|tuple[Tensor]): Input ``x`` can be a ``list`` or ``tuple`` of tensors, the Tensors in ``x`` must be of the same ++ shape and dtype. Supported data types: ``float16``, ``float32``, ``float64``, ``int8``, ``int32``, ``int64`` or ``bfloat16``. ++ name (str, optional): Name for the operation (optional, default is None). For more information, please refer to :ref:`api_guide_Name`. ++ ++ Returns: ++ Tensor, The stacked tensor with same data type as input. ++ ++ Examples: ++ .. code-block:: python ++ ++ >>> import paddle ++ ++ >>> # dstack with 0-D tensors ++ >>> x1 = paddle.to_tensor(1.0) ++ >>> x2 = paddle.to_tensor(2.0) ++ >>> out = paddle.dstack((x1, x2)) ++ >>> print(out) ++ Tensor(shape=[1, 1, 2], dtype=float32, place=Place(cpu), stop_gradient=True, ++ [[[1., 2.]]]) ++ ++ >>> # dstack with 1-D tensors ++ >>> x1 = paddle.to_tensor([1.0, 2.0, 3.0]) ++ >>> x2 = paddle.to_tensor([3.0, 4.0, 5.0]) ++ >>> out = paddle.dstack((x1, x2)) ++ >>> print(out) ++ Tensor(shape=[1, 3, 2], dtype=float32, place=Place(cpu), stop_gradient=True, ++ [[[1., 3.], ++ [2., 4.], ++ [3., 5.]]]) ++ ++ >>> # dstack with 3-D tensors ++ >>> x1 = paddle.to_tensor([[[1.0, 2.0], [3.0, 4.0]]]) ++ >>> x2 = paddle.to_tensor([[[3.0, 4.0], [5.0, 6.0]]]) ++ >>> out = paddle.dstack((x1, x2)) ++ >>> print(out) ++ Tensor(shape=[1, 2, 4], dtype=float32, place=Place(cpu), stop_gradient=True, ++ [[[1., 2., 3., 4.], ++ [3., 4., 5., 6.]]]) ++ ++ """ ++ arrays = paddle.atleast_3d(*x) ++ if not isinstance(arrays, list): ++ arrays = [arrays] ++ ++ return paddle.concat(arrays, axis=2, name=name) ++ ++ ++def column_stack(x, name=None): ++ """ ++ Stacks all the input tensors ``x`` along horizontal axis. Each tensor in ``x`` will be first reshaped into ``(tensor.numel(), 1)`` ++ if ``tensor.ndim < 2`` before being stacked. ++ All tensors must be of the same dtype. ++ ++ Args: ++ x (list[Tensor]|tuple[Tensor]): Input ``x`` can be a ``list`` or ``tuple`` of tensors, the Tensors in ``x`` must be of the same ++ shape and dtype. Supported data types: ``float16``, ``float32``, ``float64``, ``int32``, ``int64`` or ``bfloat16``. ++ name (str, optional): Name for the operation (optional, default is None). For more information, please refer to :ref:`api_guide_Name`. ++ ++ Returns: ++ Tensor, The stacked tensor with same data type as input. ++ ++ Examples: ++ .. code-block:: python ++ ++ >>> import paddle ++ ++ >>> # column_stack with 0-D tensors ++ >>> x1 = paddle.to_tensor(1.0) ++ >>> x2 = paddle.to_tensor(2.0) ++ >>> out = paddle.column_stack((x1, x2)) ++ >>> print(out) ++ Tensor(shape=[1, 2], dtype=float32, place=Place(cpu), stop_gradient=True, ++ [[1., 2.]]) ++ ++ >>> # column_stack mix with 1-D & 2-D tensors ++ >>> x1 = paddle.to_tensor([[1.0], [2.0], [3.0]]) ++ >>> x2 = paddle.to_tensor([3.0, 4.0, 5.0]) ++ >>> out = paddle.column_stack((x1, x2)) ++ >>> print(out) ++ Tensor(shape=[3, 2], dtype=float32, place=Place(cpu), stop_gradient=True, ++ [[1., 3.], ++ [2., 4.], ++ [3., 5.]]) ++ ++ >>> # column_stack with 3-D tensors ++ >>> x1 = paddle.to_tensor([[[1.0, 2.0], [3.0, 4.0]]]) ++ >>> x2 = paddle.to_tensor([[[3.0, 4.0], [5.0, 6.0]]]) ++ >>> out = paddle.column_stack((x1, x2)) ++ >>> print(out) ++ Tensor(shape=[1, 4, 2], dtype=float32, place=Place(cpu), stop_gradient=True, ++ [[[1., 2.], ++ [3., 4.], ++ [3., 4.], ++ [5., 6.]]]) ++ ++ """ ++ arrays = [] ++ ++ for tensor in x: ++ if tensor.ndim < 2: ++ arrays.append(tensor.reshape((tensor.numel(), 1))) ++ else: ++ arrays.append(tensor) ++ ++ return paddle.concat(arrays, axis=1, name=name) ++ ++ ++def row_stack(x, name=None): ++ """ ++ Alias of `paddle.vstack()`. ++ Stacks all the input tensors ``x`` along vertical axis. ++ All tensors must be of the same dtype. ++ ++ Args: ++ x (list[Tensor]|tuple[Tensor]): Input ``x`` can be a ``list`` or ``tuple`` of tensors, the Tensors in ``x`` must be of the same ++ shape and dtype. Supported data types: ``float16``, ``float32``, ``float64``, ``int8``, ``int32``, ``int64`` or ``bfloat16``. ++ name (str, optional): Name for the operation (optional, default is None). For more information, please refer to :ref:`api_guide_Name`. ++ ++ Returns: ++ Tensor, The stacked tensor with same data type as input. ++ ++ Examples: ++ .. code-block:: python ++ ++ >>> import paddle ++ ++ >>> # row_stack with 0-D tensors ++ >>> x1 = paddle.to_tensor(1.0) ++ >>> x2 = paddle.to_tensor(2.0) ++ >>> out = paddle.row_stack((x1, x2)) ++ >>> print(out) ++ Tensor(shape=[2, 1], dtype=float32, place=Place(cpu), stop_gradient=True, ++ [[1.], ++ [2.]]) ++ ++ >>> # row_stack with 1-D tensors ++ >>> x1 = paddle.to_tensor([1.0, 2.0, 3.0]) ++ >>> x2 = paddle.to_tensor([3.0, 4.0, 5.0]) ++ >>> out = paddle.row_stack((x1, x2)) ++ >>> print(out) ++ Tensor(shape=[2, 3], dtype=float32, place=Place(cpu), stop_gradient=True, ++ [[1., 2., 3.], ++ [3., 4., 5.]]) ++ ++ >>> # row_stack mix with 1-D & 2-D tensors ++ >>> x1 = paddle.to_tensor([1.0, 2.0, 3.0]) ++ >>> x2 = paddle.to_tensor([[3.0, 4.0, 5.0]]) ++ >>> out = paddle.row_stack((x1, x2)) ++ >>> print(out) ++ Tensor(shape=[2, 3], dtype=float32, place=Place(cpu), stop_gradient=True, ++ [[1., 2., 3.], ++ [3., 4., 5.]]) ++ ++ >>> # row_stack with 2-D tensors ++ >>> x1 = paddle.to_tensor([[1.0, 2.0, 3.0]]) ++ >>> x2 = paddle.to_tensor([[3.0, 4.0, 5.0]]) ++ >>> out = paddle.row_stack((x1, x2)) ++ >>> print(out) ++ Tensor(shape=[2, 3], dtype=float32, place=Place(cpu), stop_gradient=True, ++ [[1., 2., 3.], ++ [3., 4., 5.]]) ++ ++ """ ++ return paddle.vstack(x, name=name) ++ ++ + def split(x, num_or_sections, axis=0, name=None): + """ + Split the input tensor into multiple sub-Tensors. diff --git a/swe-paddle/tasks/PaddlePaddle__Paddle-59127/tests/test.patch b/swe-paddle/tasks/PaddlePaddle__Paddle-59127/tests/test.patch new file mode 100644 index 000000000..b34bcd726 --- /dev/null +++ b/swe-paddle/tasks/PaddlePaddle__Paddle-59127/tests/test.patch @@ -0,0 +1,508 @@ +diff --git a/test/legacy_test/test_stack_extension_api.py b/test/legacy_test/test_stack_extension_api.py +new file mode 100644 +index 0000000000..b6f42de6c9 +--- /dev/null ++++ b/test/legacy_test/test_stack_extension_api.py +@@ -0,0 +1,502 @@ ++# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved. ++# ++# Licensed under the Apache License, Version 2.0 (the "License"); ++# you may not use this file except in compliance with the License. ++# You may obtain a copy of the License at ++# ++# http://www.apache.org/licenses/LICENSE-2.0 ++# ++# Unless required by applicable law or agreed to in writing, software ++# distributed under the License is distributed on an "AS IS" BASIS, ++# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++# See the License for the specific language governing permissions and ++# limitations under the License. ++ ++import itertools ++import sys ++import unittest ++ ++import numpy as np ++ ++import paddle ++from paddle.base import core ++from paddle.pir_utils import test_with_pir_api ++ ++RTOL = 1e-5 ++ATOL = 1e-8 ++DTYPE_ALL = [ ++ 'float16', ++ 'float32', ++ 'float64', ++ 'int32', ++ 'int64', ++ 'bfloat16', ++] ++ ++DTYPE_COLUMN_STACK = DTYPE_ALL ++ ++PLACES = [('cpu', paddle.CPUPlace())] + ( ++ [('gpu', paddle.CUDAPlace(0))] if core.is_compiled_with_cuda() else [] ++) ++ ++ ++def rearrange_data(*inputs): ++ data = list(zip(*inputs)) ++ return [list(itertools.chain(*data[i])) for i in range(4)] ++ ++ ++def generate_data(shape, count=1, dtype='int32'): ++ """generate test data ++ ++ Args: ++ shape(list of int): shape of inputs ++ count(int): input count for each dim ++ dtype(str): dtype ++ ++ Returns: ++ a list of data like: ++ [[data, dtype, shape, name], [data, dtype, shape, name] ... ] ++ """ ++ return list( ++ zip( ++ *[ ++ [ ++ # bfloat16 convert to uint16 for numpy ++ np.random.randint(0, 255, size=shape).astype( ++ dtype if dtype != 'bfloat16' else 'uint16' ++ ), ++ dtype, ++ shape, ++ f'{shape}d_{idx}_{dtype}', ++ ] ++ for idx in range(count) ++ ] ++ ) ++ ) ++ ++ ++class BaseTest(unittest.TestCase): ++ """Test in each `PLACES` and in `static/dygraph`""" ++ ++ @test_with_pir_api ++ def _test_static_api( ++ self, ++ func_paddle, ++ func_numpy, ++ inputs: list, ++ dtypes: list, ++ shapes: list, ++ names: list, ++ ): ++ """Test `static`, convert `Tensor` to `numpy array` before feed into graph""" ++ paddle.enable_static() ++ ++ for device, place in PLACES: ++ paddle.set_device(device) ++ ++ exe = paddle.static.Executor(place) ++ new_scope = paddle.static.Scope() ++ main_program = paddle.static.Program() ++ with paddle.static.scope_guard(new_scope): ++ with paddle.static.program_guard(main_program): ++ x = [] ++ feed = {} ++ for i in range(len(inputs)): ++ input = inputs[i] ++ shape = shapes[i] ++ dtype = dtypes[i] ++ name = names[i] ++ ++ _x = paddle.static.data(name, shape, dtype) ++ _x.stop_gradient = False ++ x.append(_x) ++ ++ # the data feeded should NOT be a Tensor ++ feed[name] = input ++ ++ out = func_paddle(x) ++ out.stop_gradient = False ++ ++ y = out * 123 ++ ++ # not check old ir ++ if paddle.framework.in_pir_mode(): ++ fetch_list = [out] ++ grads = paddle.autograd.ir_backward.grad(y, x) ++ fetch_list.append(grads) ++ ++ exe = paddle.static.Executor(place) ++ res, *res_grad = exe.run( ++ feed=feed, fetch_list=fetch_list ++ ) ++ ++ # convert grad value to bool if dtype is bool ++ grad_value = 123.0 if dtypes[0] != 'bool' else True ++ np.testing.assert_allclose( ++ res_grad[0], np.ones(x[0].shape) * grad_value ++ ) ++ ++ out_ref = func_numpy(inputs) ++ for n, p in zip(out_ref, res): ++ np.testing.assert_allclose( ++ n, p, rtol=RTOL, atol=ATOL ++ ) ++ ++ def _test_dygraph_api( ++ self, ++ func_paddle, ++ func_numpy, ++ inputs: list, ++ dtypes: list, ++ shapes: list, ++ names: list, ++ ): ++ """Test `dygraph`, and check grads""" ++ paddle.disable_static() ++ ++ for device, place in PLACES: ++ paddle.set_device(device) ++ ++ out = func_paddle( ++ [ ++ paddle.to_tensor(inputs[i]).astype(dtypes[i]) ++ for i in range(len(inputs)) ++ ] ++ ) ++ out_ref = func_numpy(inputs) ++ ++ for n, p in zip(out_ref, out): ++ np.testing.assert_allclose(n, p.numpy(), rtol=RTOL, atol=ATOL) ++ ++ # check grads ++ if len(inputs) == 1: ++ out = [out] ++ ++ for y in out: ++ y.stop_gradient = False ++ z = y * 123 ++ grads = paddle.grad(z, y) ++ self.assertTrue(len(grads), 1) ++ self.assertEqual(grads[0].dtype, y.dtype) ++ self.assertEqual(grads[0].shape, y.shape) ++ ++ def _test_all(self, args, dtype=''): ++ self._test_dygraph_api(self.func_paddle, self.func_numpy, *args) ++ self._test_static_api(self.func_paddle, self.func_numpy, *args) ++ ++ ++class BaseCases: ++ def test_0d(self): ++ self._test_all(generate_data([], count=1, dtype='float64')) ++ ++ def test_1d(self): ++ self._test_all(generate_data([1], count=1, dtype='float64')) ++ ++ def test_2d(self): ++ self._test_all(generate_data([1, 1], count=1, dtype='float64')) ++ self._test_all(generate_data([3, 2], count=1, dtype='float64')) ++ ++ def test_3d(self): ++ self._test_all(generate_data([1, 1, 1], count=1, dtype='float64')) ++ self._test_all(generate_data([3, 4, 2], count=1, dtype='float64')) ++ ++ def test_4d(self): ++ self._test_all(generate_data([1, 1, 1, 1], count=1, dtype='float64')) ++ self._test_all(generate_data([3, 4, 2, 5], count=1, dtype='float64')) ++ ++ def test_0d_more(self): ++ self._test_all(generate_data([], count=3, dtype='float64')) ++ ++ def test_1d_more(self): ++ self._test_all(generate_data([1], count=3, dtype='float64')) ++ self._test_all(generate_data([5], count=3, dtype='float64')) ++ ++ def test_2d_more(self): ++ self._test_all(generate_data([1, 1], count=3, dtype='float64')) ++ self._test_all(generate_data([3, 2], count=3, dtype='float64')) ++ ++ def test_3d_more(self): ++ self._test_all(generate_data([1, 1, 1], count=3, dtype='float64')) ++ self._test_all(generate_data([3, 4, 2], count=3, dtype='float64')) ++ ++ def test_4d_more(self): ++ self._test_all(generate_data([1, 1, 1, 1], count=3, dtype='float64')) ++ self._test_all(generate_data([3, 4, 2, 5], count=3, dtype='float64')) ++ ++ ++class TestHStack(BaseTest, BaseCases): ++ def setUp(self): ++ self.func_paddle = paddle.hstack ++ self.func_numpy = np.hstack ++ ++ def test_mix_ndim(self): ++ d0 = generate_data([], count=1, dtype='float64') ++ d1 = generate_data([2], count=1, dtype='float64') ++ self._test_all(rearrange_data(d0, d1)) ++ ++ def test_dtype(self): ++ for dtype in DTYPE_ALL: ++ if dtype == 'float16' and ( ++ not core.is_compiled_with_cuda() ++ or ( ++ not core.is_float16_supported(paddle.CUDAPlace(0)) ++ or sys.platform == 'win32' ++ ) ++ ): ++ continue ++ ++ if dtype == 'bfloat16' and ( ++ not core.is_compiled_with_cuda() ++ or ( ++ not core.is_bfloat16_supported(paddle.CUDAPlace(0)) ++ or sys.platform == 'win32' ++ ) ++ ): ++ continue ++ ++ self._test_all( ++ generate_data([], count=1, dtype=dtype), ++ dtype, ++ ) ++ ++ ++class TestVStack(BaseTest, BaseCases): ++ def setUp(self): ++ self.func_paddle = paddle.vstack ++ self.func_numpy = np.vstack ++ ++ def test_mix_ndim(self): ++ d0 = generate_data([2], count=1, dtype='float64') ++ d1 = generate_data([1, 2], count=1, dtype='float64') ++ self._test_all(rearrange_data(d0, d1)) ++ ++ def test_dtype(self): ++ for dtype in DTYPE_ALL: ++ if dtype == 'float16' and ( ++ not core.is_compiled_with_cuda() ++ or ( ++ not core.is_float16_supported(paddle.CUDAPlace(0)) ++ or sys.platform == 'win32' ++ ) ++ ): ++ continue ++ ++ if dtype == 'bfloat16' and ( ++ not core.is_compiled_with_cuda() ++ or ( ++ not core.is_bfloat16_supported(paddle.CUDAPlace(0)) ++ or sys.platform == 'win32' ++ ) ++ ): ++ continue ++ ++ self._test_all( ++ generate_data([], count=1, dtype=dtype), ++ dtype, ++ ) ++ ++ ++class TestDStack(BaseTest, BaseCases): ++ def setUp(self): ++ self.func_paddle = paddle.dstack ++ self.func_numpy = np.dstack ++ ++ def test_mix_ndim(self): ++ d0 = generate_data([2], count=1, dtype='float64') ++ d1 = generate_data([1, 2], count=1, dtype='float64') ++ self._test_all(rearrange_data(d0, d1)) ++ ++ d0 = generate_data([2], count=1, dtype='float64') ++ d1 = generate_data([1, 2, 1], count=1, dtype='float64') ++ self._test_all(rearrange_data(d0, d1)) ++ ++ def test_dtype(self): ++ for dtype in DTYPE_ALL: ++ if dtype == 'float16' and ( ++ not core.is_compiled_with_cuda() ++ or ( ++ not core.is_float16_supported(paddle.CUDAPlace(0)) ++ or sys.platform == 'win32' ++ ) ++ ): ++ continue ++ ++ if dtype == 'bfloat16' and ( ++ not core.is_compiled_with_cuda() ++ or ( ++ not core.is_bfloat16_supported(paddle.CUDAPlace(0)) ++ or sys.platform == 'win32' ++ ) ++ ): ++ continue ++ ++ self._test_all( ++ generate_data([], count=1, dtype=dtype), ++ dtype, ++ ) ++ ++ ++class TestColumnStack(BaseTest, BaseCases): ++ def setUp(self): ++ self.func_paddle = paddle.column_stack ++ self.func_numpy = np.column_stack ++ ++ def test_mix_ndim(self): ++ d0 = generate_data([2], count=1, dtype='float64') ++ d1 = generate_data([2, 1], count=1, dtype='float64') ++ self._test_all(rearrange_data(d0, d1)) ++ ++ def test_dtype(self): ++ for dtype in DTYPE_COLUMN_STACK: ++ if dtype == 'float16' and ( ++ not core.is_compiled_with_cuda() ++ or ( ++ not core.is_float16_supported(paddle.CUDAPlace(0)) ++ or sys.platform == 'win32' ++ ) ++ ): ++ continue ++ ++ if dtype == 'bfloat16' and ( ++ not core.is_compiled_with_cuda() ++ or ( ++ not core.is_bfloat16_supported(paddle.CUDAPlace(0)) ++ or sys.platform == 'win32' ++ ) ++ ): ++ continue ++ ++ self._test_all( ++ generate_data([], count=1, dtype=dtype), ++ dtype=dtype, ++ ) ++ ++ ++class TestRowStack(BaseTest, BaseCases): ++ def setUp(self): ++ self.func_paddle = paddle.row_stack ++ self.func_numpy = np.row_stack ++ ++ def test_mix_ndim(self): ++ d0 = generate_data([2], count=1, dtype='float64') ++ d1 = generate_data([1, 2], count=1, dtype='float64') ++ self._test_all(rearrange_data(d0, d1)) ++ ++ def test_dtype(self): ++ for dtype in DTYPE_ALL: ++ if dtype == 'float16' and ( ++ not core.is_compiled_with_cuda() ++ or ( ++ not core.is_float16_supported(paddle.CUDAPlace(0)) ++ or sys.platform == 'win32' ++ ) ++ ): ++ continue ++ ++ if dtype == 'bfloat16' and ( ++ not core.is_compiled_with_cuda() ++ or ( ++ not core.is_bfloat16_supported(paddle.CUDAPlace(0)) ++ or sys.platform == 'win32' ++ ) ++ ): ++ continue ++ ++ self._test_all( ++ generate_data([], count=1, dtype=dtype), ++ dtype, ++ ) ++ ++ ++class ErrorCases: ++ def test_mix_dtype(self): ++ with self.assertRaises(ValueError): ++ d0 = generate_data([2], count=1, dtype='float32') ++ d1 = generate_data([2], count=1, dtype='float64') ++ self._test_dygraph_api( ++ self.func_paddle, self.func_numpy, *rearrange_data(d0, d1) ++ ) ++ ++ with self.assertRaises(TypeError): ++ d0 = generate_data([2], count=1, dtype='float32') ++ d1 = generate_data([2], count=1, dtype='float64') ++ self._test_static_api( ++ self.func_paddle, self.func_numpy, *rearrange_data(d0, d1) ++ ) ++ ++ def test_1d_2d(self): ++ with self.assertRaises(ValueError): ++ d0 = generate_data([2, 1], count=1, dtype='float64') ++ d1 = generate_data([3], count=1, dtype='float64') ++ self._test_all(rearrange_data(d0, d1)) ++ ++ with self.assertRaises(ValueError): ++ d0 = generate_data([1, 2], count=1, dtype='float64') ++ d1 = generate_data([3], count=1, dtype='float64') ++ self._test_all(rearrange_data(d0, d1)) ++ ++ def test_1d_3d(self): ++ with self.assertRaises(ValueError): ++ d0 = generate_data([2, 3, 1], count=1, dtype='float64') ++ d1 = generate_data([3], count=1, dtype='float64') ++ self._test_all(rearrange_data(d0, d1)) ++ ++ with self.assertRaises(ValueError): ++ d0 = generate_data([1, 1, 1], count=1, dtype='float64') ++ d1 = generate_data([2], count=1, dtype='float64') ++ self._test_all(rearrange_data(d0, d1)) ++ ++ def test_2d_3d(self): ++ with self.assertRaises(ValueError): ++ d0 = generate_data([2, 3, 1], count=1, dtype='float64') ++ d1 = generate_data([1, 3], count=1, dtype='float64') ++ self._test_all(rearrange_data(d0, d1)) ++ ++ with self.assertRaises(ValueError): ++ d0 = generate_data([1, 1, 1], count=1, dtype='float64') ++ d1 = generate_data([1, 2], count=1, dtype='float64') ++ self._test_all(rearrange_data(d0, d1)) ++ ++ ++class ErrorCases0d1d(ErrorCases): ++ """hstack works fine with 0d & 1d""" ++ ++ def test_vstack_0d_1d(self): ++ with self.assertRaises(ValueError): ++ d0 = generate_data([], count=1, dtype='float64') ++ d1 = generate_data([2], count=1, dtype='float64') ++ self._test_all(rearrange_data(d0, d1)) ++ ++ ++class TestErrorHStack(BaseTest, ErrorCases): ++ def setUp(self): ++ self.func_paddle = paddle.hstack ++ self.func_numpy = np.hstack ++ ++ ++class TestErrorVStack(BaseTest, ErrorCases0d1d): ++ def setUp(self): ++ self.func_paddle = paddle.vstack ++ self.func_numpy = np.vstack ++ ++ ++class TestErrorDStack(BaseTest, ErrorCases0d1d): ++ def setUp(self): ++ self.func_paddle = paddle.dstack ++ self.func_numpy = np.dstack ++ ++ ++class TestErrorColumnStack(BaseTest, ErrorCases0d1d): ++ def setUp(self): ++ self.func_paddle = paddle.column_stack ++ self.func_numpy = np.column_stack ++ ++ ++class TestErrorRowStack(BaseTest, ErrorCases0d1d): ++ def setUp(self): ++ self.func_paddle = paddle.row_stack ++ self.func_numpy = np.row_stack ++ ++ ++if __name__ == '__main__': ++ unittest.main() diff --git a/swe-paddle/tasks/PaddlePaddle__Paddle-59127/tests/test.sh b/swe-paddle/tasks/PaddlePaddle__Paddle-59127/tests/test.sh new file mode 100644 index 000000000..40723049d --- /dev/null +++ b/swe-paddle/tasks/PaddlePaddle__Paddle-59127/tests/test.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail + +python -m pytest test/legacy_test/test_stack_extension_api.py -q