diff --git a/swe-paddle/tasks/PaddlePaddle__Paddle-78238/README.md b/swe-paddle/tasks/PaddlePaddle__Paddle-78238/README.md new file mode 100644 index 000000000..cf7c0ca40 --- /dev/null +++ b/swe-paddle/tasks/PaddlePaddle__Paddle-78238/README.md @@ -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 | diff --git a/swe-paddle/tasks/PaddlePaddle__Paddle-78238/environment/README.md b/swe-paddle/tasks/PaddlePaddle__Paddle-78238/environment/README.md new file mode 100644 index 000000000..a7050dc8f --- /dev/null +++ b/swe-paddle/tasks/PaddlePaddle__Paddle-78238/environment/README.md @@ -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. diff --git a/swe-paddle/tasks/PaddlePaddle__Paddle-78238/instruction.md b/swe-paddle/tasks/PaddlePaddle__Paddle-78238/instruction.md new file mode 100644 index 000000000..3a5e8f348 --- /dev/null +++ b/swe-paddle/tasks/PaddlePaddle__Paddle-78238/instruction.md @@ -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. diff --git a/swe-paddle/tasks/PaddlePaddle__Paddle-78238/proposal.md b/swe-paddle/tasks/PaddlePaddle__Paddle-78238/proposal.md new file mode 100644 index 000000000..926417504 --- /dev/null +++ b/swe-paddle/tasks/PaddlePaddle__Paddle-78238/proposal.md @@ -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,适合作为一个任务统一验证。 diff --git a/swe-paddle/tasks/PaddlePaddle__Paddle-78238/solution/code.patch b/swe-paddle/tasks/PaddlePaddle__Paddle-78238/solution/code.patch new file mode 100644 index 000000000..821bf023e --- /dev/null +++ b/swe-paddle/tasks/PaddlePaddle__Paddle-78238/solution/code.patch @@ -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 = ( diff --git a/swe-paddle/tasks/PaddlePaddle__Paddle-78238/tests/test.patch b/swe-paddle/tasks/PaddlePaddle__Paddle-78238/tests/test.patch new file mode 100644 index 000000000..37e85c5b0 --- /dev/null +++ b/swe-paddle/tasks/PaddlePaddle__Paddle-78238/tests/test.patch @@ -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() diff --git a/swe-paddle/tasks/PaddlePaddle__Paddle-78238/tests/test.sh b/swe-paddle/tasks/PaddlePaddle__Paddle-78238/tests/test.sh new file mode 100644 index 000000000..981182c74 --- /dev/null +++ b/swe-paddle/tasks/PaddlePaddle__Paddle-78238/tests/test.sh @@ -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