diff --git a/swe-paddle/tasks/PaddlePaddle__Paddle-58323/README.md b/swe-paddle/tasks/PaddlePaddle__Paddle-58323/README.md new file mode 100644 index 000000000..d901e68bb --- /dev/null +++ b/swe-paddle/tasks/PaddlePaddle__Paddle-58323/README.md @@ -0,0 +1,37 @@ +# PaddlePaddle__Paddle-58323 + +This directory converts Paddle PR #58323 into a SWE-Paddle community task candidate. + +## Source + +| Field | Value | +| --- | --- | +| Repo | `PaddlePaddle/Paddle` | +| PR | [58323](https://github.com/PaddlePaddle/Paddle/pull/58323) | +| PR title | 【Hackathon 5th No.33】为 Paddle 新增 atleast_1d / atleast_2d / atleast_3d API -part | +| Base commit | `431a0d53bd1578385ebcd3021f08d88ed6f75c70` | +| Merged at | `2023-11-16T12:29:50Z` | +| Hackathon | `5th` task `33` | +| Task type | `feature_enhancement` | +| Resource | CPU | + +## Summary + +Add `atleast_1d`, `atleast_2d`, `atleast_3d` APIs for Paddle, which convert scalar or low-dimensional inputs to tensors with at least the requested number of dimensions, preserving higher-dimensional inputs unchanged. + +## 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-58323/environment/README.md b/swe-paddle/tasks/PaddlePaddle__Paddle-58323/environment/README.md new file mode 100644 index 000000000..7434ad2e7 --- /dev/null +++ b/swe-paddle/tasks/PaddlePaddle__Paddle-58323/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: `431a0d53bd1578385ebcd3021f08d88ed6f75c70` +- Resource: CPU +- Build path: Paddle source checkout at the base commit. This task only involves Python-side changes (tensor manipulation APIs built on existing `reshape`/`unsqueeze`), 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-58323/instruction.md b/swe-paddle/tasks/PaddlePaddle__Paddle-58323/instruction.md new file mode 100644 index 000000000..64e5bb03d --- /dev/null +++ b/swe-paddle/tasks/PaddlePaddle__Paddle-58323/instruction.md @@ -0,0 +1,35 @@ +# 新增 atleast_1d / atleast_2d / atleast_3d API + +## 详细描述 + +为 Paddle 新增 `atleast_1d`、`atleast_2d`、`atleast_3d` 三个张量操作 API。它们将标量或低维输入转换为至少具有指定维度的张量,高维输入保持不变。对标量输入(0-D)会先转换为 1-D 张量,低维输入补到目标维度。 + +要求支持: + +- `paddle.atleast_1d(*inputs, name=None)`:输出至少 1-D + - 0-D 输入 reshape 为 `[1]` + - 1-D 及以上输入原样返回 +- `paddle.atleast_2d(*inputs, name=None)`:输出至少 2-D + - 0-D 输入 reshape 为 `[1, 1]` + - 1-D 输入 unsqueeze 到 `[1, N]` + - 2-D 及以上输入原样返回 +- `paddle.atleast_3d(*inputs, name=None)`:输出至少 3-D + - 0-D、1-D、2-D 输入分别补维到 3-D + - 3-D 及以上输入原样返回 +- 支持可变参数:单输入返回单个 Tensor,多输入返回 Tensor 列表 +- 输入可为 Tensor 或可被 `paddle.to_tensor` 转换的标量 +- 在 `paddle` 顶层命名空间、`paddle.tensor` 命名空间及 tensor 方法中导出 +- 支持的数据类型:float16, float32, float64, int16, int32, int64, int8, uint8, complex64, complex128, bfloat16, bool + +## 验收说明 + +- `atleast_1d` / `atleast_2d` / `atleast_3d` 前向行为与 NumPy 对应 API(`np.atleast_1d/2d/3d`)一致 +- 单输入返回 Tensor,多输入返回 Tensor 列表 +- 高维输入保持不变,低维输入正确补维 +- 静态图与动态图下均可用 + +## 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-58323/proposal.md b/swe-paddle/tasks/PaddlePaddle__Paddle-58323/proposal.md new file mode 100644 index 000000000..bb2c5a42a --- /dev/null +++ b/swe-paddle/tasks/PaddlePaddle__Paddle-58323/proposal.md @@ -0,0 +1,54 @@ +# Task Proposal: PaddlePaddle__Paddle-58323 + +## 1. 来源信息 + +- Instance ID:`PaddlePaddle__Paddle-58323` +- PR 链接:https://github.com/PaddlePaddle/Paddle/pull/58323 +- PR 标题:`【Hackathon 5th No.33】为 Paddle 新增 atleast_1d / atleast_2d / atleast_3d API -part` +- `base_commit`:`431a0d53bd1578385ebcd3021f08d88ed6f75c70` +- merge commit:`557499bd9b511515309bcf8665b215ef7f016e71` +- merged 时间:`2023-11-16T12:29:50Z` +- 后续联系人:megemini + +## 2. 问题一句话 + +为 Paddle 新增 `atleast_1d` / `atleast_2d` / `atleast_3d` API,将标量或低维输入转换为至少具有指定维度的张量。 + +## 3. 为什么适合作为 SWE-Paddle 样本 + +- **真实性**:该任务来自已合入的 Paddle Hackathon 5th 框架开发 PR,关联 RFC(community#679),不是合成任务。 +- **代表性**:它覆盖 Python 层张量操作 API 的完整落地链路:`paddle` 顶层命名空间与 `paddle.tensor` 命名空间导出、tensor 方法注册、可变参数处理(单输入返回 Tensor / 多输入返回列表)以及基于既有 reshape/unsqueeze 的实现。 +- **边界清楚**:目标行为集中在三个 API 的补维语义(0-D/1-D/2-D 输入分别如何补维),测试补丁可直接暴露目标行为。 +- **非平凡性**:需要正确处理可变参数、标量输入转换、不同维度的分支逻辑,并保证与 NumPy 语义一致;非纯配置修改。 + +## 4. 任务类型和标签 + +- 任务类型:`feature_enhancement` +- 执行后端:`cpu` +- 设备范围:`cpu` +- 模块标签:`[python_api, tensor, manipulation]` + +## 5. 验证思路 + +- 目标测试命令:`bash tests/test.sh` +- 目标测试文件:`test/legacy_test/test_atleast_nd.py` +- 修复前预期:在 `base_commit` 上应用 `tests/test.patch` 后,`test_atleast_nd.py` 中 `atleast_1d/2d/3d` 相关测试应 fail(API 不存在)。 +- 修复后预期:继续应用 `solution/code.patch` 后,目标测试应 pass。 +- P2P 候选:`test_atleast_nd.py` 为 PR 新增文件,无存量测试;可从同模块存量 manipulation 测试中选取回归护栏,由 verifier 自动抽取稳定 nodeid。 + +## 6. 环境与资源 + +- 资源需求:CPU +- Paddle 来源:`PaddlePaddle/Paddle` source checkout at `base_commit` +- 是否能提供 Docker:暂无,建议后续补充 source-build Dockerfile +- patch 类型:纯 Python(tensor manipulation API,基于既有 reshape/unsqueeze 实现) +- 环境建议:该样本仅涉及 Python 层改动,source build 后运行 Python 测试即可 +- 最小测试命令:`bash tests/test.sh` +- 是否有 oracle 日志:由 SWE-Paddle verifier 结果另行维护 + +## 7. 风险自查 + +- 泄露风险:正式 `instruction.md` 应描述目标行为和验收标准,不直接指出具体修改行。 +- 环境风险:仅 Python 改动,复现成本低于含 C++ kernel 的样本。 +- flaky 风险:`atleast_nd` 为确定性张量操作,flaky 风险低;verifier 仍应重复运行抽取稳定 F2P/P2P nodeid。 +- 拆分风险:该 PR 的目标集中在新增三个 atleast API,适合作为一个样本。 diff --git a/swe-paddle/tasks/PaddlePaddle__Paddle-58323/solution/code.patch b/swe-paddle/tasks/PaddlePaddle__Paddle-58323/solution/code.patch new file mode 100644 index 000000000..23ef2d433 --- /dev/null +++ b/swe-paddle/tasks/PaddlePaddle__Paddle-58323/solution/code.patch @@ -0,0 +1,237 @@ +diff --git a/python/paddle/__init__.py b/python/paddle/__init__.py +index 92ac2fcbb5..c71af71396 100644 +--- a/python/paddle/__init__.py ++++ b/python/paddle/__init__.py +@@ -199,6 +199,9 @@ from .tensor.logic import ( # noqa: F401 + + + from .tensor.manipulation import ( # noqa: F401 ++ atleast_1d, ++ atleast_2d, ++ atleast_3d, + cast, + cast_, + concat, +@@ -833,6 +836,9 @@ __all__ = [ + 'logspace', + 'reshape', + 'reshape_', ++ 'atleast_1d', ++ 'atleast_2d', ++ 'atleast_3d', + 'reverse', + 'nonzero', + 'CUDAPinnedPlace', +diff --git a/python/paddle/tensor/__init__.py b/python/paddle/tensor/__init__.py +index 1d6d6f8a4f..a1557bb458 100644 +--- a/python/paddle/tensor/__init__.py ++++ b/python/paddle/tensor/__init__.py +@@ -112,6 +112,9 @@ from .logic import allclose # noqa: F401 + from .logic import isclose # noqa: F401 + from .logic import equal_all # noqa: F401 + from .logic import is_tensor # noqa: F401 ++from .manipulation import atleast_1d # noqa: F401 ++from .manipulation import atleast_2d # noqa: F401 ++from .manipulation import atleast_3d # noqa: F401 + from .manipulation import cast # noqa: F401 + from .manipulation import cast_ # noqa: F401 + from .manipulation import concat # noqa: F401 +@@ -731,6 +734,9 @@ tensor_method_func = [ + 'normal_', + 'index_fill', + 'index_fill_', ++ 'atleast_1d', ++ 'atleast_2d', ++ 'atleast_3d', + ] + + # this list used in math_op_patch.py for magic_method bind +diff --git a/python/paddle/tensor/manipulation.py b/python/paddle/tensor/manipulation.py +index 0686a17fa9..3195ffe8a8 100644 +--- a/python/paddle/tensor/manipulation.py ++++ b/python/paddle/tensor/manipulation.py +@@ -3955,6 +3955,184 @@ def reshape_(x, shape, name=None): + return out + + ++def atleast_1d(*inputs, name=None): ++ """ ++ Convert inputs to tensors and return the view with at least 1-dimension. Scalar inputs are converted, ++ one or high-dimensional inputs are preserved. ++ ++ Args: ++ inputs (Tensor|list(Tensor)): One or more tensors. The data type is ``float16``, ``float32``, ``float64``, ``int16``, ``int32``, ``int64``, ``int8``, ``uint8``, ``complex64``, ``complex128``, ``bfloat16`` or ``bool``. ++ name (str, optional): Name for the operation (optional, default is None). For more information, please refer to :ref:`api_guide_Name`. ++ ++ Returns: ++ One Tensor, if there is only one input. ++ List of Tensors, if there are more than one inputs. ++ ++ Examples: ++ .. code-block:: python ++ ++ >>> import paddle ++ ++ >>> # one input ++ >>> x = paddle.to_tensor(123, dtype='int32') ++ >>> out = paddle.atleast_1d(x) ++ >>> print(out) ++ Tensor(shape=[1], dtype=int32, place=Place(cpu), stop_gradient=True, ++ [123]) ++ ++ >>> # more than one inputs ++ >>> x = paddle.to_tensor(123, dtype='int32') ++ >>> y = paddle.to_tensor([1.23], dtype='float32') ++ >>> out = paddle.atleast_1d(x, y) ++ >>> print(out) ++ [Tensor(shape=[1], dtype=int32, place=Place(cpu), stop_gradient=True, ++ [123]), Tensor(shape=[1], dtype=float32, place=Place(cpu), stop_gradient=True, ++ [1.23000002])] ++ ++ >>> # more than 1-D input ++ >>> x = paddle.to_tensor(123, dtype='int32') ++ >>> y = paddle.to_tensor([[1.23]], dtype='float32') ++ >>> out = paddle.atleast_1d(x, y) ++ >>> print(out) ++ [Tensor(shape=[1], dtype=int32, place=Place(cpu), stop_gradient=True, ++ [123]), Tensor(shape=[1, 1], dtype=float32, place=Place(cpu), stop_gradient=True, ++ [[1.23000002]])] ++ """ ++ out = [] ++ for tensor in inputs: ++ tensor = paddle.to_tensor(tensor) ++ if tensor.dim() == 0: ++ result = tensor.reshape((1,)) ++ else: ++ result = tensor ++ out.append(result) ++ ++ if len(out) == 1: ++ return out[0] ++ else: ++ return out ++ ++ ++def atleast_2d(*inputs, name=None): ++ """ ++ Convert inputs to tensors and return the view with at least 2-dimension. Two or high-dimensional inputs are preserved. ++ ++ Args: ++ inputs (Tensor|list(Tensor)): One or more tensors. The data type is ``float16``, ``float32``, ``float64``, ``int16``, ``int32``, ``int64``, ``int8``, ``uint8``, ``complex64``, ``complex128``, ``bfloat16`` or ``bool``. ++ name (str, optional): Name for the operation (optional, default is None). For more information, please refer to :ref:`api_guide_Name`. ++ ++ Returns: ++ One Tensor, if there is only one input. ++ List of Tensors, if there are more than one inputs. ++ ++ Examples: ++ .. code-block:: python ++ ++ >>> import paddle ++ ++ >>> # one input ++ >>> x = paddle.to_tensor(123, dtype='int32') ++ >>> out = paddle.atleast_2d(x) ++ >>> print(out) ++ Tensor(shape=[1, 1], dtype=int32, place=Place(cpu), stop_gradient=True, ++ [[123]]) ++ ++ >>> # more than one inputs ++ >>> x = paddle.to_tensor(123, dtype='int32') ++ >>> y = paddle.to_tensor([1.23], dtype='float32') ++ >>> out = paddle.atleast_2d(x, y) ++ >>> print(out) ++ [Tensor(shape=[1, 1], dtype=int32, place=Place(cpu), stop_gradient=True, ++ [[123]]), Tensor(shape=[1, 1], dtype=float32, place=Place(cpu), stop_gradient=True, ++ [[1.23000002]])] ++ ++ >>> # more than 2-D input ++ >>> x = paddle.to_tensor(123, dtype='int32') ++ >>> y = paddle.to_tensor([[[1.23]]], dtype='float32') ++ >>> out = paddle.atleast_2d(x, y) ++ >>> print(out) ++ [Tensor(shape=[1, 1], dtype=int32, place=Place(cpu), stop_gradient=True, ++ [[123]]), Tensor(shape=[1, 1, 1], dtype=float32, place=Place(cpu), stop_gradient=True, ++ [[[1.23000002]]])] ++ """ ++ out = [] ++ for tensor in inputs: ++ tensor = paddle.to_tensor(tensor) ++ if tensor.dim() == 0: ++ result = tensor.reshape((1, 1)) ++ elif tensor.dim() == 1: ++ result = paddle.unsqueeze(tensor, axis=0) ++ else: ++ result = tensor ++ out.append(result) ++ ++ if len(out) == 1: ++ return out[0] ++ else: ++ return out ++ ++ ++def atleast_3d(*inputs, name=None): ++ """ ++ Convert inputs to tensors and return the view with at least 3-dimension. Three or high-dimensional inputs are preserved. ++ ++ Args: ++ inputs (Tensor|list(Tensor)): One or more tensors. The data type is ``float16``, ``float32``, ``float64``, ``int16``, ``int32``, ``int64``, ``int8``, ``uint8``, ``complex64``, ``complex128``, ``bfloat16`` or ``bool``. ++ name (str, optional): Name for the operation (optional, default is None). For more information, please refer to :ref:`api_guide_Name`. ++ ++ Returns: ++ One Tensor, if there is only one input. ++ List of Tensors, if there are more than one inputs. ++ ++ Examples: ++ .. code-block:: python ++ ++ >>> import paddle ++ ++ >>> # one input ++ >>> x = paddle.to_tensor(123, dtype='int32') ++ >>> out = paddle.atleast_3d(x) ++ >>> print(out) ++ Tensor(shape=[1, 1, 1], dtype=int32, place=Place(cpu), stop_gradient=True, ++ [[[123]]]) ++ ++ >>> # more than one inputs ++ >>> x = paddle.to_tensor(123, dtype='int32') ++ >>> y = paddle.to_tensor([1.23], dtype='float32') ++ >>> out = paddle.atleast_3d(x, y) ++ >>> print(out) ++ [Tensor(shape=[1, 1, 1], dtype=int32, place=Place(cpu), stop_gradient=True, ++ [[[123]]]), Tensor(shape=[1, 1, 1], dtype=float32, place=Place(cpu), stop_gradient=True, ++ [[[1.23000002]]])] ++ ++ >>> # more than 3-D input ++ >>> x = paddle.to_tensor(123, dtype='int32') ++ >>> y = paddle.to_tensor([[[[1.23]]]], dtype='float32') ++ >>> out = paddle.atleast_3d(x, y) ++ >>> print(out) ++ [Tensor(shape=[1, 1, 1], dtype=int32, place=Place(cpu), stop_gradient=True, ++ [[[123]]]), Tensor(shape=[1, 1, 1, 1], dtype=float32, place=Place(cpu), stop_gradient=True, ++ [[[[1.23000002]]]])] ++ """ ++ out = [] ++ for tensor in inputs: ++ tensor = paddle.to_tensor(tensor) ++ if tensor.dim() == 0: ++ result = tensor.reshape((1, 1, 1)) ++ elif tensor.dim() == 1: ++ result = paddle.unsqueeze(tensor, axis=[0, 2]) ++ elif tensor.dim() == 2: ++ result = paddle.unsqueeze(tensor, axis=2) ++ else: ++ result = tensor ++ out.append(result) ++ ++ if len(out) == 1: ++ return out[0] ++ else: ++ return out ++ ++ + def gather_nd(x, index, name=None): + """ + diff --git a/swe-paddle/tasks/PaddlePaddle__Paddle-58323/tests/test.patch b/swe-paddle/tasks/PaddlePaddle__Paddle-58323/tests/test.patch new file mode 100644 index 000000000..81fd1e53f --- /dev/null +++ b/swe-paddle/tasks/PaddlePaddle__Paddle-58323/tests/test.patch @@ -0,0 +1,464 @@ +diff --git a/test/legacy_test/test_atleast_nd.py b/test/legacy_test/test_atleast_nd.py +new file mode 100644 +index 0000000000..781534dde2 +--- /dev/null ++++ b/test/legacy_test/test_atleast_nd.py +@@ -0,0 +1,458 @@ ++# Copyright (c) 2022 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 unittest ++ ++import numpy as np ++import parameterized as param ++ ++import paddle ++from paddle.base import core ++from paddle.pir_utils import test_with_pir_api ++ ++RTOL = 1e-5 ++ATOL = 1e-8 ++ ++PLACES = [paddle.CPUPlace()] + ( ++ [paddle.CUDAPlace(0)] if core.is_compiled_with_cuda() else [] ++) ++ ++ ++def func_ref(func, *inputs): ++ """ref func, just for convenience""" ++ return func(*inputs) ++ ++ ++test_list = [ ++ (paddle.atleast_1d, np.atleast_1d), ++ (paddle.atleast_2d, np.atleast_2d), ++ (paddle.atleast_3d, np.atleast_3d), ++] ++ ++ ++def generate_data(ndim, count=1, max_size=4, mix=False, dtype='int32'): ++ """generate test data ++ ++ Args: ++ ndim(int): dim of inputs ++ count(int): input count for each dim ++ max_size(int): max size for each dim ++ mix(bool): mix data types or not, like a data list [123, np.array(123), paddle.to_tensor(123), ...] ++ dtype(str): dtype ++ ++ Returns: ++ a list of data like: ++ [[data, dtype, shape, name], [data, dtype, shape, name] ... ] ++ """ ++ ++ rtn = [] ++ for d in range(ndim): ++ data = [ ++ np.random.randint( ++ 0, ++ 255, ++ size=[np.random.randint(1, max_size) for _ in range(d)], ++ dtype=dtype, ++ ) ++ for _ in range(count) ++ ] ++ ++ if mix: ++ ++ def _mix_data(data, idx): ++ if idx % 3 == 0: ++ return data.tolist() ++ elif idx % 3 == 1: ++ return data ++ elif idx % 3 == 2: ++ return paddle.to_tensor(data) ++ ++ # mix normal/numpy/tensor ++ rtn.append( ++ list( ++ zip( ++ *[ ++ [ ++ _mix_data(_data, idx), ++ str(_data.dtype), ++ _data.shape, ++ '{}d_{}_{}'.format(d, idx, 'mix'), ++ ] ++ for idx, _data in enumerate(data) ++ ] ++ ) ++ ) ++ ) ++ ++ else: ++ # normal ++ rtn.append( ++ list( ++ zip( ++ *[ ++ [ ++ _data.tolist(), ++ str(_data.dtype), ++ _data.shape, ++ '{}d_{}_{}'.format(d, idx, 'normal'), ++ ] ++ for idx, _data in enumerate(data) ++ ] ++ ) ++ ) ++ ) ++ # numpy ++ rtn.append( ++ list( ++ zip( ++ *[ ++ [ ++ _data, ++ str(_data.dtype), ++ _data.shape, ++ '{}d_{}_{}'.format(d, idx, 'numpy'), ++ ] ++ for idx, _data in enumerate(data) ++ ] ++ ) ++ ) ++ ) ++ # tensor ++ rtn.append( ++ list( ++ zip( ++ *[ ++ [ ++ paddle.to_tensor(_data), ++ str(_data.dtype), ++ _data.shape, ++ '{}d_{}_{}'.format(d, idx, 'tensor'), ++ ] ++ for idx, _data in enumerate(data) ++ ] ++ ) ++ ) ++ ) ++ return rtn ++ ++ ++class BaseTest(unittest.TestCase): ++ """Test in each `PLACES`, each `test_list`, and in `static/dygraph`""" ++ ++ @test_with_pir_api ++ def _test_static_api( ++ self, ++ inputs: list, ++ dtypes: list, ++ shapes: list, ++ names: list, ++ ): ++ """Test `static`, convert `Tensor` to `numpy array` before feed into graph""" ++ for place in PLACES: ++ paddle.enable_static() ++ for func, func_type in test_list: ++ with paddle.static.program_guard(paddle.static.Program()): ++ x = [] ++ feed = {} ++ for i in range(len(inputs)): ++ input = inputs[i] ++ shape = shapes[i] ++ dtype = dtypes[i] ++ name = names[i] ++ x.append(paddle.static.data(name, shape, dtype)) ++ # the data feeded should NOT be a Tensor ++ feed[name] = ( ++ input.numpy() ++ if isinstance(input, paddle.Tensor) ++ else input ++ ) ++ ++ out = func(*x) ++ exe = paddle.static.Executor(place) ++ res = exe.run(feed=feed, fetch_list=[out]) ++ ++ # unwrap inputs when lenght 1 ++ if len(inputs) == 1: ++ res = res[0] ++ ++ out_ref = func_ref( ++ func_type, ++ *[ ++ input.numpy() ++ if isinstance(input, paddle.Tensor) ++ else input ++ for input in inputs ++ ] ++ ) ++ ++ for n, p in zip(out_ref, res): ++ np.testing.assert_allclose(n, p, rtol=RTOL, atol=ATOL) ++ ++ def _test_dygraph_api( ++ self, ++ inputs: list, ++ dtypes: list, ++ shapes: list, ++ names: list, ++ ): ++ """Test `dygraph`, and check grads""" ++ for place in PLACES: ++ paddle.disable_static(place) ++ for func, func_type in test_list: ++ out = func(*inputs) ++ out_ref = func_ref( ++ func_type, ++ *[ ++ input.numpy() ++ if isinstance(input, paddle.Tensor) ++ else input ++ for input in 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) ++ ++ ++@param.parameterized_class( ++ ('inputs', 'dtypes', 'shapes', 'names'), ++ (generate_data(5, count=1, max_size=4, dtype='int32')), ++) ++class TestAtleastDim(BaseTest): ++ """test dim from 0 to 5""" ++ ++ def test_all(self): ++ self._test_dygraph_api( ++ self.inputs, self.dtypes, self.shapes, self.names ++ ) ++ self._test_static_api(self.inputs, self.dtypes, self.shapes, self.names) ++ ++ ++@param.parameterized_class( ++ ('inputs', 'dtypes', 'shapes', 'names'), ++ (generate_data(5, count=3, max_size=4, dtype='int32')), ++) ++class TestAtleastDimMoreInputs(BaseTest): ++ """test inputs of 3 tensors""" ++ ++ def test_all(self): ++ self._test_dygraph_api( ++ self.inputs, self.dtypes, self.shapes, self.names ++ ) ++ self._test_static_api(self.inputs, self.dtypes, self.shapes, self.names) ++ ++ ++@param.parameterized_class( ++ ('inputs', 'dtypes', 'shapes', 'names'), ++ (generate_data(5, count=5, max_size=4, mix=True, dtype='int32')), ++) ++class TestAtleastMixData(BaseTest): ++ """test mix number/numpy/tensor""" ++ ++ def test_all(self): ++ self._test_dygraph_api( ++ self.inputs, self.dtypes, self.shapes, self.names ++ ) ++ self._test_static_api(self.inputs, self.dtypes, self.shapes, self.names) ++ ++ ++@param.parameterized_class( ++ ('inputs', 'dtypes', 'shapes', 'names'), ++ ( ++ ( ++ ( ++ 123, ++ np.array([123], dtype='int32'), ++ paddle.to_tensor([[123]], dtype='int32'), ++ [[[123]]], ++ np.array([[[[123]]]], dtype='int32'), ++ paddle.to_tensor([[[[[123]]]]], dtype='int32'), ++ ), ++ ('int32', 'int32', 'int32', 'int32', 'int32', 'int32'), ++ ((), (1,), (1, 1), (1, 1, 1), (1, 1, 1, 1), (1, 1, 1, 1, 1)), ++ ( ++ '0_mixdim', ++ '1_mixdim', ++ '2_mixdim', ++ '3_mixdim', ++ '4_mixdim', ++ '5_mixdim', ++ ), ++ ), ++ ), ++) ++class TestAtleastMixDim(BaseTest): ++ """test mix dim""" ++ ++ def test_all(self): ++ self._test_dygraph_api( ++ self.inputs, self.dtypes, self.shapes, self.names ++ ) ++ self._test_static_api(self.inputs, self.dtypes, self.shapes, self.names) ++ ++ ++@param.parameterized_class( ++ ('inputs', 'dtypes', 'shapes', 'names'), ++ ( ++ ( ++ ( ++ paddle.to_tensor(True, dtype='bool'), ++ paddle.to_tensor(0.1, dtype='float16'), ++ paddle.to_tensor(0.1, dtype='float32'), ++ paddle.to_tensor(0.1, dtype='float64'), ++ paddle.to_tensor(1, dtype='int8'), ++ paddle.to_tensor(1, dtype='int16'), ++ paddle.to_tensor(1, dtype='int32'), ++ paddle.to_tensor(1, dtype='int64'), ++ paddle.to_tensor(1, dtype='uint8'), ++ paddle.to_tensor(1 + 1j, dtype='complex64'), ++ paddle.to_tensor(1 + 1j, dtype='complex128'), ++ paddle.to_tensor(0.1, dtype='bfloat16'), ++ ), ++ ( ++ 'bool', ++ 'float16', ++ 'float32', ++ 'float64', ++ 'int8', ++ 'int16', ++ 'int32', ++ 'int64', ++ 'uint8', ++ 'complex64', ++ 'complex128', ++ 'bfloat16', ++ ), ++ ( ++ (), ++ (), ++ (), ++ (), ++ (), ++ (), ++ (), ++ (), ++ (), ++ (), ++ (), ++ (), ++ ), ++ ( ++ '0_mixdtype', ++ '1_mixdtype', ++ '2_mixdtype', ++ '3_mixdtype', ++ '4_mixdtype', ++ '5_mixdtype', ++ '6_mixdtype', ++ '7_mixdtype', ++ '8_mixdtype', ++ '9_mixdtype', ++ '10_mixdtype', ++ '11_mixdtype', ++ ), ++ ), ++ ), ++) ++class TestAtleastMixDtypes(BaseTest): ++ """test mix dtypes""" ++ ++ def test_all(self): ++ self._test_dygraph_api( ++ self.inputs, self.dtypes, self.shapes, self.names ++ ) ++ self._test_static_api(self.inputs, self.dtypes, self.shapes, self.names) ++ ++ ++@param.parameterized_class( ++ ('inputs', 'dtypes', 'shapes', 'names'), ++ ( ++ (((123, [123]),), ('int32',), ((),), ('0_combine',)), ++ ( ++ ((np.array([123], dtype='int32'), [[123]]),), ++ ('int32',), ++ ((),), ++ ('1_combine',), ++ ), ++ ( ++ ( ++ ( ++ np.array([[123]], dtype='int32'), ++ paddle.to_tensor([[[123]]], dtype='int32'), ++ ), ++ ), ++ ('int32',), ++ ((),), ++ ('2_combine',), ++ ), ++ ), ++) ++class TestAtleastErrorCombineInputs(BaseTest): ++ """test combine inputs, like: `at_leastNd((x, y))`, where paddle treats like numpy""" ++ ++ def test_all(self): ++ with self.assertRaises(ValueError): ++ self._test_dygraph_api( ++ self.inputs, self.dtypes, self.shapes, self.names ++ ) ++ ++ with self.assertRaises(ValueError): ++ self._test_static_api( ++ self.inputs, self.dtypes, self.shapes, self.names ++ ) ++ ++ ++class TestAtleastAsTensorMethod(unittest.TestCase): ++ def test_as_tensor_method(self): ++ input = 123 ++ tensor = paddle.to_tensor(input) ++ ++ for place in PLACES: ++ paddle.disable_static(place) ++ ++ out = tensor.atleast_1d() ++ out_ref = np.atleast_1d(input) ++ ++ for n, p in zip(out_ref, out): ++ np.testing.assert_allclose(n, p.numpy(), rtol=RTOL, atol=ATOL) ++ ++ out = tensor.atleast_2d() ++ out_ref = np.atleast_2d(input) ++ ++ for n, p in zip(out_ref, out): ++ np.testing.assert_allclose(n, p.numpy(), rtol=RTOL, atol=ATOL) ++ ++ out = tensor.atleast_3d() ++ out_ref = np.atleast_3d(input) ++ ++ for n, p in zip(out_ref, out): ++ np.testing.assert_allclose(n, p.numpy(), rtol=RTOL, atol=ATOL) ++ ++ ++if __name__ == '__main__': ++ unittest.main() diff --git a/swe-paddle/tasks/PaddlePaddle__Paddle-58323/tests/test.sh b/swe-paddle/tasks/PaddlePaddle__Paddle-58323/tests/test.sh new file mode 100644 index 000000000..7e848c027 --- /dev/null +++ b/swe-paddle/tasks/PaddlePaddle__Paddle-58323/tests/test.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +set -euo pipefail + +# P2P tests (pass-to-pass) +python -m pytest test/legacy_test/test_reshape_op.py -q + +# F2P tests (fail-to-pass) +python -m pytest test/legacy_test/test_atleast_nd.py -q