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
51 changes: 51 additions & 0 deletions swe-paddle/tasks/PaddlePaddle__Paddle-78238/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# PaddlePaddle__Paddle-78238

This directory converts Paddle PR #78238 into a SWE-Paddle community task candidate.

## Source

| Field | Value |
| --- | --- |
| Repo | `PaddlePaddle/Paddle` |
| PR | [78238](https://github.com/PaddlePaddle/Paddle/pull/78238) |
| PR title | `[ZeroDim] fix put_along_axis with 0-size indices tensor` |
| Base commit | `ae907b878e91dbabf3582da99f8b05a46b588fc2` |
| Gold commit | `2d26799c4f1a710deb78b7a2182c60eaa0ee7d22` |
| Merged at | `2026-03-20` |
| Task type | `bug_fix` |
| Resource | CPU |
| Scope | Python Tensor API |

## Summary

完善 `paddle.put_along_axis` 和 `Tensor.put_along_axis_` 对 0-size `indices` Tensor 的支持。

## Why This Is A Good SWE-Paddle Candidate

- It is derived from a merged Paddle bug-fix PR rather than a synthetic issue.
- The target behavior is isolated to the Python Tensor API and does not require rebuilding C++ kernels.
- The failure is deterministic: the base revision reaches an invalid broadcast when the index tensor is empty.
- The task has clear regression coverage for existing non-empty-index behavior.
- The task runs on CPU and does not require distributed execution, external services, or additional datasets.

## Files

- `proposal.md`: candidate proposal for maintainer triage.
- `instruction.md`: self-contained problem statement for the coding agent.
- `solution/code.patch`: gold implementation patch.
- `tests/test.patch`: tests exposing the target behavior.
- `tests/test.sh`: minimal target test command.
- `environment/README.md`: environment and reproduction notes.

## Verification

```bash
bash tests/test.sh
```

Expected behavior:

| Revision state | Existing behavior | Zero-size out-of-place | Zero-size in-place |
| --- | ---: | ---: | ---: |
| Base + `tests/test.patch` | PASS | FAIL | FAIL |
| Base + `tests/test.patch` + `solution/code.patch` | PASS | PASS | PASS |
37 changes: 37 additions & 0 deletions swe-paddle/tasks/PaddlePaddle__Paddle-78238/environment/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# Environment Notes

## Expected Environment

- Repository: `PaddlePaddle/Paddle`
- Base commit: `ae907b878e91dbabf3582da99f8b05a46b588fc2`
- Gold commit: `2d26799c4f1a710deb78b7a2182c60eaa0ee7d22`
- Resource: CPU
- GPU required: no
- Patch type: Python-only
- Python dependencies: PaddlePaddle, NumPy, pytest

The verifier should execute against the Paddle source revision represented by the selected patch state. A source build is not required when an equivalent Python overlay is available and the underlying runtime remains API-compatible.

## Run Order

1. Check out `PaddlePaddle/Paddle` at the base commit.
2. Apply `tests/test.patch`.
3. Run the P2P test; existing non-empty-index behavior should pass.
4. Run the zero-size tests; both target cases should fail before the fix.
5. Apply `solution/code.patch`.
6. Run `bash tests/test.sh`; all target tests should pass.

## Minimal Test Command

```bash
bash tests/test.sh
```

## Expected Matrix

| Revision state | P2P | Out-of-place F2P | In-place F2P |
| --- | ---: | ---: | ---: |
| Base + test patch | PASS | FAIL | FAIL |
| Base + test patch + solution patch | PASS | PASS | PASS |

No GPU, distributed runtime, external service, or additional dataset is required.
30 changes: 30 additions & 0 deletions swe-paddle/tasks/PaddlePaddle__Paddle-78238/instruction.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# 完善 `paddle.put_along_axis` 和 `paddle.put_along_axis_` 对 0-size `indices` Tensor 的支持

## 详细描述

完善 out-of-place API `paddle.put_along_axis` 和 in-place API `paddle.put_along_axis_` 对 0-size `indices` Tensor 的支持。

本 issue 中,0-size Tensor 是指 `Tensor.shape` 中至少存在一个 size 为 `0` 的 dimension,因此其元素个数为 `0`,但仍具有 `shape`、`dtype`、`place` 等 Tensor metadata。

当 `indices` 为 0-size Tensor 时,不存在需要执行的 index update,API 应按 no-op semantics 正常完成。即使 `values` 的 shape 与 `indices` 不一致,也不应仅因 empty update path 中无需使用 `values` 而执行失败。与 empty update 无关的 dtype、rank、`axis` 等现有 validation 应保持不变。

## 验收说明

- 当 `indices` 为 0-size Tensor 时,接口应正常完成
- out-of-place API 应返回与 `arr` shape 和 data 一致的结果
- in-place API 应保持 `arr` 的 shape 和 data 不变
- 应覆盖 `values` 与 0-size `indices` shape 不一致但无需执行 update 的场景
- 非 0-size `indices` 的现有行为不得退化

## 技术要求

- 熟悉 Python 和 Paddle Tensor API
- 了解 Tensor shape 和 broadcast rules
- 了解 in-place 与 out-of-place API semantics
- 了解 Paddle 单元测试开发流程

## Acceptance Criteria

- The behavior described above should be supported correctly.
- Existing valid behavior should remain unchanged.
- Do not satisfy the task by deleting tests, weakening assertions, or broadly bypassing validation.
55 changes: 55 additions & 0 deletions swe-paddle/tasks/PaddlePaddle__Paddle-78238/proposal.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# Task Proposal: PaddlePaddle__Paddle-78238

## 1. 来源信息

- Instance ID:`PaddlePaddle__Paddle-78238`
- PR 链接:https://github.com/PaddlePaddle/Paddle/pull/78238
- PR 标题:`[ZeroDim] fix put_along_axis with 0-size indices tensor`
- `base_commit`:`ae907b878e91dbabf3582da99f8b05a46b588fc2`
- Merged time:`2026-03-20`
- 你的身份:熟悉该模块的 contributor
- 后续联系人:TBD

## 2. 问题一句话

完善 `paddle.put_along_axis` 和 `Tensor.put_along_axis_` 对 0-size `indices` Tensor 的支持。

## 3. 为什么适合作为 SWE-Paddle 样本

- **真实性**:任务来自已合入的 Paddle bug-fix PR,不是合成任务。
- **边界清楚**:目标行为集中在 `put_along_axis` 的 Python API wrapper,production code 修改范围较小。
- **可验证性**:修复前,0-size `indices` cases 稳定失败;修复后通过。非 0-size `indices` cases 可作为 regression guard。
- **环境稳定**:测试可在 CPU 环境完成,不依赖 GPU、distributed execution 或 external services。
- **行为导向**:测试仅断言 public API 的输出和 in-place semantics,不检查实现源码,也不依赖特定修复方式。

## 4. 任务类型和标签

- 任务类型:`bug_fix`
- 执行 backend:`cpu`
- Device scope:`cpu_only`
- 模块标签:`[tensor, manipulation, put_along_axis, zero_size, broadcasting, python_api, legacy_test]`

## 5. 验证思路

- 目标测试命令:`bash tests/test.sh`
- 目标测试文件:`test/legacy_test/test_put_along_axis_zero_size.py`
- P2P:非 0-size `indices` 的现有 update behavior 在修复前后均应通过。
- F2P 1:out-of-place API 接收 0-size `indices` 时,修复前应失败,修复后应返回与输入一致的结果。
- F2P 2:in-place API 接收 0-size `indices` 时,修复前应失败,修复后应保持输入不变。
- 修复后预期:目标测试文件中的全部 cases 通过。

## 6. 环境与资源

- 资源需求:CPU
- Paddle 来源:`PaddlePaddle/Paddle` source checkout at `base_commit`
- Patch type:Python-only
- Python 依赖:PaddlePaddle、NumPy、pytest
- 最小测试命令:`bash tests/test.sh`
- GPU、distributed execution、external services 和额外 dataset 均不是必需项

## 7. 风险自查

- 泄露风险:`instruction.md` 仅描述目标行为和验收标准,不指定具体代码位置或实现方案。
- 环境风险:production code 修改为 Python-only;verifier 可使用 source environment 或等价的 Python overlay。
- Flaky 风险:测试使用固定 shape 和确定性的 shape/data assertions,不依赖随机数值结果。
- 拆分风险:in-place 与 out-of-place API 属于同一 0-size `indices` semantics,适合作为一个任务统一验证。
31 changes: 31 additions & 0 deletions swe-paddle/tasks/PaddlePaddle__Paddle-78238/solution/code.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
diff --git a/python/paddle/tensor/manipulation.py b/python/paddle/tensor/manipulation.py
--- a/python/paddle/tensor/manipulation.py
+++ b/python/paddle/tensor/manipulation.py
@@ -7510,6 +7510,16 @@ def has_dynamic_shape(shapes):
"`indices` and `arr` must have the same number of dimensions!"
)
axis = non_negative_axis(arr, axis)
+ # When indices is empty (numel == 0) there are no scatter operations to
+ # perform. Return a copy of arr immediately to avoid passing a 0-size
+ # index tensor through the broadcast path, which would attempt an invalid
+ # expand (e.g. values dim 4 -> 0) and raise an error.
+ # In dynamic mode use numel(); in static mode indices.numel() returns a
+ # symbolic Value so we check the shape directly instead.
+ if (paddle.in_dynamic_mode() and indices.numel() == 0) or (
+ not paddle.in_dynamic_mode() and 0 in indices.shape
+ ):
+ return paddle.assign(arr)
if broadcast:
if has_dynamic_shape(arr.shape) or has_dynamic_shape(indices.shape):
arr_shape = paddle.shape(arr)
@@ -7629,6 +7639,10 @@ def put_along_axis_(
"`indices` and `arr` must have the same number of dimensions!"
)
axis = non_negative_axis(arr, axis)
+ if (paddle.in_dynamic_mode() and indices.numel() == 0) or (
+ not paddle.in_dynamic_mode() and 0 in indices.shape
+ ):
+ return arr
if broadcast:
broadcast_shape = infer_broadcast_shape(arr, indices, axis)
values = (
67 changes: 67 additions & 0 deletions swe-paddle/tasks/PaddlePaddle__Paddle-78238/tests/test.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
diff --git a/test/legacy_test/test_put_along_axis_zero_size.py b/test/legacy_test/test_put_along_axis_zero_size.py
new file mode 100644
--- /dev/null
+++ b/test/legacy_test/test_put_along_axis_zero_size.py
@@ -0,0 +1,62 @@
+# Copyright (c) 2026 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 paddle
+
+
+class TestPutAlongAxisZeroSize(unittest.TestCase):
+ def setUp(self):
+ paddle.disable_static()
+
+ def test_non_empty_indices_existing_behavior(self):
+ arr = paddle.to_tensor(
+ [[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]], dtype="float32"
+ )
+ indices = paddle.to_tensor([[1], [0]], dtype="int64")
+ values = paddle.to_tensor([[9.0], [8.0]], dtype="float32")
+
+ out = paddle.put_along_axis(arr, indices, values, axis=1)
+
+ np.testing.assert_allclose(
+ out.numpy(),
+ np.array([[1.0, 9.0, 3.0], [8.0, 5.0, 6.0]], dtype="float32"),
+ )
+
+ def test_zero_size_indices_out_of_place(self):
+ arr = paddle.rand([2, 60], dtype="float32")
+ indices = paddle.zeros([2, 0], dtype="int64")
+ values = paddle.rand([2, 4], dtype="float32")
+
+ out = paddle.put_along_axis(arr, indices, values, axis=1)
+
+ self.assertEqual(list(out.shape), [2, 60])
+ np.testing.assert_allclose(out.numpy(), arr.numpy(), rtol=0, atol=0)
+
+ def test_zero_size_indices_in_place(self):
+ arr = paddle.rand([2, 60], dtype="float32")
+ expected = arr.clone()
+ indices = paddle.zeros([2, 0], dtype="int64")
+ values = paddle.rand([2, 4], dtype="float32")
+
+ result = arr.put_along_axis_(indices, values, axis=1)
+
+ self.assertIs(result, arr)
+ np.testing.assert_allclose(arr.numpy(), expected.numpy(), rtol=0, atol=0)
+
+
+if __name__ == "__main__":
+ unittest.main()
4 changes: 4 additions & 0 deletions swe-paddle/tasks/PaddlePaddle__Paddle-78238/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/legacy_test/test_put_along_axis_zero_size.py -q