Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 44 additions & 0 deletions swe-paddle/tasks/PaddlePaddle__Paddle-74439/README.md
Original file line number Diff line number Diff line change
@@ -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.
27 changes: 27 additions & 0 deletions swe-paddle/tasks/PaddlePaddle__Paddle-74439/environment/README.md
Original file line number Diff line number Diff line change
@@ -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.
23 changes: 23 additions & 0 deletions swe-paddle/tasks/PaddlePaddle__Paddle-74439/instruction.md
Original file line number Diff line number Diff line change
@@ -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 动态图、静态图和自动求导机制
53 changes: 53 additions & 0 deletions swe-paddle/tasks/PaddlePaddle__Paddle-74439/proposal.md
Original file line number Diff line number Diff line change
@@ -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 的完整能力,适合作为单个任务。
83 changes: 83 additions & 0 deletions swe-paddle/tasks/PaddlePaddle__Paddle-74439/solution/code.patch
Original file line number Diff line number Diff line change
@@ -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
154 changes: 154 additions & 0 deletions swe-paddle/tasks/PaddlePaddle__Paddle-74439/tests/test.patch
Original file line number Diff line number Diff line change
@@ -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
4 changes: 4 additions & 0 deletions swe-paddle/tasks/PaddlePaddle__Paddle-74439/tests/test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#!/usr/bin/env bash
set -euo pipefail

python -m pytest test/swe_paddle/test_pr74439_ravel.py -q