diff --git a/swe-paddle/tasks/PaddlePaddle__Paddle-74439/README.md b/swe-paddle/tasks/PaddlePaddle__Paddle-74439/README.md new file mode 100644 index 000000000..f25215c15 --- /dev/null +++ b/swe-paddle/tasks/PaddlePaddle__Paddle-74439/README.md @@ -0,0 +1,44 @@ +# PaddlePaddle__Paddle-74439 + +This directory converts Paddle PR #74439 into a SWE-Paddle community task candidate. + +## Source + +| Field | Value | +| --- | --- | +| Repo | `PaddlePaddle/Paddle` | +| PR | [74439](https://github.com/PaddlePaddle/Paddle/pull/74439) | +| PR title | `[API compatibility] add paddle.ravel` | +| Base commit | `cb81162732f15ae02e82b07f8462e04b093c2464` | +| Merged at | `2025-08-08` | +| Task type | `feature_enhancement` | +| Resource | CPU | + +## Summary + +Add a public `paddle.ravel` API that returns a one-dimensional flattened result for tensors of any rank, including scalars and empty tensors. + +## Why This Is A Good SWE-Paddle Candidate + +- It comes from a merged Paddle API-compatibility pull request with a small, well-defined production scope. +- The target behavior is user-visible through both `paddle.ravel` and `paddle.tensor.ravel`. +- The existing `flatten` API provides a stable regression guard for behavior that must remain unchanged. +- The Python-only implementation can be verified deterministically with AST overlays and controlled doubles without a Paddle source build. + +## Files + +- `proposal.md`: candidate proposal for maintainer triage. +- `instruction.md`: self-contained problem statement for the coding agent. +- `solution/code.patch`: production-only 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. +- `README.md`: task overview and verification entrypoint. + +## Verification + +```bash +bash tests/test.sh +``` + +Expected behavior: applying `tests/test.patch` to the base commit should preserve the existing `flatten` regression test while failing the new `ravel` behavior tests; applying both patches should make all target tests pass. diff --git a/swe-paddle/tasks/PaddlePaddle__Paddle-74439/environment/README.md b/swe-paddle/tasks/PaddlePaddle__Paddle-74439/environment/README.md new file mode 100644 index 000000000..73ddaccad --- /dev/null +++ b/swe-paddle/tasks/PaddlePaddle__Paddle-74439/environment/README.md @@ -0,0 +1,27 @@ +# Environment Notes + +This candidate is part of the SWE-Paddle community task set. + +## Expected Environment + +- Repository: `PaddlePaddle/Paddle` +- Base commit: `cb81162732f15ae02e82b07f8462e04b093c2464` +- Resource: CPU +- GPU required: no +- Build path: Paddle source checkout at the base commit. This Python-only task is verified with AST overlays and controlled doubles; a source build is not required. + +## 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-74439/instruction.md b/swe-paddle/tasks/PaddlePaddle__Paddle-74439/instruction.md new file mode 100644 index 000000000..4471ddbb9 --- /dev/null +++ b/swe-paddle/tasks/PaddlePaddle__Paddle-74439/instruction.md @@ -0,0 +1,23 @@ +# 新增 `paddle.ravel` API + +## 详细描述 + +Paddle 当前缺少用于完整展平 Tensor 的 `ravel` 公共接口。调用方需要能够将任意维度的 Tensor 转换为一维 Tensor,同时保持原有的元素顺序和数据类型。需要新增 `paddle.ravel`,并使其能够处理标量、一维 Tensor、多维 Tensor,以及包含零长度维度的 Tensor。该接口应同时支持动态图和静态图模式,并保持正确的梯度传播行为。同时保持现有 `flatten` 接口的合法调用方式和行为不得受到影响。 + +## 验收说明 + +* `paddle.ravel` 应作为公开 API 提供,并能够从 `paddle` 和 `paddle.tensor` 命名空间访问 +* API 应支持通过 `input` 参数传入 Tensor +* 返回结果应为一维 Tensor,元素顺序和数据类型应与输入保持一致 +* 标量输入应得到只包含一个元素的一维结果 +* 一维和多维 Tensor 应得到符合完整展平语义的结果 +* 包含零长度维度的 Tensor 应得到形状正确的空一维结果 +* API 应能够在动态图和静态图模式下正常使用 +* 动态图模式下的反向传播行为应正确 +* 现有 `flatten` 接口的行为不得发生变化 + +## 技术要求 + +* 熟悉 Paddle Python Tensor API 及公共接口导出方式 +* 理解 Tensor 的形状、维数和完整展平语义 +* 了解 Paddle 动态图、静态图和自动求导机制 diff --git a/swe-paddle/tasks/PaddlePaddle__Paddle-74439/proposal.md b/swe-paddle/tasks/PaddlePaddle__Paddle-74439/proposal.md new file mode 100644 index 000000000..c1ba7b42a --- /dev/null +++ b/swe-paddle/tasks/PaddlePaddle__Paddle-74439/proposal.md @@ -0,0 +1,53 @@ +# Task Proposal: PaddlePaddle__Paddle-74439 + +## 1. 来源信息 + +* Instance ID:`PaddlePaddle__Paddle-74439` +* PR 链接:https://github.com/PaddlePaddle/Paddle/pull/74439 +* PR 标题:`[API compatibility] add paddle.ravel` +* `base_commit`:`cb81162732f15ae02e82b07f8462e04b093c2464` +* merged 时间:`2025-08-08` +* 你的身份:熟悉该模块的 contributor +* 后续联系人:TBD + +## 2. 问题一句话 + +为 Paddle 新增公开的 `ravel` API,使任意维度的 Tensor 都能够在保持元素顺序的前提下完整展平为一维结果。 + +## 3. 为什么适合作为 SWE-Paddle 样本 + +* **真实性**:该任务来自已经合入 Paddle `develop` 分支的 API compatibility PR #74439,不是人工构造的需求。 +* **代表性**:该任务涉及 Tensor 形状变换、公共 API 导出、动态图与静态图支持,以及不同维度输入的边界行为。 +* **边界清楚**:production change 集中在三个 Python 文件中,功能范围明确;原 PR 测试覆盖 `ravel` 的前向结果、反向传播和不同维度输入。 +* **非平凡性**:任务不仅需要新增公开接口,还要正确处理标量、一维、多维和空 Tensor,并保证现有 `flatten` 行为不受影响。 + +## 4. 任务类型和标签 + +* 任务类型:`feature_enhancement` +* 执行后端:`cpu` +* 设备范围:`cpu_only` +* 模块标签:`[tensor, manipulation, api_compatibility, flatten, python_api]` + +## 5. 验证思路 + +* 目标测试命令:`bash tests/test.sh` +* 目标测试文件:`test/swe_paddle/test_pr74439_ravel.py` +* 修复前预期:现有 `flatten` 动态图路径的回归测试应通过;`ravel` 的公共导出、展平结果和边界输入测试应失败。 +* 修复后预期:继续应用 `solution/code.patch` 后,现有 `flatten` 测试应继续通过;`ravel` 对标量、一维、多维和空 Tensor 的测试,以及公共命名空间导出测试均应通过。 +* P2P 候选:现有 `flatten` 在 dynamic/PIR 路径下的参数处理、底层调用和返回行为保持不变。 + +## 6. 环境与资源 + +* 资源需求:CPU +* Paddle 来源:`PaddlePaddle/Paddle` source checkout at `base_commit` +* 是否能提供 Docker:暂无 +* patch 类型:Python-only +* 最小测试命令:`bash tests/test.sh` +* 是否有 oracle 日志:由 SWE-Paddle verifier 结果另行维护 + +## 7. 风险自查 + +* 泄露风险:`instruction.md` 只描述 `ravel` 的公开接口、展平语义、边界输入和兼容性要求,不透露 Gold patch 的具体函数调用方式或修改位置。 +* 环境风险:测试不导入历史 Paddle package 的完整运行环境,而是执行 source checkout 中相关的 Python 控制流程,避免对 native extension 的依赖。 +* flaky 风险:测试使用固定输入并验证确定性的形状、元素顺序和对象行为,不依赖随机数、GPU、设备调度或异步执行。 +* 拆分风险:公共命名空间导出、完整展平语义和边界输入支持共同构成 `ravel` API 的完整能力,适合作为单个任务。 diff --git a/swe-paddle/tasks/PaddlePaddle__Paddle-74439/solution/code.patch b/swe-paddle/tasks/PaddlePaddle__Paddle-74439/solution/code.patch new file mode 100644 index 000000000..198a44ab7 --- /dev/null +++ b/swe-paddle/tasks/PaddlePaddle__Paddle-74439/solution/code.patch @@ -0,0 +1,83 @@ +diff --git a/python/paddle/__init__.py b/python/paddle/__init__.py +index a138b8d52324f1dd99ddc9526270e25cf529fbbb..4ebc15fdc9753cc7b70071b143974f5140b81239 100644 +--- a/python/paddle/__init__.py ++++ b/python/paddle/__init__.py +@@ -328,6 +328,7 @@ from .tensor.manipulation import ( + masked_scatter_, + moveaxis, + put_along_axis, ++ ravel, + repeat_interleave, + reshape, + reshape_, +@@ -1094,6 +1095,7 @@ __all__ = [ + 'std', + 'flatten', + 'flatten_', ++ 'ravel', + 'asin', + 'multiply', + 'multiply_', +diff --git a/python/paddle/tensor/__init__.py b/python/paddle/tensor/__init__.py +index 3f0495ac94fffc7bdcc95a557c40f57900136351..32425a36ee145d5851b81a782ff30bec5b9a3d5e 100644 +--- a/python/paddle/tensor/__init__.py ++++ b/python/paddle/tensor/__init__.py +@@ -193,6 +193,7 @@ from .manipulation import ( # noqa: F401 + moveaxis, + put_along_axis, + put_along_axis_, ++ ravel, + repeat_interleave, + reshape, + reshape_, +diff --git a/python/paddle/tensor/manipulation.py b/python/paddle/tensor/manipulation.py +index 9904dd9b1ee64d89e732f329eb871e5bd85a8954..857554b5dd1f2a005437b8548f5027ef9e79204d 100644 +--- a/python/paddle/tensor/manipulation.py ++++ b/python/paddle/tensor/manipulation.py +@@ -1992,6 +1992,46 @@ def flatten( + return out + + ++def ravel(input: Tensor) -> Tensor: ++ """ ++ Return a contiguous flattened tensor. A copy is made only if needed. ++ Note: ++ The output Tensor will share data with origin Tensor and doesn't have a Tensor copy in ``dygraph`` mode. ++ If you want to use the Tensor copy version, please use `Tensor.clone` like ``ravel_clone_x = x.ravel().clone()``. ++ For example: ++ ++ .. code-block:: text ++ Case 1: ++ Given ++ X.shape = (3, 100, 100, 4) ++ ++ We get: ++ Out.shape = (3 * 100 * 100 * 4) ++ Args: ++ x (Tensor): A tensor of number of dimensions >= axis. A tensor with data type float16, float32, ++ float64, int8, int32, int64, uint8. ++ ++ Returns: ++ Tensor: A tensor with the contents of the input tensor, whose input axes are flattened by indicated :attr:`start_axis` and :attr:`stop_axis`, and data type is the same as input :attr:`x`. ++ ++ Examples: ++ ++ .. code-block:: python ++ ++ >>> import paddle ++ ++ >>> image_shape=(2, 3, 4, 4) ++ ++ >>> x = paddle.arange(end=image_shape[0] * image_shape[1] * image_shape[2] * image_shape[3]) ++ >>> img = paddle.reshape(x, image_shape) ++ ++ >>> out = paddle.ravel(img) ++ >>> print(out.shape) ++ [96] ++ """ ++ return flatten(input) ++ ++ + @inplace_apis_in_dygraph_only + def flatten_( + x: Tensor, start_axis: int = 0, stop_axis: int = -1, name: str | None = None diff --git a/swe-paddle/tasks/PaddlePaddle__Paddle-74439/tests/test.patch b/swe-paddle/tasks/PaddlePaddle__Paddle-74439/tests/test.patch new file mode 100644 index 000000000..096db1898 --- /dev/null +++ b/swe-paddle/tasks/PaddlePaddle__Paddle-74439/tests/test.patch @@ -0,0 +1,154 @@ +diff --git a/test/swe_paddle/test_pr74439_ravel.py b/test/swe_paddle/test_pr74439_ravel.py +new file mode 100644 +--- /dev/null ++++ b/test/swe_paddle/test_pr74439_ravel.py +@@ -0,0 +1,149 @@ ++import ast ++import copy ++import sys ++import types ++from pathlib import Path ++ ++import numpy as np ++ ++TARGET = Path("python/paddle/tensor/manipulation.py") ++ROOT_INIT = Path("python/paddle/__init__.py") ++TENSOR_INIT = Path("python/paddle/tensor/__init__.py") ++ ++ ++def _extract_function(name, namespace): ++ tree = ast.parse(TARGET.read_text(encoding="utf-8"), filename=str(TARGET)) ++ node = next( ++ ( ++ copy.deepcopy(item) ++ for item in tree.body ++ if isinstance(item, (ast.FunctionDef, ast.AsyncFunctionDef)) ++ and item.name == name ++ ), ++ None, ++ ) ++ assert node is not None, f"paddle.tensor.manipulation must provide {name}" ++ node.decorator_list = [] ++ ast.fix_missing_locations(node) ++ scope = dict(namespace) ++ exec(compile(ast.Module(body=[node], type_ignores=[]), str(TARGET), "exec"), scope) ++ return scope[name] ++ ++ ++def _execute_public_import(path, package_name): ++ tree = ast.parse(path.read_text(encoding="utf-8"), filename=str(path)) ++ node = next( ++ ( ++ copy.deepcopy(item) ++ for item in tree.body ++ if isinstance(item, ast.ImportFrom) ++ and any(alias.name == "ravel" for alias in item.names) ++ ), ++ None, ++ ) ++ assert node is not None, f"{path} must publicly import ravel" ++ assert node.level == 1 and node.module ++ ++ module_parts = node.module.split(".") ++ module_name = ".".join([package_name, *module_parts]) ++ module_names = [package_name] ++ for index in range(1, len(module_parts)): ++ module_names.append(".".join([package_name, *module_parts[:index]])) ++ module_names.append(module_name) ++ ++ saved = {name: sys.modules.get(name) for name in module_names} ++ for name in module_names[:-1]: ++ package = types.ModuleType(name) ++ package.__path__ = [] ++ sys.modules[name] = package ++ ++ imported = types.ModuleType(module_name) ++ marker = object() ++ for alias in node.names: ++ setattr(imported, alias.name, marker if alias.name == "ravel" else object()) ++ sys.modules[module_name] = imported ++ ++ try: ++ scope = {"__package__": package_name, "__name__": f"{package_name}.probe"} ++ ast.fix_missing_locations(node) ++ exec(compile(ast.Module(body=[node], type_ignores=[]), str(path), "exec"), scope) ++ finally: ++ for name in reversed(module_names): ++ previous = saved[name] ++ if previous is None: ++ sys.modules.pop(name, None) ++ else: ++ sys.modules[name] = previous ++ return scope, marker ++ ++ ++class _Variable: ++ def __init__(self, shape): ++ self.shape = shape ++ ++ ++class _PirValue: ++ pass ++ ++ ++def test_existing_flatten_dynamic_path_remains_compatible(): ++ calls = [] ++ marker = object() ++ ++ def native_flatten(value, start_axis, stop_axis): ++ calls.append((value, start_axis, stop_axis)) ++ return marker ++ ++ paddle = types.SimpleNamespace(pir=types.SimpleNamespace(Value=_PirValue)) ++ function = _extract_function( ++ "flatten", ++ { ++ "Tensor": object, ++ "Variable": _Variable, ++ "paddle": paddle, ++ "in_dynamic_or_pir_mode": lambda: True, ++ "_C_ops": types.SimpleNamespace(flatten=native_flatten), ++ "check_variable_and_dtype": lambda *args, **kwargs: None, ++ "LayerHelper": object, ++ }, ++ ) ++ value = _Variable((2, 3, 4)) ++ assert function(value, start_axis=1, stop_axis=-1) is marker ++ assert calls == [(value, 1, 2)] ++ ++ ++def test_ravel_flattens_scalar_multidimensional_and_empty_inputs(): ++ def controlled_flatten(value, *args, **kwargs): ++ return np.asarray(value).reshape(-1) ++ ++ function = _extract_function( ++ "ravel", ++ { ++ "Tensor": object, ++ "flatten": controlled_flatten, ++ "reshape": lambda value, shape: np.asarray(value).reshape(shape), ++ "paddle": types.SimpleNamespace( ++ flatten=controlled_flatten, ++ reshape=lambda value, shape: np.asarray(value).reshape(shape), ++ ), ++ "np": np, ++ }, ++ ) ++ cases = [ ++ np.array(5.0, dtype="float32"), ++ np.array([7.0, 8.0, 9.0], dtype="float32"), ++ np.arange(24, dtype="float32").reshape(2, 3, 4), ++ np.array([], dtype="float32").reshape(0, 3), ++ ] ++ for value in cases: ++ result = function(value) ++ expected = value.reshape(-1) ++ assert result.ndim == 1 ++ np.testing.assert_array_equal(result, expected) ++ ++ ++def test_ravel_is_reexported_from_public_namespaces(): ++ tensor_scope, tensor_marker = _execute_public_import(TENSOR_INIT, "swe_fake_paddle_tensor") ++ assert tensor_scope.get("ravel") is tensor_marker ++ root_scope, root_marker = _execute_public_import(ROOT_INIT, "swe_fake_paddle") ++ assert root_scope.get("ravel") is root_marker diff --git a/swe-paddle/tasks/PaddlePaddle__Paddle-74439/tests/test.sh b/swe-paddle/tasks/PaddlePaddle__Paddle-74439/tests/test.sh new file mode 100644 index 000000000..d250225d6 --- /dev/null +++ b/swe-paddle/tasks/PaddlePaddle__Paddle-74439/tests/test.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail + +python -m pytest test/swe_paddle/test_pr74439_ravel.py -q