Skip to content

Commit 095203d

Browse files
committed
unit: introduce UMTensor tests
Right now, its just a copy of the btas type test case
1 parent cd9eee9 commit 095203d

2 files changed

Lines changed: 249 additions & 1 deletion

File tree

tests/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ set(ta_test_src_files ta_test.cpp
105105
)
106106

107107
if(TILEDARRAY_HAS_CUDA OR TILEDARRAY_HAS_HIP)
108-
list(APPEND ta_test_src_files librett.cpp expressions_device_um.cpp btas_tensor_um.cpp)
108+
list(APPEND ta_test_src_files librett.cpp expressions_device_um.cpp btas_tensor_um.cpp tensor_um.cpp)
109109
endif()
110110

111111
# if using C++20 must use Boost 1.74 or later:

tests/tensor_um.cpp

Lines changed: 248 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,248 @@
1+
/*
2+
* This file is a part of TiledArray.
3+
* Copyright (C) 2025 Virginia Tech
4+
*
5+
* This program is free software: you can redistribute it and/or modify
6+
* it under the terms of the GNU General Public License as published by
7+
* the Free Software Foundation, either version 3 of the License, or
8+
* (at your option) any later version.
9+
*
10+
* This program is distributed in the hope that it will be useful,
11+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
* GNU General Public License for more details.
14+
*
15+
* You should have received a copy of the GNU General Public License
16+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
17+
*
18+
* Ajay Melekamburath
19+
* Department of Chemistry, Virginia Tech
20+
* Aug 02, 2025
21+
*/
22+
23+
#include <TiledArray/device/um_tensor.h>
24+
#include "global_fixture.h"
25+
#include "unit_test_config.h"
26+
27+
using namespace TiledArray;
28+
29+
struct TensorUMFixture {
30+
typedef UMTensor<int> TensorN;
31+
typedef TensorN::value_type value_type;
32+
typedef TensorN::range_type::index index;
33+
typedef TensorN::size_type size_type;
34+
typedef TensorN::range_type::index_view_type* index_view_type;
35+
typedef TensorN::range_type range_type;
36+
37+
const range_type r;
38+
39+
TensorUMFixture() : r(make_range(81)), t(r) {
40+
rand_fill(18, t.size(), t.data());
41+
}
42+
43+
~TensorUMFixture() {}
44+
45+
static range_type make_range(const int seed) {
46+
GlobalFixture::world->srand(seed);
47+
std::array<std::size_t, GlobalFixture::dim> start, finish;
48+
49+
for (unsigned int i = 0ul; i < GlobalFixture::dim; ++i) {
50+
start[i] = GlobalFixture::world->rand() % 10;
51+
finish[i] = GlobalFixture::world->rand() % 8 + start[i] + 2;
52+
}
53+
54+
return range_type(start, finish);
55+
}
56+
57+
static void rand_fill(const int seed, const size_type n, int* const data) {
58+
GlobalFixture::world->srand(seed);
59+
for (size_type i = 0ul; i < n; ++i)
60+
data[i] = GlobalFixture::world->rand() % 42;
61+
}
62+
63+
template <typename T>
64+
static void rand_fill(const int seed, const size_type n,
65+
std::complex<T>* const data) {
66+
GlobalFixture::world->srand(seed);
67+
for (size_type i = 0ul; i < n; ++i)
68+
data[i] = std::complex<T>(GlobalFixture::world->rand() % 42,
69+
GlobalFixture::world->rand() % 42);
70+
}
71+
72+
static TensorN make_tensor(const int range_seed, const int data_seed) {
73+
TensorN tensor(make_range(range_seed));
74+
rand_fill(data_seed, tensor.size(), tensor.data());
75+
return tensor;
76+
}
77+
78+
// // make permutation definition object
79+
// static Permutation make_perm() {
80+
// std::array<unsigned int, GlobalFixture::dim> temp;
81+
// for(std::size_t i = 0; i < temp.size(); ++i)
82+
// temp[i] = i + 1;
83+
//
84+
// temp.back() = 0;
85+
//
86+
// return Permutation(temp.begin(), temp.end());
87+
// }
88+
89+
TensorN t;
90+
};
91+
92+
BOOST_FIXTURE_TEST_SUITE(ta_tensor_um_suite, TensorUMFixture,
93+
TA_UT_LABEL_SERIAL)
94+
95+
BOOST_AUTO_TEST_CASE(default_constructor) {
96+
// check constructor
97+
BOOST_REQUIRE_NO_THROW(TensorN x);
98+
TensorN x;
99+
100+
BOOST_CHECK(x.empty());
101+
102+
// Check that range data is correct
103+
BOOST_CHECK_EQUAL(x.size(), 0ul);
104+
BOOST_CHECK_EQUAL(x.range().volume(), 0ul);
105+
106+
// Check the element data
107+
BOOST_CHECK_EQUAL(x.begin(), x.end());
108+
BOOST_CHECK_EQUAL(const_cast<const TensorN&>(x).begin(),
109+
const_cast<const TensorN&>(x).end());
110+
}
111+
112+
BOOST_AUTO_TEST_CASE(range_constructor) {
113+
BOOST_REQUIRE_NO_THROW(TensorN x(r));
114+
TensorN x(r);
115+
116+
BOOST_CHECK(!x.empty());
117+
118+
// Check that range data is correct
119+
BOOST_CHECK_NE(x.data(), static_cast<int*>(NULL));
120+
BOOST_CHECK_EQUAL(x.size(), r.volume());
121+
BOOST_CHECK_EQUAL(x.range(), r);
122+
BOOST_CHECK_EQUAL(std::distance(x.begin(), x.end()), r.volume());
123+
BOOST_CHECK_EQUAL(std::distance(const_cast<const TensorN&>(x).begin(),
124+
const_cast<const TensorN&>(x).end()),
125+
r.volume());
126+
}
127+
128+
BOOST_AUTO_TEST_CASE(value_constructor) {
129+
BOOST_REQUIRE_NO_THROW(TensorN x(r, 8));
130+
TensorN x(r, 8);
131+
132+
BOOST_CHECK(!x.empty());
133+
134+
// Check that range data is correct
135+
BOOST_CHECK_NE(x.data(), static_cast<int*>(NULL));
136+
BOOST_CHECK_EQUAL(x.size(), r.volume());
137+
BOOST_CHECK_EQUAL(x.range(), r);
138+
BOOST_CHECK_EQUAL(std::distance(x.begin(), x.end()), r.volume());
139+
BOOST_CHECK_EQUAL(std::distance(const_cast<const TensorN&>(x).begin(),
140+
const_cast<const TensorN&>(x).end()),
141+
r.volume());
142+
143+
for (TensorN::const_iterator it = x.begin(); it != x.end(); ++it)
144+
BOOST_CHECK_EQUAL(*it, 8);
145+
}
146+
147+
// BOOST_AUTO_TEST_CASE( copy_constructor ) {
148+
// // check constructor
149+
// BOOST_REQUIRE_NO_THROW(TensorN tc(t));
150+
// TensorN tc(t);
151+
//
152+
// BOOST_CHECK_EQUAL(tc.empty(), t.empty());
153+
//
154+
// // Check that range data is correct
155+
// BOOST_CHECK_EQUAL(tc.data(), t.data());
156+
// BOOST_CHECK_EQUAL(tc.size(), t.size());
157+
// BOOST_CHECK_EQUAL(tc.range(), t.range());
158+
// BOOST_CHECK_EQUAL(tc.begin(), t.begin());
159+
// BOOST_CHECK_EQUAL(tc.end(), t.end());
160+
// BOOST_CHECK_EQUAL(const_cast<const TensorN&>(tc).begin(), const_cast<const
161+
// TensorN&>(t).begin()); BOOST_CHECK_EQUAL(const_cast<const
162+
// TensorN&>(tc).end(), const_cast<const TensorN&>(t).end());
163+
// BOOST_CHECK_EQUAL_COLLECTIONS(tc.begin(), tc.end(), t.begin(), t.end());
164+
//}
165+
166+
BOOST_AUTO_TEST_CASE(range_accessor) {
167+
BOOST_CHECK_EQUAL_COLLECTIONS(
168+
t.range().lobound_data(), t.range().lobound_data() + t.range().rank(),
169+
r.lobound_data(), r.lobound_data() + r.rank()); // check start accessor
170+
BOOST_CHECK_EQUAL_COLLECTIONS(
171+
t.range().upbound_data(), t.range().upbound_data() + t.range().rank(),
172+
r.upbound_data(), r.upbound_data() + r.rank()); // check finish accessor
173+
BOOST_CHECK_EQUAL_COLLECTIONS(
174+
t.range().extent_data(), t.range().extent_data() + t.range().rank(),
175+
r.extent_data(), r.extent_data() + r.rank()); // check size accessor
176+
BOOST_CHECK_EQUAL_COLLECTIONS(
177+
t.range().stride_data(), t.range().stride_data() + t.range().rank(),
178+
r.stride_data(), r.stride_data() + r.rank()); // check weight accessor
179+
BOOST_CHECK_EQUAL(t.range().volume(), r.volume()); // check volume accessor
180+
BOOST_CHECK_EQUAL(t.range(), r); // check range accessof
181+
}
182+
183+
BOOST_AUTO_TEST_CASE(element_access) {
184+
// check operator[] with array coordinate index and ordinal index
185+
for (std::size_t i = 0ul; i < t.size(); ++i) {
186+
BOOST_CHECK_LT(t[i], 42);
187+
BOOST_CHECK_EQUAL(t[r.idx(i)], t[i]);
188+
}
189+
190+
// check access via call operator, if implemented
191+
#if defined(TILEDARRAY_HAS_VARIADIC_TEMPLATES)
192+
#if TEST_DIM == 3u
193+
BOOST_CHECK_EQUAL(t(0, 0, 0), t[0]);
194+
#endif
195+
#endif
196+
}
197+
198+
BOOST_AUTO_TEST_CASE(iteration) {
199+
BOOST_CHECK_EQUAL(t.begin(), const_cast<const TensorN&>(t).begin());
200+
BOOST_CHECK_EQUAL(t.end(), const_cast<const TensorN&>(t).end());
201+
202+
for (TensorN::iterator it = t.begin(); it != t.end(); ++it) {
203+
BOOST_CHECK_LT(*it, 42);
204+
BOOST_CHECK_EQUAL(*it, t[std::distance(t.begin(), it)]);
205+
}
206+
207+
// check iterator assignment
208+
TensorN::iterator it = t.begin();
209+
BOOST_CHECK_NE(t[0], 88);
210+
*it = 88;
211+
BOOST_CHECK_EQUAL(t[0], 88);
212+
213+
// Check that the iterators of an empty tensor are equal
214+
TensorN t2;
215+
BOOST_CHECK_EQUAL(t2.begin(), t2.end());
216+
}
217+
218+
BOOST_AUTO_TEST_CASE(element_assignment) {
219+
// verify preassignment conditions
220+
BOOST_CHECK_NE(t[1], 2);
221+
// check that assignment returns itself.
222+
BOOST_CHECK_EQUAL(t[1] = 2, 2);
223+
// check for correct assignment.
224+
BOOST_CHECK_EQUAL(t[1], 2);
225+
}
226+
227+
BOOST_AUTO_TEST_CASE(serialization) {
228+
std::size_t buf_size = (t.range().volume() * sizeof(int) +
229+
sizeof(size_type) * (r.rank() * 4 + 2)) *
230+
2;
231+
unsigned char* buf = new unsigned char[buf_size];
232+
madness::archive::BufferOutputArchive oar(buf, buf_size);
233+
BOOST_REQUIRE_NO_THROW(oar & t);
234+
std::size_t nbyte = oar.size();
235+
oar.close();
236+
237+
TensorN ts;
238+
madness::archive::BufferInputArchive iar(buf, nbyte);
239+
BOOST_REQUIRE_NO_THROW(iar & ts);
240+
iar.close();
241+
242+
delete[] buf;
243+
244+
BOOST_CHECK_EQUAL(t.range(), ts.range());
245+
BOOST_CHECK_EQUAL_COLLECTIONS(t.begin(), t.end(), ts.begin(), ts.end());
246+
}
247+
248+
BOOST_AUTO_TEST_SUITE_END()

0 commit comments

Comments
 (0)