From c410e859783438e40a6ec6c1bc386c25c4d6d9b1 Mon Sep 17 00:00:00 2001 From: youge325 Date: Sun, 14 Jun 2026 15:40:02 +0800 Subject: [PATCH 01/12] docs(skill): update branch creation workflow --- .claude/skills/add-compat-api/SKILL.md | 4 ++-- .../skills/add-compat-api/references/Step7.md | 18 +++++++++++------- .claude/skills/fix-compat-api/SKILL.md | 2 +- .github/skills/add-compat-api/SKILL.md | 4 ++-- .../skills/add-compat-api/references/Step7.md | 18 +++++++++++------- .github/skills/fix-compat-api/SKILL.md | 2 +- 6 files changed, 28 insertions(+), 20 deletions(-) diff --git a/.claude/skills/add-compat-api/SKILL.md b/.claude/skills/add-compat-api/SKILL.md index 1bc79e5..b784e5e 100644 --- a/.claude/skills/add-compat-api/SKILL.md +++ b/.claude/skills/add-compat-api/SKILL.md @@ -202,12 +202,12 @@ bash test/result_cmp.sh ./build/ 闭环验证通过且文档已回填后,按以下流程提交。完整命令模板见 [`references/Step7.md`](references/Step7.md)。 -1. **从 fork 主分支 checkout 新分支**(`git fetch upstream && git checkout -B add/- upstream/develop`) +1. **从本地跟踪 origin 的 develop 创建新分支**(`git checkout develop && git pull --ff-only origin develop && git checkout -b add/-`) 2. **commit 改动**(commit message 首行使用 `[Cpp API Compatibility] <对齐迭代记录标题>`) 3. **push 到 fork**(`git push origin `) 4. **`gh pr create` 到 upstream**(`--repo PaddlePaddle/Paddle --base develop`) 5. **同步 PCAT 测试改动** - 1. **从 fork 主分支 checkout 新分支**(`cd "$PCAT_ROOT" && git fetch upstream && git checkout -B test/- upstream/master`) + 1. **从本地跟踪 origin 的 master 创建新分支**(`cd "$PCAT_ROOT" && git checkout master && git pull --ff-only origin master && git checkout -b test/-`) 2. **commit 改动**(commit message 首行使用 `test(): align with Paddle compat 行为`) 3. **push 到 fork**(`git push origin `) 4. **`gh pr create` 到 upstream**(`--repo PFCCLab/PaddleCppAPITest --base master`,PR body 中加 `Related: PaddlePaddle/Paddle#`) diff --git a/.claude/skills/add-compat-api/references/Step7.md b/.claude/skills/add-compat-api/references/Step7.md index 892239d..ec2f5d4 100644 --- a/.claude/skills/add-compat-api/references/Step7.md +++ b/.claude/skills/add-compat-api/references/Step7.md @@ -13,24 +13,27 @@ 任一未通过 → **不要**进入本流程。 -## 1) 从 fork 主分支 checkout 新分支 +## 1) 从本地跟踪 origin 的基分支创建新分支 ### Paddle 侧 ```bash cd "$PADDLE_ROOT" -git fetch upstream +git checkout develop +git pull --ff-only origin develop # add 流程 -git checkout -B "add/-$(date +%Y%m%d)" upstream/develop +git checkout -b "add/-$(date +%Y%m%d)" # fix 流程 -git checkout -B "fix/-$(date +%Y%m%d)" upstream/develop +git checkout -b "fix/-$(date +%Y%m%d)" ``` 分支命名规则: - add:`add/-`(例:`add/abs-20260519`) - fix:`fix/-`(例:`fix/78652-20260519`) -> 前提:Paddle 仓库已配置 `origin = /Paddle` 与 `upstream = PaddlePaddle/Paddle`。若 remote 缺失,**提示用户配置后再继续**,不要主动改用户仓库的 remote。 +> 实际执行时只选 add 或 fix 对应的一条 `git checkout -b`。若分支已存在,`git checkout -b` 会失败;换新分支名或让用户手动处理,**不要**改用 `-B` 覆盖已有分支。 +> +> 前提:Paddle 仓库已配置 `origin = /Paddle` 与 `upstream = PaddlePaddle/Paddle`,且本地 `develop` 跟踪 `origin/develop`。若 remote 或本地基分支缺失,**提示用户配置后再继续**,不要主动改用户仓库的 remote。 ## 2) commit 改动 @@ -100,8 +103,9 @@ EOF ```bash cd "$PCAT_ROOT" -git fetch upstream -git checkout -B "test/-$(date +%Y%m%d)" upstream/master +git checkout master +git pull --ff-only origin master +git checkout -b "test/-$(date +%Y%m%d)" git add test/<改动文件> git commit -m "test(): align with Paddle compat 行为" git push origin diff --git a/.claude/skills/fix-compat-api/SKILL.md b/.claude/skills/fix-compat-api/SKILL.md index 9245cf8..d366845 100644 --- a/.claude/skills/fix-compat-api/SKILL.md +++ b/.claude/skills/fix-compat-api/SKILL.md @@ -218,7 +218,7 @@ bash test/result_cmp.sh ./build/ 闭环验证通过且文档已回填后,按以下流程提交。完整命令模板见 [`../add-compat-api/references/Step7.md`](../add-compat-api/references/Step7.md)(与 `add-compat-api` 共享同一份 references)。 -1. **从 fork 主分支 checkout 新分支**(`git fetch upstream && git checkout -B fix/- upstream/develop`) +1. **从本地跟踪 origin 的 develop 创建新分支**(`git checkout develop && git pull --ff-only origin develop && git checkout -b fix/-`) 2. **commit 改动**(commit message 首行使用 `[Cpp API Compatibility] `) 3. **征求用户同意后 push 到 fork**(`git push origin `——这是发出去的动作,**push 前必须明确询问用户**) 4. **征求用户同意后 `gh pr create` 到 upstream**(`--repo PaddlePaddle/Paddle --base develop`——同样需要用户确认;若本轮修复源自外部 PR/Actions/comment 链接,PR 描述里应**引用原链接**便于追溯) diff --git a/.github/skills/add-compat-api/SKILL.md b/.github/skills/add-compat-api/SKILL.md index 1bc79e5..b784e5e 100644 --- a/.github/skills/add-compat-api/SKILL.md +++ b/.github/skills/add-compat-api/SKILL.md @@ -202,12 +202,12 @@ bash test/result_cmp.sh ./build/ 闭环验证通过且文档已回填后,按以下流程提交。完整命令模板见 [`references/Step7.md`](references/Step7.md)。 -1. **从 fork 主分支 checkout 新分支**(`git fetch upstream && git checkout -B add/- upstream/develop`) +1. **从本地跟踪 origin 的 develop 创建新分支**(`git checkout develop && git pull --ff-only origin develop && git checkout -b add/-`) 2. **commit 改动**(commit message 首行使用 `[Cpp API Compatibility] <对齐迭代记录标题>`) 3. **push 到 fork**(`git push origin `) 4. **`gh pr create` 到 upstream**(`--repo PaddlePaddle/Paddle --base develop`) 5. **同步 PCAT 测试改动** - 1. **从 fork 主分支 checkout 新分支**(`cd "$PCAT_ROOT" && git fetch upstream && git checkout -B test/- upstream/master`) + 1. **从本地跟踪 origin 的 master 创建新分支**(`cd "$PCAT_ROOT" && git checkout master && git pull --ff-only origin master && git checkout -b test/-`) 2. **commit 改动**(commit message 首行使用 `test(): align with Paddle compat 行为`) 3. **push 到 fork**(`git push origin `) 4. **`gh pr create` 到 upstream**(`--repo PFCCLab/PaddleCppAPITest --base master`,PR body 中加 `Related: PaddlePaddle/Paddle#`) diff --git a/.github/skills/add-compat-api/references/Step7.md b/.github/skills/add-compat-api/references/Step7.md index 892239d..ec2f5d4 100644 --- a/.github/skills/add-compat-api/references/Step7.md +++ b/.github/skills/add-compat-api/references/Step7.md @@ -13,24 +13,27 @@ 任一未通过 → **不要**进入本流程。 -## 1) 从 fork 主分支 checkout 新分支 +## 1) 从本地跟踪 origin 的基分支创建新分支 ### Paddle 侧 ```bash cd "$PADDLE_ROOT" -git fetch upstream +git checkout develop +git pull --ff-only origin develop # add 流程 -git checkout -B "add/-$(date +%Y%m%d)" upstream/develop +git checkout -b "add/-$(date +%Y%m%d)" # fix 流程 -git checkout -B "fix/-$(date +%Y%m%d)" upstream/develop +git checkout -b "fix/-$(date +%Y%m%d)" ``` 分支命名规则: - add:`add/-`(例:`add/abs-20260519`) - fix:`fix/-`(例:`fix/78652-20260519`) -> 前提:Paddle 仓库已配置 `origin = /Paddle` 与 `upstream = PaddlePaddle/Paddle`。若 remote 缺失,**提示用户配置后再继续**,不要主动改用户仓库的 remote。 +> 实际执行时只选 add 或 fix 对应的一条 `git checkout -b`。若分支已存在,`git checkout -b` 会失败;换新分支名或让用户手动处理,**不要**改用 `-B` 覆盖已有分支。 +> +> 前提:Paddle 仓库已配置 `origin = /Paddle` 与 `upstream = PaddlePaddle/Paddle`,且本地 `develop` 跟踪 `origin/develop`。若 remote 或本地基分支缺失,**提示用户配置后再继续**,不要主动改用户仓库的 remote。 ## 2) commit 改动 @@ -100,8 +103,9 @@ EOF ```bash cd "$PCAT_ROOT" -git fetch upstream -git checkout -B "test/-$(date +%Y%m%d)" upstream/master +git checkout master +git pull --ff-only origin master +git checkout -b "test/-$(date +%Y%m%d)" git add test/<改动文件> git commit -m "test(): align with Paddle compat 行为" git push origin diff --git a/.github/skills/fix-compat-api/SKILL.md b/.github/skills/fix-compat-api/SKILL.md index 9245cf8..d366845 100644 --- a/.github/skills/fix-compat-api/SKILL.md +++ b/.github/skills/fix-compat-api/SKILL.md @@ -218,7 +218,7 @@ bash test/result_cmp.sh ./build/ 闭环验证通过且文档已回填后,按以下流程提交。完整命令模板见 [`../add-compat-api/references/Step7.md`](../add-compat-api/references/Step7.md)(与 `add-compat-api` 共享同一份 references)。 -1. **从 fork 主分支 checkout 新分支**(`git fetch upstream && git checkout -B fix/- upstream/develop`) +1. **从本地跟踪 origin 的 develop 创建新分支**(`git checkout develop && git pull --ff-only origin develop && git checkout -b fix/-`) 2. **commit 改动**(commit message 首行使用 `[Cpp API Compatibility] `) 3. **征求用户同意后 push 到 fork**(`git push origin `——这是发出去的动作,**push 前必须明确询问用户**) 4. **征求用户同意后 `gh pr create` 到 upstream**(`--repo PaddlePaddle/Paddle --base develop`——同样需要用户确认;若本轮修复源自外部 PR/Actions/comment 链接,PR 描述里应**引用原链接**便于追溯) From 0d071c14c1895c213e9dde40abf068b89356d78f Mon Sep 17 00:00:00 2001 From: youge325 Date: Sat, 20 Jun 2026 18:02:13 +0800 Subject: [PATCH 02/12] Fix PCAT result file handling --- test/ATen/ops/AsStridedTest.cpp | 17 +++------------- test/ATen/ops/BitwiseTest.cpp | 13 +----------- test/ATen/ops/ClampTest.cpp | 35 +++++++++++---------------------- test/ATen/ops/VarTest.cpp | 19 ++++-------------- test/result_cmp.sh | 26 ++++++++++++++++++++++-- 5 files changed, 44 insertions(+), 66 deletions(-) diff --git a/test/ATen/ops/AsStridedTest.cpp b/test/ATen/ops/AsStridedTest.cpp index 4410024..d1f46b4 100644 --- a/test/ATen/ops/AsStridedTest.cpp +++ b/test/ATen/ops/AsStridedTest.cpp @@ -19,19 +19,8 @@ class AsStridedTest : public ::testing::Test { void SetUp() override {} }; -// 返回当前用例的结果文件名 -std::string GetTestCaseResultFileName() { - std::string base = g_custom_param.get(); - std::string test_name = - ::testing::UnitTest::GetInstance()->current_test_info()->name(); - if (base.size() >= 4 && base.substr(base.size() - 4) == ".txt") { - base.resize(base.size() - 4); - } - return base + "_" + test_name + ".txt"; -} - TEST_F(AsStridedTest, AsStrided) { - FileManerger file(GetTestCaseResultFileName()); + FileManerger file(g_custom_param.get()); file.createFile(); file << "AsStrided "; at::Tensor tensor = at::ones({2, 3, 4}, at::kFloat); @@ -44,7 +33,7 @@ TEST_F(AsStridedTest, AsStrided) { } TEST_F(AsStridedTest, AsStridedInplace) { - FileManerger file(GetTestCaseResultFileName()); + FileManerger file(g_custom_param.get()); file.openAppend(); file << "AsStridedInplace "; at::Tensor tensor = at::ones({2, 3, 4}, at::kFloat); @@ -57,7 +46,7 @@ TEST_F(AsStridedTest, AsStridedInplace) { } TEST_F(AsStridedTest, AsStridedScatter) { - FileManerger file(GetTestCaseResultFileName()); + FileManerger file(g_custom_param.get()); file.openAppend(); file << "AsStridedScatter "; at::Tensor tensor = at::ones({2, 3, 4}, at::kFloat); diff --git a/test/ATen/ops/BitwiseTest.cpp b/test/ATen/ops/BitwiseTest.cpp index 90d2a55..77f2a85 100644 --- a/test/ATen/ops/BitwiseTest.cpp +++ b/test/ATen/ops/BitwiseTest.cpp @@ -19,19 +19,8 @@ class BitwiseTest : public ::testing::Test { void SetUp() override {} }; -// 返回当前用例的结果文件名 -std::string GetTestCaseResultFileName() { - std::string base = g_custom_param.get(); - std::string test_name = - ::testing::UnitTest::GetInstance()->current_test_info()->name(); - if (base.size() >= 4 && base.substr(base.size() - 4) == ".txt") { - base.resize(base.size() - 4); - } - return base + "_" + test_name + ".txt"; -} - TEST_F(BitwiseTest, BitwiseRightShift) { - FileManerger file(GetTestCaseResultFileName()); + FileManerger file(g_custom_param.get()); file.createFile(); file << "BitwiseRightShift "; at::Tensor input = at::ones({2, 3}, at::kInt).fill_(8); diff --git a/test/ATen/ops/ClampTest.cpp b/test/ATen/ops/ClampTest.cpp index 26ed74d..28d54a3 100644 --- a/test/ATen/ops/ClampTest.cpp +++ b/test/ATen/ops/ClampTest.cpp @@ -19,19 +19,8 @@ class ClampTest : public ::testing::Test { void SetUp() override {} }; -// 返回当前用例的结果文件名 -std::string GetTestCaseResultFileName() { - std::string base = g_custom_param.get(); - std::string test_name = - ::testing::UnitTest::GetInstance()->current_test_info()->name(); - if (base.size() >= 4 && base.substr(base.size() - 4) == ".txt") { - base.resize(base.size() - 4); - } - return base + "_" + test_name + ".txt"; -} - TEST_F(ClampTest, ClampScalarMinMax) { - FileManerger file(GetTestCaseResultFileName()); + FileManerger file(g_custom_param.get()); file.createFile(); file << "ClampScalarMinMax "; at::Tensor input = at::ones({2, 3}, at::kFloat).fill_(5.0f); @@ -44,7 +33,7 @@ TEST_F(ClampTest, ClampScalarMinMax) { } TEST_F(ClampTest, ClampTensorMinMax) { - FileManerger file(GetTestCaseResultFileName()); + FileManerger file(g_custom_param.get()); file.openAppend(); file << "ClampTensorMinMax "; at::Tensor input = at::ones({2, 3}, at::kFloat).fill_(5.0f); @@ -57,7 +46,7 @@ TEST_F(ClampTest, ClampTensorMinMax) { } TEST_F(ClampTest, ClampInplaceScalar) { - FileManerger file(GetTestCaseResultFileName()); + FileManerger file(g_custom_param.get()); file.openAppend(); file << "ClampInplaceScalar "; at::Tensor input = at::ones({2, 3}, at::kFloat).fill_(5.0f); @@ -69,7 +58,7 @@ TEST_F(ClampTest, ClampInplaceScalar) { } TEST_F(ClampTest, ClampInplaceTensor) { - FileManerger file(GetTestCaseResultFileName()); + FileManerger file(g_custom_param.get()); file.openAppend(); file << "ClampInplaceTensor "; at::Tensor input = at::ones({2, 3}, at::kFloat).fill_(5.0f); @@ -82,7 +71,7 @@ TEST_F(ClampTest, ClampInplaceTensor) { } TEST_F(ClampTest, ClampMaxScalar) { - FileManerger file(GetTestCaseResultFileName()); + FileManerger file(g_custom_param.get()); file.openAppend(); file << "ClampMaxScalar "; at::Tensor input = at::ones({2, 3}, at::kFloat).fill_(5.0f); @@ -94,7 +83,7 @@ TEST_F(ClampTest, ClampMaxScalar) { } TEST_F(ClampTest, ClampMaxTensor) { - FileManerger file(GetTestCaseResultFileName()); + FileManerger file(g_custom_param.get()); file.openAppend(); file << "ClampMaxTensor "; at::Tensor input = at::ones({2, 3}, at::kFloat).fill_(5.0f); @@ -106,7 +95,7 @@ TEST_F(ClampTest, ClampMaxTensor) { } TEST_F(ClampTest, ClampMaxInplace) { - FileManerger file(GetTestCaseResultFileName()); + FileManerger file(g_custom_param.get()); file.openAppend(); file << "ClampMaxInplace "; at::Tensor input = at::ones({2, 3}, at::kFloat).fill_(5.0f); @@ -118,7 +107,7 @@ TEST_F(ClampTest, ClampMaxInplace) { } TEST_F(ClampTest, ClampMaxInplaceTensor) { - FileManerger file(GetTestCaseResultFileName()); + FileManerger file(g_custom_param.get()); file.openAppend(); file << "ClampMaxInplaceTensor "; at::Tensor input = at::ones({2, 3}, at::kFloat).fill_(5.0f); @@ -130,7 +119,7 @@ TEST_F(ClampTest, ClampMaxInplaceTensor) { } TEST_F(ClampTest, ClampMinScalar) { - FileManerger file(GetTestCaseResultFileName()); + FileManerger file(g_custom_param.get()); file.openAppend(); file << "ClampMinScalar "; at::Tensor input = at::ones({2, 3}, at::kFloat); @@ -142,7 +131,7 @@ TEST_F(ClampTest, ClampMinScalar) { } TEST_F(ClampTest, ClampMinTensor) { - FileManerger file(GetTestCaseResultFileName()); + FileManerger file(g_custom_param.get()); file.openAppend(); file << "ClampMinTensor "; at::Tensor input = at::ones({2, 3}, at::kFloat); @@ -154,7 +143,7 @@ TEST_F(ClampTest, ClampMinTensor) { } TEST_F(ClampTest, ClampMinInplace) { - FileManerger file(GetTestCaseResultFileName()); + FileManerger file(g_custom_param.get()); file.openAppend(); file << "ClampMinInplace "; at::Tensor input = at::ones({2, 3}, at::kFloat); @@ -166,7 +155,7 @@ TEST_F(ClampTest, ClampMinInplace) { } TEST_F(ClampTest, ClampMinInplaceTensor) { - FileManerger file(GetTestCaseResultFileName()); + FileManerger file(g_custom_param.get()); file.openAppend(); file << "ClampMinInplaceTensor "; at::Tensor input = at::ones({2, 3}, at::kFloat); diff --git a/test/ATen/ops/VarTest.cpp b/test/ATen/ops/VarTest.cpp index feac64c..82b80b0 100644 --- a/test/ATen/ops/VarTest.cpp +++ b/test/ATen/ops/VarTest.cpp @@ -19,19 +19,8 @@ class VarTest : public ::testing::Test { void SetUp() override {} }; -// 返回当前用例的结果文件名 -std::string GetTestCaseResultFileName() { - std::string base = g_custom_param.get(); - std::string test_name = - ::testing::UnitTest::GetInstance()->current_test_info()->name(); - if (base.size() >= 4 && base.substr(base.size() - 4) == ".txt") { - base.resize(base.size() - 4); - } - return base + "_" + test_name + ".txt"; -} - TEST_F(VarTest, VarDim) { - FileManerger file(GetTestCaseResultFileName()); + FileManerger file(g_custom_param.get()); file.createFile(); file << "VarDim "; at::Tensor input = at::ones({2, 3}, at::kFloat); @@ -44,7 +33,7 @@ TEST_F(VarTest, VarDim) { } TEST_F(VarTest, VarAll) { - FileManerger file(GetTestCaseResultFileName()); + FileManerger file(g_custom_param.get()); file.openAppend(); file << "VarAll "; at::Tensor input = at::ones({2, 3}, at::kFloat); @@ -57,7 +46,7 @@ TEST_F(VarTest, VarAll) { } TEST_F(VarTest, VarDims) { - FileManerger file(GetTestCaseResultFileName()); + FileManerger file(g_custom_param.get()); file.openAppend(); file << "VarDims "; at::Tensor input = at::ones({2, 3}, at::kFloat); @@ -71,7 +60,7 @@ TEST_F(VarTest, VarDims) { } TEST_F(VarTest, VarCorrection) { - FileManerger file(GetTestCaseResultFileName()); + FileManerger file(g_custom_param.get()); file.openAppend(); file << "VarCorrection "; at::Tensor input = at::ones({2, 3}, at::kFloat); diff --git a/test/result_cmp.sh b/test/result_cmp.sh index e5fa3c0..4311325 100755 --- a/test/result_cmp.sh +++ b/test/result_cmp.sh @@ -8,6 +8,22 @@ PADDLE_PATH=${BUILD_PATH}/paddle/ TORCH_PATH=${BUILD_PATH}/torch/ RESULT_FILE_PATH="/tmp/paddle_cpp_api_test/" +cleanup_coverage_data() { + local build_path="$1" + local gcda_count + + if [[ ! -d "$build_path" ]]; then + return + fi + + gcda_count=$(find "$build_path" -type f -name "*.gcda" | wc -l) + gcda_count=${gcda_count//[[:space:]]/} + if [[ "$gcda_count" -gt 0 ]]; then + echo "Cleaning ${gcda_count} stale .gcda coverage files under ${build_path}..." + find "$build_path" -type f -name "*.gcda" -delete + fi +} + # 保存原始终端输出,并在退出时稳定打印日志路径 LOG_FILE="${RESULT_FILE_PATH}result_cmp_$(date +%Y%m%d_%H%M%S).log" mkdir -p "${RESULT_FILE_PATH}" @@ -16,6 +32,8 @@ trap 'status=$?; printf "\nDone. Full output saved to: %s\n" "$LOG_FILE" | tee - exec > >(tee -a "$LOG_FILE") 2>&1 echo "Log file: $LOG_FILE" +cleanup_coverage_data "$BUILD_PATH" + collect_and_run_executables() { local exec_path="$1" local prefix="$2" @@ -59,8 +77,12 @@ for key in "${!TORCH_EXECUTABLES[@]}"; do done while IFS= read -r key; do - paddle_exec="${PADDLE_EXECUTABLES[$key]}" - torch_exec="${TORCH_EXECUTABLES[$key]}" + if [[ -z "$key" ]]; then + continue + fi + + paddle_exec="${PADDLE_EXECUTABLES[$key]:-}" + torch_exec="${TORCH_EXECUTABLES[$key]:-}" if [[ -z "$paddle_exec" || -z "$torch_exec" ]]; then has_mismatch=1 From 223b3c6639b6ddb0e2bec77d0c5a7b79c6cd71f5 Mon Sep 17 00:00:00 2001 From: youge325 Date: Sat, 20 Jun 2026 22:27:47 +0800 Subject: [PATCH 03/12] Add transpose large-dim alignment tests --- test/ATen/ops/TransposeTest.cpp | 50 +++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/test/ATen/ops/TransposeTest.cpp b/test/ATen/ops/TransposeTest.cpp index 8731aa8..2d24da7 100644 --- a/test/ATen/ops/TransposeTest.cpp +++ b/test/ATen/ops/TransposeTest.cpp @@ -284,5 +284,55 @@ TEST_F(TransposeTest, TransposeSpecialValues) { file.saveFile(); } +TEST_F(TransposeTest, LargePositiveDimThrows) { + auto file_name = g_custom_param.get(); + FileManerger file(file_name); + file.openAppend(); + file << "LargePositiveDimThrows "; + + try { + (void)at::transpose(tensor, 1LL << 32, 1); + file << "ok "; + } catch (const std::exception&) { + file << "exception "; + } + + at::Tensor in_place = at::zeros({2, 3, 4}, at::kFloat); + try { + (void)in_place.transpose_(1LL << 32, 1); + file << "inplace_ok "; + } catch (const std::exception&) { + file << "inplace_exception "; + } + for (int64_t i = 0; i < in_place.dim(); ++i) { + file << std::to_string(in_place.sizes()[i]) << " "; + } + file << "\n"; + file.saveFile(); +} + +TEST_F(TransposeTest, LargeNegativeDimThrows) { + auto file_name = g_custom_param.get(); + FileManerger file(file_name); + file.openAppend(); + file << "LargeNegativeDimThrows "; + + try { + (void)tensor.transpose(0, -(1LL << 32)); + file << "member_ok "; + } catch (const std::exception&) { + file << "member_exception "; + } + + try { + (void)at::transpose(tensor, 0, -(1LL << 32)); + file << "free_ok "; + } catch (const std::exception&) { + file << "free_exception "; + } + file << "\n"; + file.saveFile(); +} + } // namespace test } // namespace at From b6d337b9d32f0f08b223487963a63b37fd097a21 Mon Sep 17 00:00:00 2001 From: youge325 Date: Fri, 26 Jun 2026 18:09:31 +0800 Subject: [PATCH 04/12] Add Tensor const_data_ptr alignment coverage --- test/ATen/ops/TensorPtrTest.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/ATen/ops/TensorPtrTest.cpp b/test/ATen/ops/TensorPtrTest.cpp index 8f46f8b..8c116c6 100644 --- a/test/ATen/ops/TensorPtrTest.cpp +++ b/test/ATen/ops/TensorPtrTest.cpp @@ -12,6 +12,9 @@ TEST(TensorBodyTest, PtrTest) { const float* const_ptr = t.const_data_ptr(); EXPECT_NE(const_ptr, nullptr); + const float* const_type_ptr = t.const_data_ptr(); + EXPECT_NE(const_type_ptr, nullptr); + const void* void_const_ptr = t.const_data_ptr(); EXPECT_NE(void_const_ptr, nullptr); @@ -27,6 +30,7 @@ TEST(TensorBodyTest, PtrTest) { file.createFile(); file << "PtrTest "; file << "const_ptr[0]: " + std::to_string(const_ptr[0]) + "\n"; + file << "const_type_ptr[0]: " + std::to_string(const_type_ptr[0]) + "\n"; mut_ptr[0] = 5.0f; file << "mut_ptr[0]: " + std::to_string(mut_ptr[0]) + "\n"; From 2be4399b90ce8ef95e209bad9d9ad104c71d91cb Mon Sep 17 00:00:00 2001 From: youge325 Date: Sat, 27 Jun 2026 11:18:19 +0800 Subject: [PATCH 05/12] Add TensorBase noexcept alignment coverage --- test/ATen/core/TensorUtilTest.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/test/ATen/core/TensorUtilTest.cpp b/test/ATen/core/TensorUtilTest.cpp index f0c17c7..947b4bc 100644 --- a/test/ATen/core/TensorUtilTest.cpp +++ b/test/ATen/core/TensorUtilTest.cpp @@ -5,6 +5,7 @@ #include #include +#include #include #include "src/file_manager.h" @@ -17,6 +18,11 @@ namespace test { using paddle_api_test::FileManerger; using paddle_api_test::ThreadSafeParam; +static_assert(noexcept(std::declval().is_same( + std::declval()))); +static_assert(noexcept(std::declval().use_count())); +static_assert(noexcept(std::declval().weak_use_count())); + class TensorUtilTest : public ::testing::Test { protected: void SetUp() override { From 622e2ba2b781b89e6bc01440f365bfe4004adbae Mon Sep 17 00:00:00 2001 From: youge325 Date: Sat, 27 Jun 2026 12:35:29 +0800 Subject: [PATCH 06/12] Extend Tensor pointer alignment coverage --- test/ATen/ops/TensorPtrTest.cpp | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/test/ATen/ops/TensorPtrTest.cpp b/test/ATen/ops/TensorPtrTest.cpp index 8c116c6..813bb4a 100644 --- a/test/ATen/ops/TensorPtrTest.cpp +++ b/test/ATen/ops/TensorPtrTest.cpp @@ -18,6 +18,12 @@ TEST(TensorBodyTest, PtrTest) { const void* void_const_ptr = t.const_data_ptr(); EXPECT_NE(void_const_ptr, nullptr); + float* data_ptr = t.data_ptr(); + EXPECT_NE(data_ptr, nullptr); + + void* void_data_ptr = t.data_ptr(); + EXPECT_NE(void_data_ptr, nullptr); + float* mut_ptr = t.mutable_data_ptr(); EXPECT_NE(mut_ptr, nullptr); @@ -31,6 +37,15 @@ TEST(TensorBodyTest, PtrTest) { file << "PtrTest "; file << "const_ptr[0]: " + std::to_string(const_ptr[0]) + "\n"; file << "const_type_ptr[0]: " + std::to_string(const_type_ptr[0]) + "\n"; + file << "void_const_ptr_equal: " + << std::to_string(void_const_ptr == static_cast(const_ptr)) + << "\n"; + file << "data_ptr_equal: " + << std::to_string(static_cast(data_ptr) == void_data_ptr) << "\n"; + file << "const_type_ptr_equal: " + << std::to_string(static_cast(const_type_ptr) == + static_cast(const_ptr)) + << "\n"; mut_ptr[0] = 5.0f; file << "mut_ptr[0]: " + std::to_string(mut_ptr[0]) + "\n"; From bc33301f27ed7711ae945bca892d23dd144f0a24 Mon Sep 17 00:00:00 2001 From: youge325 Date: Sat, 27 Jun 2026 21:14:14 +0800 Subject: [PATCH 07/12] Add as_strided_scatter alignment coverage --- test/ATen/ops/AsStridedTest.cpp | 35 +++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/test/ATen/ops/AsStridedTest.cpp b/test/ATen/ops/AsStridedTest.cpp index d1f46b4..90d650e 100644 --- a/test/ATen/ops/AsStridedTest.cpp +++ b/test/ATen/ops/AsStridedTest.cpp @@ -58,5 +58,40 @@ TEST_F(AsStridedTest, AsStridedScatter) { file.saveFile(); } +TEST_F(AsStridedTest, AsStridedScatterPreservesInputShape) { + FileManerger file(g_custom_param.get()); + file.openAppend(); + file << "AsStridedScatterPreservesInputShape "; + at::Tensor tensor = at::arange(12, at::kFloat); + at::Tensor src = at::full({2, 3}, 99.0f, at::kFloat); + at::Tensor result = tensor.as_strided_scatter(src, {2, 3}, {3, 1}); + file << std::to_string(result.dim()) << " "; + file << std::to_string(result.sizes()[0]) << " "; + float* data = result.data_ptr(); + for (int i = 0; i < 6; ++i) { + file << std::to_string(data[i]) << " "; + } + file << "\n"; + file.saveFile(); +} + +TEST_F(AsStridedTest, AsStridedScatterWithOffset) { + FileManerger file(g_custom_param.get()); + file.openAppend(); + file << "AsStridedScatterWithOffset "; + at::Tensor tensor = at::arange(12, at::kFloat); + at::Tensor src = at::full({2, 2}, 88.0f, at::kFloat); + at::Tensor result = tensor.as_strided_scatter(src, {2, 2}, {2, 1}, 2); + file << std::to_string(result.dim()) << " "; + file << std::to_string(result.sizes()[0]) << " "; + float* data = result.data_ptr(); + file << std::to_string(data[0]) << " "; + file << std::to_string(data[2]) << " "; + file << std::to_string(data[3]) << " "; + file << std::to_string(data[5]) << " "; + file << "\n"; + file.saveFile(); +} + } // namespace test } // namespace at From c29c30bfcb749567208508c504bdeac3c11007a2 Mon Sep 17 00:00:00 2001 From: youge325 Date: Sat, 27 Jun 2026 22:50:13 +0800 Subject: [PATCH 08/12] Add index_put None alignment coverage --- test/ATen/ops/IndexPutTest.cpp | 58 ++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/test/ATen/ops/IndexPutTest.cpp b/test/ATen/ops/IndexPutTest.cpp index 3b1b258..ba36b1d 100644 --- a/test/ATen/ops/IndexPutTest.cpp +++ b/test/ATen/ops/IndexPutTest.cpp @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -190,5 +191,62 @@ TEST(TensorBodyTest, IndexPutAccumulateTrue) { file.saveFile(); } +TEST(TensorBodyTest, IndexPutTensorIndexNoneValue) { + auto options = at::TensorOptions().dtype(at::kFloat).device(at::kCPU); + at::Tensor base = at::zeros({2, 3}, options); + at::Tensor values = at::full({1, 2, 3}, 6.0f, options); + + base.index_put_({at::indexing::None}, values); + + auto file_name = g_custom_param.get(); + FileManerger file(file_name); + file.openAppend(); + file << "IndexPutTensorIndexNoneValue "; + write_index_result_to_file(&file, base); + file << "\n"; + file.saveFile(); +} + +TEST(TensorBodyTest, IndexPutTensorIndexTensorNoneAndSlice) { + auto options = at::TensorOptions().dtype(at::kFloat).device(at::kCPU); + at::Tensor base = at::zeros({3, 4}, options); + at::Tensor idx = tensor_from_vector_i64({2, 0}); + at::Tensor values = at::full({2, 1, 4}, 8.0f, options); + + base.index_put_({idx, at::indexing::None, at::indexing::Slice()}, values); + + auto file_name = g_custom_param.get(); + FileManerger file(file_name); + file.openAppend(); + file << "IndexPutTensorIndexTensorNoneAndSlice "; + file << std::to_string(base.dim()) << " "; + file << std::to_string(base.numel()) << " "; + file << std::to_string(base.sizes()[0]) << " "; + file << std::to_string(base.sizes()[1]) << " "; + at::Tensor cont = base.contiguous(); + float* data = cont.data_ptr(); + file << std::to_string(data[0]) << " "; + file << std::to_string(data[4]) << " "; + file << std::to_string(data[8]) << " "; + file << std::to_string(cont.sum().item()) << " "; + file << "\n"; + file.saveFile(); +} + +TEST(TensorBodyTest, IndexPutTensorIndexNoneScalar) { + auto options = at::TensorOptions().dtype(at::kFloat).device(at::kCPU); + at::Tensor base = at::zeros({2, 3}, options); + + base.index_put_({at::indexing::None}, at::Scalar(4.0)); + + auto file_name = g_custom_param.get(); + FileManerger file(file_name); + file.openAppend(); + file << "IndexPutTensorIndexNoneScalar "; + write_index_result_to_file(&file, base); + file << "\n"; + file.saveFile(); +} + } // namespace test } // namespace at From 8f5d2517b0844dad6e7d3bfe880c2e55820a0dbe Mon Sep 17 00:00:00 2001 From: youge325 Date: Sat, 30 May 2026 17:35:28 +0800 Subject: [PATCH 09/12] test(index_reduce): align with Paddle compat index_reduce behavior Add cross-framework compatibility tests for Tensor::index_reduce: - 14 test cases covering prod/mean/amax/amin reduce modes - Shape coverage: small/large/boundary/1D/multi-dim - Dtype coverage: kFloat/kDouble/kInt/kLong - include_self true/false, in-place, non-member function - Invalid reduce type exception handling Related: PaddlePaddle/Paddle#79195 Co-Authored-By: Claude Opus 4.7 --- test/ATen/ops/IndexReduceTest.cpp | 325 ++++++++++++++++++++++++++++++ 1 file changed, 325 insertions(+) create mode 100644 test/ATen/ops/IndexReduceTest.cpp diff --git a/test/ATen/ops/IndexReduceTest.cpp b/test/ATen/ops/IndexReduceTest.cpp new file mode 100644 index 0000000..07cc4ab --- /dev/null +++ b/test/ATen/ops/IndexReduceTest.cpp @@ -0,0 +1,325 @@ +#include +#include +#include + +#include +#include + +#include "src/file_manager.h" + +extern paddle_api_test::ThreadSafeParam g_custom_param; + +namespace at { +namespace test { + +using paddle_api_test::FileManerger; + +static at::Tensor tensor_from_vector_i64(const std::vector& values) { + auto options = at::TensorOptions().dtype(at::kLong).device(at::kCPU); + return at::from_blob(const_cast(values.data()), + {static_cast(values.size())}, + options) + .clone(); +} + +static void write_index_reduce_result_to_file(FileManerger* file, + const at::Tensor& result) { + *file << std::to_string(result.dim()) << " "; + *file << std::to_string(result.numel()) << " "; + for (int64_t i = 0; i < result.dim(); ++i) { + *file << std::to_string(result.sizes()[i]) << " "; + } + if (result.numel() == 0) { + *file << "empty "; + return; + } + at::Tensor cont = result.contiguous(); + if (result.dtype() == at::kFloat) { + float* data = cont.data_ptr(); + *file << std::to_string(data[0]) << " "; + *file << std::to_string(data[cont.numel() - 1]) << " "; + *file << std::to_string(cont.sum().item()) << " "; + } else if (result.dtype() == at::kDouble) { + double* data = cont.data_ptr(); + *file << std::to_string(data[0]) << " "; + *file << std::to_string(data[cont.numel() - 1]) << " "; + *file << std::to_string(cont.sum().item()) << " "; + } else if (result.dtype() == at::kInt) { + int* data = cont.data_ptr(); + *file << std::to_string(data[0]) << " "; + *file << std::to_string(data[cont.numel() - 1]) << " "; + *file << std::to_string(cont.sum().item()) << " "; + } else if (result.dtype() == at::kLong) { + int64_t* data = cont.data_ptr(); + *file << std::to_string(data[0]) << " "; + *file << std::to_string(data[cont.numel() - 1]) << " "; + *file << std::to_string(cont.sum().item()) << " "; + } +} + +class IndexReduceTest : public ::testing::Test { + protected: + void SetUp() override {} +}; + +// index_reduce with "prod" reduce, float dtype, small shape +TEST_F(IndexReduceTest, IndexReduceProdFloatSmall) { + auto options = at::TensorOptions().dtype(at::kFloat).device(at::kCPU); + at::Tensor self = at::ones({3, 4}, options); + at::Tensor index = tensor_from_vector_i64({0, 2}); + at::Tensor source = at::full({2, 4}, 2.0f, options); + + at::Tensor result = self.index_reduce(0, index, source, "prod"); + + auto file_name = g_custom_param.get(); + FileManerger file(file_name); + file.createFile(); + file << "IndexReduceProdFloatSmall "; + write_index_reduce_result_to_file(&file, result); + file << "\n"; + file.saveFile(); +} + +// index_reduce with "mean" reduce, float dtype, small shape +TEST_F(IndexReduceTest, IndexReduceMeanFloatSmall) { + auto options = at::TensorOptions().dtype(at::kFloat).device(at::kCPU); + at::Tensor self = at::zeros({3, 4}, options); + at::Tensor index = tensor_from_vector_i64({0, 1, 0}); + at::Tensor source = at::full({3, 4}, 3.0f, options); + + at::Tensor result = self.index_reduce(0, index, source, "mean"); + + auto file_name = g_custom_param.get(); + FileManerger file(file_name); + file.openAppend(); + file << "IndexReduceMeanFloatSmall "; + write_index_reduce_result_to_file(&file, result); + file << "\n"; + file.saveFile(); +} + +// index_reduce with "amax" reduce, float dtype +TEST_F(IndexReduceTest, IndexReduceAmaxFloat) { + auto options = at::TensorOptions().dtype(at::kFloat).device(at::kCPU); + at::Tensor self = at::arange(0, 12, options).reshape({3, 4}); + at::Tensor index = tensor_from_vector_i64({0, 2, 0}); + at::Tensor source = at::full({3, 4}, 10.0f, options); + + at::Tensor result = self.index_reduce(0, index, source, "amax"); + + auto file_name = g_custom_param.get(); + FileManerger file(file_name); + file.openAppend(); + file << "IndexReduceAmaxFloat "; + write_index_reduce_result_to_file(&file, result); + file << "\n"; + file.saveFile(); +} + +// index_reduce with "amin" reduce, float dtype +TEST_F(IndexReduceTest, IndexReduceAminFloat) { + auto options = at::TensorOptions().dtype(at::kFloat).device(at::kCPU); + at::Tensor self = at::arange(0, 12, options).reshape({3, 4}); + at::Tensor index = tensor_from_vector_i64({1, 1, 0}); + at::Tensor source = at::full({3, 4}, -5.0f, options); + + at::Tensor result = self.index_reduce(0, index, source, "amin"); + + auto file_name = g_custom_param.get(); + FileManerger file(file_name); + file.openAppend(); + file << "IndexReduceAminFloat "; + write_index_reduce_result_to_file(&file, result); + file << "\n"; + file.saveFile(); +} + +// index_reduce with include_self=false +TEST_F(IndexReduceTest, IndexReduceProdExcludeSelf) { + auto options = at::TensorOptions().dtype(at::kFloat).device(at::kCPU); + at::Tensor self = at::full({3, 4}, 5.0f, options); + at::Tensor index = tensor_from_vector_i64({0, 2}); + at::Tensor source = at::full({2, 4}, 2.0f, options); + + at::Tensor result = self.index_reduce(0, index, source, "prod", false); + + auto file_name = g_custom_param.get(); + FileManerger file(file_name); + file.openAppend(); + file << "IndexReduceProdExcludeSelf "; + write_index_reduce_result_to_file(&file, result); + file << "\n"; + file.saveFile(); +} + +// index_reduce_ in-place version +TEST_F(IndexReduceTest, IndexReduceInplaceProd) { + auto options = at::TensorOptions().dtype(at::kFloat).device(at::kCPU); + at::Tensor self = at::ones({3, 4}, options); + at::Tensor index = tensor_from_vector_i64({0, 2}); + at::Tensor source = at::full({2, 4}, 3.0f, options); + + self.index_reduce_(0, index, source, "prod"); + + auto file_name = g_custom_param.get(); + FileManerger file(file_name); + file.openAppend(); + file << "IndexReduceInplaceProd "; + write_index_reduce_result_to_file(&file, self); + file << "\n"; + file.saveFile(); +} + +// index_reduce with double dtype +TEST_F(IndexReduceTest, IndexReduceMeanDouble) { + auto options = at::TensorOptions().dtype(at::kDouble).device(at::kCPU); + at::Tensor self = at::zeros({3, 4}, options); + at::Tensor index = tensor_from_vector_i64({0, 1, 0}); + at::Tensor source = at::full({3, 4}, 2.0, options); + + at::Tensor result = self.index_reduce(0, index, source, "mean"); + + auto file_name = g_custom_param.get(); + FileManerger file(file_name); + file.openAppend(); + file << "IndexReduceMeanDouble "; + write_index_reduce_result_to_file(&file, result); + file << "\n"; + file.saveFile(); +} + +// index_reduce with int dtype +TEST_F(IndexReduceTest, IndexReduceAmaxInt) { + auto options = at::TensorOptions().dtype(at::kInt).device(at::kCPU); + at::Tensor self = at::arange(0, 12, options).reshape({3, 4}); + at::Tensor index = tensor_from_vector_i64({0, 2, 0}); + at::Tensor source = at::full({3, 4}, 20, options); + + at::Tensor result = self.index_reduce(0, index, source, "amax"); + + auto file_name = g_custom_param.get(); + FileManerger file(file_name); + file.openAppend(); + file << "IndexReduceAmaxInt "; + write_index_reduce_result_to_file(&file, result); + file << "\n"; + file.saveFile(); +} + +// index_reduce with long dtype +TEST_F(IndexReduceTest, IndexReduceAminLong) { + auto options = at::TensorOptions().dtype(at::kLong).device(at::kCPU); + at::Tensor self = at::arange(0, 12, options).reshape({3, 4}); + at::Tensor index = tensor_from_vector_i64({1, 1, 0}); + at::Tensor source = at::full({3, 4}, -3L, options); + + at::Tensor result = self.index_reduce(0, index, source, "amin"); + + auto file_name = g_custom_param.get(); + FileManerger file(file_name); + file.openAppend(); + file << "IndexReduceAminLong "; + write_index_reduce_result_to_file(&file, result); + file << "\n"; + file.saveFile(); +} + +// index_reduce with large shape +TEST_F(IndexReduceTest, IndexReduceProdLargeShape) { + auto options = at::TensorOptions().dtype(at::kFloat).device(at::kCPU); + at::Tensor self = at::ones({50, 20}, options); + std::vector idx_vec; + for (int64_t i = 0; i < 10; ++i) { + idx_vec.push_back(i % 5); + } + at::Tensor index = tensor_from_vector_i64(idx_vec); + at::Tensor source = at::full({10, 20}, 2.0f, options); + + at::Tensor result = self.index_reduce(0, index, source, "prod"); + + auto file_name = g_custom_param.get(); + FileManerger file(file_name); + file.openAppend(); + file << "IndexReduceProdLargeShape "; + write_index_reduce_result_to_file(&file, result); + file << "\n"; + file.saveFile(); +} + +// index_reduce on dim=1 +TEST_F(IndexReduceTest, IndexReduceDim1) { + auto options = at::TensorOptions().dtype(at::kFloat).device(at::kCPU); + at::Tensor self = at::zeros({4, 6}, options); + at::Tensor index = tensor_from_vector_i64({1, 3, 5}); + at::Tensor source = at::full({4, 3}, 4.0f, options); + + at::Tensor result = self.index_reduce(1, index, source, "mean"); + + auto file_name = g_custom_param.get(); + FileManerger file(file_name); + file.openAppend(); + file << "IndexReduceDim1 "; + write_index_reduce_result_to_file(&file, result); + file << "\n"; + file.saveFile(); +} + +// index_reduce with boundary shape (1D tensor) +TEST_F(IndexReduceTest, IndexReduce1D) { + auto options = at::TensorOptions().dtype(at::kFloat).device(at::kCPU); + at::Tensor self = at::ones({5}, options); + at::Tensor index = tensor_from_vector_i64({0, 2, 4}); + at::Tensor source = at::full({3}, 3.0f, options); + + at::Tensor result = self.index_reduce(0, index, source, "prod"); + + auto file_name = g_custom_param.get(); + FileManerger file(file_name); + file.openAppend(); + file << "IndexReduce1D "; + write_index_reduce_result_to_file(&file, result); + file << "\n"; + file.saveFile(); +} + +// index_reduce non-member function version +TEST_F(IndexReduceTest, IndexReduceNonMember) { + auto options = at::TensorOptions().dtype(at::kFloat).device(at::kCPU); + at::Tensor self = at::ones({3, 4}, options); + at::Tensor index = tensor_from_vector_i64({0, 2}); + at::Tensor source = at::full({2, 4}, 2.0f, options); + + at::Tensor result = at::index_reduce(self, 0, index, source, "prod"); + + auto file_name = g_custom_param.get(); + FileManerger file(file_name); + file.openAppend(); + file << "IndexReduceNonMember "; + write_index_reduce_result_to_file(&file, result); + file << "\n"; + file.saveFile(); +} + +// index_reduce invalid reduce type - should throw +TEST_F(IndexReduceTest, IndexReduceInvalidReduce) { + auto options = at::TensorOptions().dtype(at::kFloat).device(at::kCPU); + at::Tensor self = at::ones({3, 4}, options); + at::Tensor index = tensor_from_vector_i64({0, 2}); + at::Tensor source = at::full({2, 4}, 2.0f, options); + + auto file_name = g_custom_param.get(); + FileManerger file(file_name); + file.openAppend(); + file << "IndexReduceInvalidReduce "; + try { + (void)self.index_reduce(0, index, source, "invalid"); + file << "no_exception "; + } catch (const std::exception&) { + file << "exception "; + } + file << "\n"; + file.saveFile(); +} + +} // namespace test +} // namespace at From 26ffb8568fc7c55596cabdcae3ee2b93e1053b64 Mon Sep 17 00:00:00 2001 From: youge325 Date: Sun, 14 Jun 2026 16:55:21 +0800 Subject: [PATCH 10/12] test(index_reduce): cover review alignment cases --- test/ATen/ops/IndexReduceTest.cpp | 149 ++++++++++++++++++++++++++++++ 1 file changed, 149 insertions(+) diff --git a/test/ATen/ops/IndexReduceTest.cpp b/test/ATen/ops/IndexReduceTest.cpp index 07cc4ab..ddd0dfb 100644 --- a/test/ATen/ops/IndexReduceTest.cpp +++ b/test/ATen/ops/IndexReduceTest.cpp @@ -22,6 +22,22 @@ static at::Tensor tensor_from_vector_i64(const std::vector& values) { .clone(); } +static at::Tensor tensor_from_vector_i32(const std::vector& values) { + auto options = at::TensorOptions().dtype(at::kInt).device(at::kCPU); + return at::from_blob(const_cast(values.data()), + {static_cast(values.size())}, + options) + .clone(); +} + +static at::Tensor tensor_from_vector_f32(const std::vector& values) { + auto options = at::TensorOptions().dtype(at::kFloat).device(at::kCPU); + return at::from_blob(const_cast(values.data()), + {static_cast(values.size())}, + options) + .clone(); +} + static void write_index_reduce_result_to_file(FileManerger* file, const at::Tensor& result) { *file << std::to_string(result.dim()) << " "; @@ -264,6 +280,40 @@ TEST_F(IndexReduceTest, IndexReduceDim1) { file.saveFile(); } +TEST_F(IndexReduceTest, IndexReduceNegativeDim) { + auto options = at::TensorOptions().dtype(at::kFloat).device(at::kCPU); + at::Tensor self = at::zeros({4, 6}, options); + at::Tensor index = tensor_from_vector_i64({1, 3, 5}); + at::Tensor source = at::full({4, 3}, 4.0f, options); + + at::Tensor result = self.index_reduce(-1, index, source, "mean"); + + auto file_name = g_custom_param.get(); + FileManerger file(file_name); + file.openAppend(); + file << "IndexReduceNegativeDim "; + write_index_reduce_result_to_file(&file, result); + file << "\n"; + file.saveFile(); +} + +TEST_F(IndexReduceTest, IndexReduceInt32Index) { + auto options = at::TensorOptions().dtype(at::kFloat).device(at::kCPU); + at::Tensor self = at::ones({3, 4}, options); + at::Tensor index = tensor_from_vector_i32({0, 2}); + at::Tensor source = at::full({2, 4}, 2.0f, options); + + at::Tensor result = self.index_reduce(0, index, source, "prod"); + + auto file_name = g_custom_param.get(); + FileManerger file(file_name); + file.openAppend(); + file << "IndexReduceInt32Index "; + write_index_reduce_result_to_file(&file, result); + file << "\n"; + file.saveFile(); +} + // index_reduce with boundary shape (1D tensor) TEST_F(IndexReduceTest, IndexReduce1D) { auto options = at::TensorOptions().dtype(at::kFloat).device(at::kCPU); @@ -321,5 +371,104 @@ TEST_F(IndexReduceTest, IndexReduceInvalidReduce) { file.saveFile(); } +TEST_F(IndexReduceTest, IndexReduceSumReduceThrows) { + auto options = at::TensorOptions().dtype(at::kFloat).device(at::kCPU); + at::Tensor self = at::ones({3, 4}, options); + at::Tensor index = tensor_from_vector_i64({0, 2}); + at::Tensor source = at::full({2, 4}, 2.0f, options); + + auto file_name = g_custom_param.get(); + FileManerger file(file_name); + file.openAppend(); + file << "IndexReduceSumReduceThrows "; + try { + (void)self.index_reduce(0, index, source, "sum"); + file << "no_exception "; + } catch (const std::exception&) { + file << "exception "; + } + file << "\n"; + file.saveFile(); +} + +TEST_F(IndexReduceTest, IndexReducePaddleReduceNameThrows) { + auto options = at::TensorOptions().dtype(at::kFloat).device(at::kCPU); + at::Tensor self = at::ones({3, 4}, options); + at::Tensor index = tensor_from_vector_i64({0, 2}); + at::Tensor source = at::full({2, 4}, 2.0f, options); + + auto file_name = g_custom_param.get(); + FileManerger file(file_name); + file.openAppend(); + file << "IndexReducePaddleReduceNameThrows "; + try { + (void)self.index_reduce(0, index, source, "add"); + file << "no_exception "; + } catch (const std::exception&) { + file << "exception "; + } + file << "\n"; + file.saveFile(); +} + +TEST_F(IndexReduceTest, IndexReduceFloatIndexThrows) { + auto options = at::TensorOptions().dtype(at::kFloat).device(at::kCPU); + at::Tensor self = at::ones({3, 4}, options); + at::Tensor index = tensor_from_vector_f32({0.0f, 2.0f}); + at::Tensor source = at::full({2, 4}, 2.0f, options); + + auto file_name = g_custom_param.get(); + FileManerger file(file_name); + file.openAppend(); + file << "IndexReduceFloatIndexThrows "; + try { + (void)self.index_reduce(0, index, source, "prod"); + file << "no_exception "; + } catch (const std::exception&) { + file << "exception "; + } + file << "\n"; + file.saveFile(); +} + +TEST_F(IndexReduceTest, IndexReduceSourceDtypeMismatchThrows) { + auto self_options = at::TensorOptions().dtype(at::kFloat).device(at::kCPU); + auto source_options = at::TensorOptions().dtype(at::kDouble).device(at::kCPU); + at::Tensor self = at::ones({3, 4}, self_options); + at::Tensor index = tensor_from_vector_i64({0, 2}); + at::Tensor source = at::full({2, 4}, 2.0, source_options); + + auto file_name = g_custom_param.get(); + FileManerger file(file_name); + file.openAppend(); + file << "IndexReduceSourceDtypeMismatchThrows "; + try { + (void)self.index_reduce(0, index, source, "prod"); + file << "no_exception "; + } catch (const std::exception&) { + file << "exception "; + } + file << "\n"; + file.saveFile(); +} + +TEST_F(IndexReduceTest, IndexReduceOutWritesOutput) { + auto options = at::TensorOptions().dtype(at::kFloat).device(at::kCPU); + at::Tensor self = at::ones({3, 4}, options); + at::Tensor index = tensor_from_vector_i64({0, 2}); + at::Tensor source = at::full({2, 4}, 2.0f, options); + at::Tensor out = at::zeros({3, 4}, options); + + at::index_reduce_out(out, self, 0, index, source, "prod", false); + + auto file_name = g_custom_param.get(); + FileManerger file(file_name); + file.openAppend(); + file << "IndexReduceOutWritesOutput "; + write_index_reduce_result_to_file(&file, out); + file << "\n"; + file.saveFile(); +} + } // namespace test } // namespace at From 3b23fe32810eb7d405abee6789a83e5a0f1f8f08 Mon Sep 17 00:00:00 2001 From: youge325 Date: Mon, 15 Jun 2026 09:56:34 +0800 Subject: [PATCH 11/12] test(ATen): cover index_reduce index bounds --- test/ATen/ops/IndexReduceTest.cpp | 40 +++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/test/ATen/ops/IndexReduceTest.cpp b/test/ATen/ops/IndexReduceTest.cpp index ddd0dfb..c11e2ab 100644 --- a/test/ATen/ops/IndexReduceTest.cpp +++ b/test/ATen/ops/IndexReduceTest.cpp @@ -431,6 +431,46 @@ TEST_F(IndexReduceTest, IndexReduceFloatIndexThrows) { file.saveFile(); } +TEST_F(IndexReduceTest, IndexReduceNegativeIndexThrows) { + auto options = at::TensorOptions().dtype(at::kFloat).device(at::kCPU); + at::Tensor self = at::ones({3, 4}, options); + at::Tensor index = tensor_from_vector_i64({0, -1}); + at::Tensor source = at::full({2, 4}, 2.0f, options); + + auto file_name = g_custom_param.get(); + FileManerger file(file_name); + file.openAppend(); + file << "IndexReduceNegativeIndexThrows "; + try { + (void)self.index_reduce(0, index, source, "prod"); + file << "no_exception "; + } catch (const std::exception&) { + file << "exception "; + } + file << "\n"; + file.saveFile(); +} + +TEST_F(IndexReduceTest, IndexReduceUpperBoundIndexThrows) { + auto options = at::TensorOptions().dtype(at::kFloat).device(at::kCPU); + at::Tensor self = at::ones({3, 4}, options); + at::Tensor index = tensor_from_vector_i32({0, 3}); + at::Tensor source = at::full({2, 4}, 2.0f, options); + + auto file_name = g_custom_param.get(); + FileManerger file(file_name); + file.openAppend(); + file << "IndexReduceUpperBoundIndexThrows "; + try { + (void)self.index_reduce(0, index, source, "prod"); + file << "no_exception "; + } catch (const std::exception&) { + file << "exception "; + } + file << "\n"; + file.saveFile(); +} + TEST_F(IndexReduceTest, IndexReduceSourceDtypeMismatchThrows) { auto self_options = at::TensorOptions().dtype(at::kFloat).device(at::kCPU); auto source_options = at::TensorOptions().dtype(at::kDouble).device(at::kCPU); From 17ce5a906e0498da5d441c20c7f92310fc0ef7d7 Mon Sep 17 00:00:00 2001 From: youge325 Date: Mon, 15 Jun 2026 10:44:50 +0800 Subject: [PATCH 12/12] test(ATen): cover index_reduce invalid reduce names --- test/ATen/ops/IndexReduceTest.cpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/test/ATen/ops/IndexReduceTest.cpp b/test/ATen/ops/IndexReduceTest.cpp index c11e2ab..49dab36 100644 --- a/test/ATen/ops/IndexReduceTest.cpp +++ b/test/ATen/ops/IndexReduceTest.cpp @@ -401,11 +401,14 @@ TEST_F(IndexReduceTest, IndexReducePaddleReduceNameThrows) { FileManerger file(file_name); file.openAppend(); file << "IndexReducePaddleReduceNameThrows "; - try { - (void)self.index_reduce(0, index, source, "add"); - file << "no_exception "; - } catch (const std::exception&) { - file << "exception "; + const char* reduce_names[] = {"add", "assign", "multiply"}; + for (const char* reduce : reduce_names) { + try { + (void)self.index_reduce(0, index, source, reduce); + file << "no_exception "; + } catch (const std::exception&) { + file << "exception "; + } } file << "\n"; file.saveFile();