Skip to content

Commit 56cf145

Browse files
committed
Add unittests for cuSub
1 parent d7e9612 commit 56cf145

File tree

2 files changed

+204
-0
lines changed

2 files changed

+204
-0
lines changed

tests/gpu/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ add_executable(
1717
linalg_test/Abs_test.cpp
1818
linalg_test/Add_test.cpp
1919
linalg_test/Mul_test.cpp
20+
linalg_test/Sub_test.cpp
2021
linalg_test/Det_test.cpp
2122
linalg_test/Directsum_test.cpp
2223
linalg_test/ExpH_test.cpp

tests/gpu/linalg_test/Sub_test.cpp

Lines changed: 203 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,203 @@
1+
#include "gtest/gtest.h"
2+
3+
#include "gpu_test_tools.h"
4+
#include "cytnx.hpp"
5+
6+
namespace SubTest {
7+
8+
::testing::AssertionResult CheckSubResult(const cytnx::Tensor& gpu_result,
9+
const cytnx::Tensor& left_tensor,
10+
const cytnx::Tensor& right_tensor);
11+
12+
::testing::AssertionResult CheckSubScalarResult(const cytnx::Tensor& gpu_result,
13+
const cytnx::Tensor& tensor,
14+
const cytnx::cytnx_double& scalar,
15+
bool scalar_left = false);
16+
17+
std::vector<std::vector<cytnx::cytnx_uint64>> GetTestShapes();
18+
19+
cytnx::cytnx_double GetTolerance(const unsigned int& dtype);
20+
21+
class SubTestAllShapes : public ::testing::TestWithParam<std::vector<cytnx::cytnx_uint64>> {};
22+
23+
// Test tensor-to-tensor subtraction
24+
TEST_P(SubTestAllShapes, gpu_tensor_sub_tensor_all_types) {
25+
const std::vector<cytnx::cytnx_uint64>& shape = GetParam();
26+
27+
for (auto dtype : cytnx::TestTools::dtype_list) {
28+
if (dtype == cytnx::Type.Bool) {
29+
continue;
30+
}
31+
32+
SCOPED_TRACE("Testing Sub(tensor, tensor) with shape: " + ::testing::PrintToString(shape) +
33+
" and dtype: " + std::to_string(dtype));
34+
35+
cytnx::Tensor gpu_tensor1 = cytnx::Tensor(shape, dtype).to(cytnx::Device.cuda);
36+
cytnx::Tensor gpu_tensor2 = cytnx::Tensor(shape, dtype).to(cytnx::Device.cuda);
37+
cytnx::TestTools::InitTensorUniform(gpu_tensor1);
38+
cytnx::TestTools::InitTensorUniform(gpu_tensor2);
39+
40+
cytnx::Tensor gpu_result = cytnx::linalg::Sub(gpu_tensor1, gpu_tensor2);
41+
EXPECT_TRUE(CheckSubResult(gpu_result, gpu_tensor1, gpu_tensor2));
42+
43+
cytnx::Tensor gpu_result_member = gpu_tensor1.Sub(gpu_tensor2);
44+
EXPECT_TRUE(CheckSubResult(gpu_result_member, gpu_tensor1, gpu_tensor2));
45+
46+
cytnx::Tensor gpu_result_operator = gpu_tensor1 - gpu_tensor2;
47+
EXPECT_TRUE(CheckSubResult(gpu_result_operator, gpu_tensor1, gpu_tensor2));
48+
}
49+
}
50+
51+
// Test scalar-to-tensor subtraction
52+
TEST_P(SubTestAllShapes, gpu_scalar_sub_tensor_all_types) {
53+
const std::vector<cytnx::cytnx_uint64>& shape = GetParam();
54+
55+
for (auto dtype : cytnx::TestTools::dtype_list) {
56+
if (dtype == cytnx::Type.Bool) {
57+
continue;
58+
}
59+
60+
SCOPED_TRACE("Testing Sub(scalar, tensor) with shape: " + ::testing::PrintToString(shape) +
61+
" and dtype: " + std::to_string(dtype));
62+
63+
cytnx::Tensor gpu_tensor = cytnx::Tensor(shape, dtype).to(cytnx::Device.cuda);
64+
cytnx::TestTools::InitTensorUniform(gpu_tensor);
65+
cytnx::cytnx_double scalar = 2.3;
66+
67+
cytnx::Tensor gpu_result = cytnx::linalg::Sub(scalar, gpu_tensor);
68+
EXPECT_TRUE(CheckSubScalarResult(gpu_result, gpu_tensor, scalar, true));
69+
70+
cytnx::Tensor gpu_result_operator = scalar - gpu_tensor;
71+
EXPECT_TRUE(CheckSubScalarResult(gpu_result_operator, gpu_tensor, scalar, true));
72+
}
73+
}
74+
75+
// Test tensor-to-scalar subtraction
76+
TEST_P(SubTestAllShapes, gpu_tensor_sub_scalar_all_types) {
77+
const std::vector<cytnx::cytnx_uint64>& shape = GetParam();
78+
79+
for (auto dtype : cytnx::TestTools::dtype_list) {
80+
if (dtype == cytnx::Type.Bool) {
81+
continue;
82+
}
83+
84+
SCOPED_TRACE("Testing Sub(tensor, scalar) with shape: " + ::testing::PrintToString(shape) +
85+
" and dtype: " + std::to_string(dtype));
86+
87+
cytnx::Tensor gpu_tensor = cytnx::Tensor(shape, dtype).to(cytnx::Device.cuda);
88+
cytnx::TestTools::InitTensorUniform(gpu_tensor);
89+
cytnx::cytnx_double scalar = 2.3;
90+
91+
cytnx::Tensor gpu_result = cytnx::linalg::Sub(gpu_tensor, scalar);
92+
EXPECT_TRUE(CheckSubScalarResult(gpu_result, gpu_tensor, scalar, false));
93+
94+
cytnx::Tensor gpu_result_member = gpu_tensor.Sub(scalar);
95+
EXPECT_TRUE(CheckSubScalarResult(gpu_result_member, gpu_tensor, scalar, false));
96+
97+
cytnx::Tensor gpu_result_operator = gpu_tensor - scalar;
98+
EXPECT_TRUE(CheckSubScalarResult(gpu_result_operator, gpu_tensor, scalar, false));
99+
}
100+
}
101+
102+
// Test in-place tensor subtraction
103+
TEST_P(SubTestAllShapes, gpu_tensor_isub_all_types) {
104+
const std::vector<cytnx::cytnx_uint64>& shape = GetParam();
105+
106+
for (auto dtype : cytnx::TestTools::dtype_list) {
107+
if (dtype == cytnx::Type.Bool) {
108+
continue;
109+
}
110+
111+
SCOPED_TRACE("Testing iSub(tensor, tensor) with shape: " + ::testing::PrintToString(shape) +
112+
" and dtype: " + std::to_string(dtype));
113+
114+
cytnx::Tensor gpu_tensor1 = cytnx::Tensor(shape, dtype).to(cytnx::Device.cuda);
115+
cytnx::Tensor gpu_tensor2 = cytnx::Tensor(shape, dtype).to(cytnx::Device.cuda);
116+
cytnx::TestTools::InitTensorUniform(gpu_tensor1);
117+
cytnx::TestTools::InitTensorUniform(gpu_tensor2);
118+
119+
cytnx::Tensor original_gpu_tensor1 = gpu_tensor1.clone();
120+
cytnx::Tensor original_gpu_tensor2 = gpu_tensor2.clone();
121+
122+
cytnx::linalg::iSub(gpu_tensor1, gpu_tensor2);
123+
EXPECT_TRUE(CheckSubResult(gpu_tensor1, original_gpu_tensor1, original_gpu_tensor2));
124+
125+
cytnx::Tensor gpu_tensor1_op = original_gpu_tensor1.clone();
126+
gpu_tensor1_op -= original_gpu_tensor2;
127+
EXPECT_TRUE(CheckSubResult(gpu_tensor1_op, original_gpu_tensor1, original_gpu_tensor2));
128+
}
129+
}
130+
131+
INSTANTIATE_TEST_SUITE_P(SubTests, SubTestAllShapes, ::testing::ValuesIn(GetTestShapes()));
132+
133+
::testing::AssertionResult CheckSubResult(const cytnx::Tensor& gpu_result,
134+
const cytnx::Tensor& left_tensor,
135+
const cytnx::Tensor& right_tensor) {
136+
// Compare CUDA Sub result against CPU Sub result
137+
cytnx::Tensor left_cpu = left_tensor.to(cytnx::Device.cpu);
138+
cytnx::Tensor right_cpu = right_tensor.to(cytnx::Device.cpu);
139+
cytnx::Tensor expected_cpu = cytnx::linalg::Sub(left_cpu, right_cpu);
140+
cytnx::Tensor gpu_result_cpu = gpu_result.to(cytnx::Device.cpu);
141+
142+
cytnx::cytnx_double tolerance = GetTolerance(gpu_result.dtype());
143+
144+
if (!cytnx::TestTools::AreNearlyEqTensor(gpu_result_cpu, expected_cpu, tolerance)) {
145+
return ::testing::AssertionFailure()
146+
<< "Sub result mismatch: CUDA Sub result differs from CPU Sub result. "
147+
<< "Left dtype: " << left_tensor.dtype() << ", Right dtype: " << right_tensor.dtype()
148+
<< ", tolerance used: " << tolerance;
149+
}
150+
151+
return ::testing::AssertionSuccess();
152+
}
153+
154+
::testing::AssertionResult CheckSubScalarResult(const cytnx::Tensor& gpu_result,
155+
const cytnx::Tensor& tensor,
156+
const cytnx::cytnx_double& scalar,
157+
bool scalar_left) {
158+
// Compare CUDA Sub result against CPU Sub result
159+
cytnx::Tensor tensor_cpu = tensor.to(cytnx::Device.cpu);
160+
cytnx::Tensor expected_cpu;
161+
162+
if (scalar_left) {
163+
expected_cpu = cytnx::linalg::Sub(scalar, tensor_cpu);
164+
} else {
165+
expected_cpu = cytnx::linalg::Sub(tensor_cpu, scalar);
166+
}
167+
168+
cytnx::Tensor gpu_result_cpu = gpu_result.to(cytnx::Device.cpu);
169+
170+
cytnx::cytnx_double tolerance = GetTolerance(gpu_result.dtype());
171+
172+
if (!cytnx::TestTools::AreNearlyEqTensor(gpu_result_cpu, expected_cpu, tolerance)) {
173+
return ::testing::AssertionFailure()
174+
<< "Sub scalar result mismatch: CUDA Sub result differs from CPU Sub result. "
175+
<< "Tensor dtype: " << tensor.dtype() << ", scalar: " << scalar
176+
<< ", scalar_left: " << scalar_left << ", tolerance used: " << tolerance;
177+
}
178+
179+
return ::testing::AssertionSuccess();
180+
}
181+
182+
std::vector<std::vector<cytnx::cytnx_uint64>> GetTestShapes() {
183+
std::vector<std::vector<cytnx::cytnx_uint64>> all_shapes;
184+
185+
auto shapes_1d = cytnx::TestTools::GenerateTestShapes(1, 1, 1024, 4);
186+
auto shapes_2d = cytnx::TestTools::GenerateTestShapes(2, 1, 512, 4);
187+
auto shapes_3d = cytnx::TestTools::GenerateTestShapes(3, 1, 64, 4);
188+
auto shapes_4d = cytnx::TestTools::GenerateTestShapes(4, 1, 32, 4);
189+
190+
all_shapes.insert(all_shapes.end(), shapes_1d.begin(), shapes_1d.end());
191+
all_shapes.insert(all_shapes.end(), shapes_2d.begin(), shapes_2d.end());
192+
all_shapes.insert(all_shapes.end(), shapes_3d.begin(), shapes_3d.end());
193+
all_shapes.insert(all_shapes.end(), shapes_4d.begin(), shapes_4d.end());
194+
195+
return all_shapes;
196+
}
197+
198+
cytnx::cytnx_double GetTolerance(const unsigned int& dtype) {
199+
cytnx::cytnx_double tolerance = 1e-6;
200+
return tolerance;
201+
}
202+
203+
} // namespace SubTest

0 commit comments

Comments
 (0)