// 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. #include #include #include #include #include #include #include #include #if defined(PADDLE_WITH_CUDA) || defined(PADDLE_WITH_HIP) #include #include #endif #include "ATen/ATen.h" #include "gtest/gtest.h" #include "paddle/phi/common/float16.h" #include "torch/all.h" // ============================================================ // Tests for at::Tensor::item() / at::Tensor::item() // ============================================================ TEST(TensorItemTest, ItemFloat_ReturnsScalar) { // item() on a single-element float tensor returns an at::Scalar at::Tensor t = at::tensor({3.14f}, at::kFloat); at::Scalar s = t.item(); ASSERT_NEAR(s.to(), 3.14f, 1e-5f); } TEST(TensorItemTest, ItemDouble_ReturnsScalar) { // item() on a single-element double tensor at::Tensor t = at::tensor({2.718281828}, at::kDouble); at::Scalar s = t.item(); ASSERT_NEAR(s.to(), 2.718281828, 1e-9); } TEST(TensorItemTest, ItemInt32_ReturnsScalar) { // item() on a single-element int32 tensor at::Tensor t = at::tensor({42}, at::kInt); at::Scalar s = t.item(); ASSERT_EQ(s.to(), 42); } TEST(TensorItemTest, ItemInt64_ReturnsScalar) { // item() on a single-element int64 tensor at::Tensor t = at::tensor({static_cast(1234567890)}, at::kLong); at::Scalar s = t.item(); ASSERT_EQ(s.to(), 1234567890LL); } TEST(TensorItemTest, ItemTemplated_Float) { // item() returns float directly at::Tensor t = at::tensor({1.5f}, at::kFloat); float val = t.item(); ASSERT_FLOAT_EQ(val, 1.5f); } TEST(TensorItemTest, ItemTemplated_Double) { // item() returns double directly at::Tensor t = at::tensor({1.0 / 3.0}, at::kDouble); double val = t.item(); ASSERT_NEAR(val, 1.0 / 3.0, 1e-15); } TEST(TensorItemTest, ItemTemplated_Int32) { // item() on int32 tensor at::Tensor t = at::tensor({-7}, at::kInt); int32_t val = t.item(); ASSERT_EQ(val, -7); } TEST(TensorItemTest, ItemFromSqueezed1D) { // item() works on a tensor that has been reshaped to single element via // squeeze / indexing at::Tensor t = at::arange(6, at::kFloat).reshape({2, 3}); at::Tensor elem = t[1][2]; // value = 5.0 ASSERT_FLOAT_EQ(elem.item(), 5.0f); } TEST(TensorItemTest, ItemOnMultiElementTensorThrows) { // item() on a tensor with more than one element must throw. at::Tensor t = at::ones({2, 3}, at::kFloat); ASSERT_THROW(t.item(), std::exception); } // ============================================================ // Tests for at::Tensor::is_variable() // ============================================================ TEST(TensorIsVariableTest, AlwaysReturnsTrue) { // is_variable() is always true in the eager execution mode. at::Tensor t = at::ones({3, 4}, at::kFloat); ASSERT_TRUE(t.is_variable()); } TEST(TensorIsVariableTest, AlwaysTrueForScalarTensor) { at::Tensor t = at::tensor({1.0f}, at::kFloat); ASSERT_TRUE(t.is_variable()); } TEST(TensorIsVariableTest, AlwaysTrueFor1D) { at::Tensor t = at::arange(10, at::kFloat); ASSERT_TRUE(t.is_variable()); } // ============================================================ // Tests for at::Tensor::item() — sparse tensor paths // ============================================================ TEST(TensorItemSparseTest, EmptySparseCOO_ItemReturnsZero) { // A sparse tensor with nnz == 0: item() must return zero (Scalar(0)). at::Tensor indices = at::zeros({2, 0}, at::kLong); at::Tensor values = at::zeros({0}, at::kFloat); // 1x1 empty sparse tensor at::Tensor sparse = at::sparse_coo_tensor(indices, values, {1, 1}); sparse = sparse.coalesce(); at::Scalar s = sparse.item(); ASSERT_NEAR(s.to(), 0.0f, 1e-6f); } TEST(TensorItemSparseTest, CoalescedSparseCOO_SingleNonZero_ReturnsValue) { // 1x1 sparse COO with one non-zero at (0,0) = 5.0. at::Tensor indices = at::tensor({0, 0}, at::kLong).reshape({2, 1}); at::Tensor values = at::tensor({5.0f}, at::kFloat); at::Tensor sparse = at::sparse_coo_tensor(indices, values, {1, 1}); sparse = sparse.coalesce(); ASSERT_TRUE(sparse.is_coalesced()); at::Scalar s = sparse.item(); ASSERT_NEAR(s.to(), 5.0f, 1e-5f); } TEST(TensorItemSparseTest, NonCoalescedSparseCOO_DuplicateIndices_SumsValues) { // Two entries both at (0,0): item() must sum them (3 + 7 = 10). at::Tensor indices = at::tensor({0, 0, 0, 0}, at::kLong).reshape({2, 2}); at::Tensor values = at::tensor({3.0f, 7.0f}, at::kFloat); at::Tensor sparse = at::sparse_coo_tensor(indices, values, {1, 1}); // Do NOT coalesce — exercising the non-coalesced path. ASSERT_FALSE(sparse.is_coalesced()); at::Scalar s = sparse.item(); ASSERT_NEAR(s.to(), 10.0f, 1e-5f); }