// 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/bfloat16.h" #include "paddle/phi/common/float16.h" #include "torch/all.h" // ============================================================ // Tests for at::_local_scalar_dense() // ============================================================ TEST(LocalScalarDenseTest, Float32_ReturnsCorrectValue) { at::Tensor t = at::tensor({2.5f}, at::kFloat); at::Scalar s = at::_local_scalar_dense(t); ASSERT_NEAR(s.to(), 2.5f, 1e-6f); } TEST(LocalScalarDenseTest, Float64_ReturnsCorrectValue) { at::Tensor t = at::tensor({3.141592653589793}, at::kDouble); at::Scalar s = at::_local_scalar_dense(t); ASSERT_NEAR(s.to(), 3.141592653589793, 1e-12); } TEST(LocalScalarDenseTest, Float16_ReturnsCorrectValue) { // Create FP16 tensor from float, then read back via _local_scalar_dense. at::Tensor t = at::tensor({1.5f}, at::kHalf); at::Scalar s = at::_local_scalar_dense(t); // Float16 has ~3 significant decimal digits. ASSERT_NEAR(s.to(), 1.5f, 1e-2f); } TEST(LocalScalarDenseTest, BFloat16_ReturnsCorrectValue) { at::Tensor t = at::tensor({1.0f}, at::kBFloat16); at::Scalar s = at::_local_scalar_dense(t); ASSERT_NEAR(s.to(), 1.0f, 1e-2f); } TEST(LocalScalarDenseTest, Int8_ReturnsCorrectValue) { at::Tensor t = at::tensor({static_cast(-7)}, at::kChar); at::Scalar s = at::_local_scalar_dense(t); ASSERT_EQ(s.to(), static_cast(-7)); } TEST(LocalScalarDenseTest, Int16_ReturnsCorrectValue) { at::Tensor t = at::tensor({static_cast(300)}, at::kShort); at::Scalar s = at::_local_scalar_dense(t); ASSERT_EQ(s.to(), static_cast(300)); } TEST(LocalScalarDenseTest, Int32_ReturnsCorrectValue) { at::Tensor t = at::tensor({42}, at::kInt); at::Scalar s = at::_local_scalar_dense(t); ASSERT_EQ(s.to(), 42); } TEST(LocalScalarDenseTest, Int64_ReturnsCorrectValue) { at::Tensor t = at::tensor({static_cast(9876543210LL)}, at::kLong); at::Scalar s = at::_local_scalar_dense(t); ASSERT_EQ(s.to(), 9876543210LL); } TEST(LocalScalarDenseTest, UInt8_ReturnsCorrectValue) { at::Tensor t = at::tensor({static_cast(255)}, at::kByte); at::Scalar s = at::_local_scalar_dense(t); ASSERT_EQ(s.to(), static_cast(255)); } TEST(LocalScalarDenseTest, Bool_True_ReturnsCorrectValue) { at::Tensor t = at::tensor({true}, at::kBool); at::Scalar s = at::_local_scalar_dense(t); ASSERT_TRUE(s.to()); } TEST(LocalScalarDenseTest, Bool_False_ReturnsCorrectValue) { at::Tensor t = at::tensor({false}, at::kBool); at::Scalar s = at::_local_scalar_dense(t); ASSERT_FALSE(s.to()); } TEST(LocalScalarDenseTest, NegativeValue_Float) { at::Tensor t = at::tensor({-99.0f}, at::kFloat); at::Scalar s = at::_local_scalar_dense(t); ASSERT_NEAR(s.to(), -99.0f, 1e-5f); } TEST(LocalScalarDenseTest, ZeroValue_Int32) { at::Tensor t = at::tensor({0}, at::kInt); at::Scalar s = at::_local_scalar_dense(t); ASSERT_EQ(s.to(), 0); } #if defined(PADDLE_WITH_CUDA) || defined(PADDLE_WITH_HIP) TEST(LocalScalarDenseTest, GPU_Float32_ReturnsCorrectValue) { // _local_scalar_dense must copy to CPU when the tensor is on GPU. at::Tensor t = at::tensor( {7.0f}, at::TensorOptions().dtype(at::kFloat).device(c10::Device(c10::kCUDA, 0))); at::Scalar s = at::_local_scalar_dense(t); ASSERT_NEAR(s.to(), 7.0f, 1e-5f); } #endif TEST(LocalScalarDenseTest, EmptyTensor_ThrowsCheck) { // Passing an empty tensor should trigger PD_CHECK in the implementation. at::Tensor t = at::empty({0}, at::kFloat); ASSERT_THROW(at::_local_scalar_dense(t), std::exception); }