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-73850/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# PaddlePaddle__Paddle-73850

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

## Source

| Field | Value |
| --- | --- |
| Repo | `PaddlePaddle/Paddle` |
| PR | [73850](https://github.com/PaddlePaddle/Paddle/pull/73850) |
| PR title | `[0-size Tensor No.118] Add 0-size Tensor support for paddle.linalg.triangular_solve` |
| Base commit | `917f720a58b3ed5aeb8a1ac0022fdbd76f3b2b4b` |
| Gold commit | `0a23433eddfd286cbdb8746240eaf662cd027c69` |
| Merged at | `2025-07-08` |
| Task type | `bug_fix` |
| Resource | CPU |
| Scope | C++ phi kernel + Python test |

## Summary

Fix `paddle.linalg.triangular_solve` to correctly handle 0-size tensors in both forward and backward passes. The forward kernel adds an early return when `x.numel() == 0 || y.numel() == 0`, and the backward kernel fills gradients with 0 when `out.numel() == 0`.

## 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 triangular_solve phi kernels (CPU/GPU) and grad kernel impl.
- The failure is deterministic: the base revision fails when processing 0-size tensors in triangular_solve.
- The task has clear regression coverage for existing non-zero-size 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 (P2P) | triangular_solve F2P |
| --- | ---: | ---: |
| Base + `tests/test.patch` | PASS | FAIL |
| Base + test patch + solution patch | PASS | PASS |
56 changes: 56 additions & 0 deletions swe-paddle/tasks/PaddlePaddle__Paddle-73850/environment/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# Environment Notes

## Expected Environment

- Repository: `PaddlePaddle/Paddle`
- Base commit: `917f720a58b3ed5aeb8a1ac0022fdbd76f3b2b4b`
- Gold commit: `0a23433eddfd286cbdb8746240eaf662cd027c69`
- Resource: CPU
- GPU required: no
- Patch type: C++ kernel (phi kernels) + Python test
- Python dependencies: PaddlePaddle (source build), NumPy, pytest

The verifier should execute against the Paddle source revision represented by the selected patch state. Since the patch modifies C++ kernel files, a source rebuild is required after applying the solution patch.

## Build Instructions

1. Check out `PaddlePaddle/Paddle` at the base commit.
2. Build Paddle from source (CPU-only build is sufficient):
```bash
mkdir build && cd build
cmake .. -DWITH_GPU=OFF -DWITH_TESTING=ON -DCMAKE_BUILD_TYPE=Release
make -j$(nproc)
```
3. Install the built Paddle package.

## Run Order

1. Check out `PaddlePaddle/Paddle` at the base commit.
2. Build and install Paddle from source.
3. Apply `tests/test.patch`.
4. Run the P2P tests; existing non-zero-size behavior should pass.
5. Run the 0-size tensor tests; the target cases should fail before the fix.
6. Apply `solution/code.patch`.
7. Rebuild Paddle from source so the modified C++ kernels take effect:
```bash
cd build
make -j$(nproc)
pip install --force-reinstall python/dist/paddlepaddle-*.whl
cd ..
```
8. Run `bash tests/test.sh`; all target tests should pass.

## Minimal Test Command

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

## Expected Matrix

| Revision state | P2P | triangular_solve F2P |
| --- | ---: | ---: |
| Base + test patch | PASS | FAIL |
| Base + test patch + solution patch | PASS | PASS |

No GPU, distributed runtime, external service, or additional dataset is required.
43 changes: 43 additions & 0 deletions swe-paddle/tasks/PaddlePaddle__Paddle-73850/instruction.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# 修复 `paddle.linalg.triangular_solve` 对 0-size Tensor 的处理

## 详细描述

当 `paddle.linalg.triangular_solve(x, y, ...)` 的输入 `x` 或 `y` 中存在大小为 `0` 的 dimension,即 `x.numel() == 0` 或 `y.numel() == 0` 时,当前实现会直接进入底层算子,导致报错或产生错误结果。

典型表现包括:

- 底层算子在处理 0-size tensor 时出现 shape 推断异常或计算错误
- 调用失败并抛出与 shape 相关的错误

例如:

```python
import numpy as np
import paddle

paddle.disable_static()
x = paddle.to_tensor(np.random.random([0, 2, 2]).astype('float32'))
y = paddle.to_tensor(np.random.random([0, 2, 1]).astype('float32'))
out = paddle.linalg.triangular_solve(x, y, upper=False, left=True, unitriangular=False)
# 期望: out shape 为 [0, 2, 1],正常返回空 tensor
```

上述调用中 `x` 的 shape 为 `[0, 2, 2]`,`y` 的 shape 为 `[0, 2, 1]`,不包含任何元素。按照 API semantics,当输入 tensor 的 numel 为 0 时,不存在需要求解的方程组,因此该调用应正常完成并返回正确 shape 的空 tensor。

此外,反向传播也需要正确处理 0-size tensor 的情况。当 `out.numel() == 0` 时,`dx` 和 `dy` 应被填充为 0。

当前 C++ kernel 层在进入底层计算之前,没有对 0-size tensor 输入进行显式的早期返回处理。需要在 forward kernel 中检测 `x.numel() == 0 || y.numel() == 0` 并直接分配输出后返回;在 backward kernel 中检测 `out.numel() == 0` 并将梯度填充为 0。

## 验收说明

- 当输入 tensor 的 numel 为 0 时,`paddle.linalg.triangular_solve` 前向应正常完成,返回正确 shape 的空 tensor
- 返回的 out tensor 应保持与输入相同的 dtype
- 反向传播时,当 `out.numel() == 0`,`dx` 和 `dy` 应被正确填充为 0
- 非 0-size tensor 输入下的 triangular_solve 行为不得退化

## 技术要求

- 熟悉 C++ 和 Paddle phi kernel 开发
- 了解 Tensor shape、0-size Tensor 和 kernel 执行路径
- 了解 triangular_solve 算子的前向和反向语义
- 了解 Paddle phi kernel 的 CPU/GPU 实现结构
58 changes: 58 additions & 0 deletions swe-paddle/tasks/PaddlePaddle__Paddle-73850/proposal.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# SWE-Paddle Task Proposal: PaddlePaddle__Paddle-73850

## 1. 来源信息

- Instance ID: `PaddlePaddle__Paddle-73850`
- PR 链接: https://github.com/PaddlePaddle/Paddle/pull/73850
- PR 标题: `[0-size Tensor No.118] Add 0-size Tensor support for paddle.linalg.triangular_solve`
- Base commit: `917f720a58b3ed5aeb8a1ac0022fdbd76f3b2b4b`
- Gold commit: `0a23433eddfd286cbdb8746240eaf662cd027c69`
- Merged at: 2025-07-08
- 你的身份: contributor

## 2. 问题一句话

`paddle.linalg.triangular_solve` 在动态图模式下对 0-size tensor(任意维度含有 0)的输入缺少显式处理,前向进入底层算子时出错,反向未正确填充梯度为 0,需要补齐 0-size tensor 支持。

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

- **真实性**:该问题来自 Paddle 的「0-size Tensor 机制建设」系列任务,是真实研发需求,目标是为 `triangular_solve` 算子补齐 0-size tensor 支持。
- **代表性**:覆盖 C++ phi kernel 层面的算子边界处理,涉及 forward kernel 的早期返回和 backward kernel 的梯度填充,是 Paddle 算子机制增强的典型样本。
- **边界清楚**:目标仅限 0-size tensor 输入的 forward/backward 早期返回逻辑;正向非零尺寸输入不应受影响。
- **非平凡性**:修复需要在 CPU kernel、GPU kernel 和 grad kernel impl 三处分别添加 0-size 判断逻辑,涉及 `numel() == 0` 检查、输出分配和梯度填充(使用 `phi::Full`),不是简单机械修改。
- **回归护栏明确**:目标 F2P 可覆盖 0-size tensor 输入的 `triangular_solve` 前向和反向调用;同文件已有的 `TestTriangularSolveOp` 等标准算子测试用例可作为 P2P 护栏。

## 4. 任务类型和标签

- 任务类型:`bug_fix`
- 执行后端:`cpu`
- 设备范围:`cpu_only`
- 模块标签:`[phi_kernel, triangular_solve, 0-size_tensor, forward, backward, cpu, gpu]`

## 5. 验证思路

- 目标测试命令:`bash tests/test.sh`
- 目标测试文件:
- `test/legacy_test/test_triangular_solve_op.py`(`TestTriangularSolveOp_ZeroSize`)
- P2P 候选:同文件中已有的 `TestTriangularSolveOp` 等标准 triangular_solve 算子测试用例。
- 修复前预期:`base_commit` + `tests/test.patch` 后,0-size tensor 输入在 `triangular_solve` 的前向/反向调用中失败(进入底层算子时出错)。
- 修复后预期:继续应用 `solution/code.patch` 后,0-size tensor 输入返回正确的空 tensor(shape 与预期一致),反向梯度填充为 0,P2P 存量测试仍然通过。

## 6. 环境与资源

- 是否能提供 Docker: 无
- Dockerfile 或镜像地址: 暂无
- Paddle 来源: `PaddlePaddle/Paddle` source checkout at `base_commit`,需要源码编译。
- OS / Python / CUDA / cuDNN / 其他关键依赖: Linux CPU + Python + numpy;编译需要 CMake、GCC;不要求 CUDA/cuDNN(CPU 编译即可验证)。
- 硬件: CPU 即可(编译和测试均不需要 GPU)。
- patch 类型: C++ kernel 修改(`paddle/phi/kernels/cpu/triangular_solve_kernel.cc`、`paddle/phi/kernels/gpu/triangular_solve_kernel.cu`、`paddle/phi/kernels/impl/triangular_solve_grad_kernel_impl.h`),需要重新编译。
- 最小测试命令: `bash tests/test.sh`
- 是否有 oracle 日志: 无

## 7. 风险自查

- 泄露风险:正式 `instruction.md` 只描述「triangular_solve 对 0-size tensor 输入的行为异常」,不指出具体 `numel() == 0` 分支逻辑或具体代码位置。
- 环境风险:中。任务需要 Paddle 源码环境,patch 涉及 C++ 文件,需要重新编译。
- flaky 风险:低。测试使用固定的 0-size tensor 构造,不依赖随机数差异或多设备同步。
- 拆分风险:低。该 PR 目标集中在 triangular_solve 的 forward/backward kernel 的 0-size 处理,测试明确指向零尺寸分支,适合作为一个独立样本。
- 其他不确定点:完整任务包阶段应确认新增 F2P(`TestTriangularSolveOp_ZeroSize`)在 `base_commit` 上确实失败,并选择同文件中已有的 `TestTriangularSolveOp` 等标准测试用例作为在 base 与修复后都稳定通过的 P2P nodeid。
68 changes: 68 additions & 0 deletions swe-paddle/tasks/PaddlePaddle__Paddle-73850/solution/code.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
diff --git a/paddle/phi/kernels/cpu/triangular_solve_kernel.cc b/paddle/phi/kernels/cpu/triangular_solve_kernel.cc
index 68af8bc2b1..de3ae7ef06 100644
--- a/paddle/phi/kernels/cpu/triangular_solve_kernel.cc
+++ b/paddle/phi/kernels/cpu/triangular_solve_kernel.cc
@@ -32,6 +32,10 @@ void TriangularSolveKernel(const Context& dev_ctx,
bool transpose,
bool unitriangular,
DenseTensor* out) {
+ if (x.numel() == 0 || y.numel() == 0) {
+ dev_ctx.template Alloc<T>(out);
+ return;
+ }
// get broadcast dim
std::vector<int64_t> x_bst_dims_vec;
std::vector<int64_t> y_bst_dims_vec;
diff --git a/paddle/phi/kernels/gpu/triangular_solve_kernel.cu b/paddle/phi/kernels/gpu/triangular_solve_kernel.cu
index 2c2bb299f8..5311cea5fc 100644
--- a/paddle/phi/kernels/gpu/triangular_solve_kernel.cu
+++ b/paddle/phi/kernels/gpu/triangular_solve_kernel.cu
@@ -33,6 +33,10 @@ void TriangularSolveKernel(const Context& dev_ctx,
bool transpose,
bool unitriangular,
DenseTensor* out) {
+ if (x.numel() == 0 || y.numel() == 0) {
+ dev_ctx.template Alloc<T>(out);
+ return;
+ }
// get broadcast dim
std::vector<int64_t> x_bst_dims_vec;
std::vector<int64_t> y_bst_dims_vec;
diff --git a/paddle/phi/kernels/impl/triangular_solve_grad_kernel_impl.h b/paddle/phi/kernels/impl/triangular_solve_grad_kernel_impl.h
index 483694335a..ad656b7a6c 100644
--- a/paddle/phi/kernels/impl/triangular_solve_grad_kernel_impl.h
+++ b/paddle/phi/kernels/impl/triangular_solve_grad_kernel_impl.h
@@ -16,6 +16,7 @@

#include "paddle/phi/core/tensor_utils.h"
#include "paddle/phi/kernels/empty_kernel.h"
+#include "paddle/phi/kernels/full_kernel.h"
#include "paddle/phi/kernels/funcs/blas/blas.h"
#include "paddle/phi/kernels/funcs/common_shape.h"
#include "paddle/phi/kernels/funcs/complex_functors.h"
@@ -24,7 +25,6 @@
#include "paddle/phi/kernels/funcs/tril_triu_compute.h"
#include "paddle/phi/kernels/triangular_solve_grad_kernel.h"
#include "paddle/phi/kernels/triangular_solve_kernel.h"
-
namespace phi {

template <typename T, typename Context>
@@ -38,6 +38,17 @@ void TriangularSolveGradKernel(const Context& dev_ctx,
bool unitriangular,
DenseTensor* dx,
DenseTensor* dy) {
+ if (out.numel() == 0) {
+ if (dx) {
+ phi::Full<T, Context>(
+ dev_ctx, phi::IntArray(common::vectorize(dx->dims())), 0, dx);
+ }
+ if (dy) {
+ phi::Full<T, Context>(
+ dev_ctx, phi::IntArray(common::vectorize(dy->dims())), 0, dy);
+ }
+ return;
+ }
std::vector<int64_t> x_bst_dims_vec;
std::vector<int64_t> y_bst_dims_vec;
std::tie(x_bst_dims_vec, y_bst_dims_vec) =
21 changes: 21 additions & 0 deletions swe-paddle/tasks/PaddlePaddle__Paddle-73850/tests/test.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
diff --git a/test/legacy_test/test_triangular_solve_op.py b/test/legacy_test/test_triangular_solve_op.py
index 0475eaf944..b1e194a813 100644
--- a/test/legacy_test/test_triangular_solve_op.py
+++ b/test/legacy_test/test_triangular_solve_op.py
@@ -840,5 +840,16 @@ class TestTriangularSolveOpError(unittest.TestCase):
)


+class TestTriangularSolveOp_ZeroSize(TestTriangularSolveOp):
+ def config(self):
+ self.__class__.exist_fp64_check_grad = True
+ self.x_shape = [0, 2, 2]
+ self.y_shape = [0, 2, 1]
+ self.upper = False
+ self.transpose = False
+ self.unitriangular = False
+ self.dtype = "float32"
+
+
if __name__ == "__main__":
unittest.main()
8 changes: 8 additions & 0 deletions swe-paddle/tasks/PaddlePaddle__Paddle-73850/tests/test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#!/usr/bin/env bash
set -euo pipefail

# P2P tests (pass-to-pass)
python -m pytest test/legacy_test/test_triangular_solve_op.py::TestTriangularSolveOp -q

# F2P tests (fail-to-pass)
python -m pytest test/legacy_test/test_triangular_solve_op.py::TestTriangularSolveOp_ZeroSize -q