xref: /aosp_15_r20/external/executorch/runtime/core/exec_aten/testing_util/test/tensor_util_test.cpp (revision 523fa7a60841cd1ecfb9cc4201f1ca8b03ed023a)
1 /*
2  * Copyright (c) Meta Platforms, Inc. and affiliates.
3  * All rights reserved.
4  *
5  * This source code is licensed under the BSD-style license found in the
6  * LICENSE file in the root directory of this source tree.
7  */
8 
9 #include <algorithm>
10 #include <cmath>
11 #include <cstdint>
12 #include <limits>
13 #include <sstream>
14 #include <vector>
15 
16 #include <executorch/runtime/core/exec_aten/exec_aten.h>
17 #include <executorch/runtime/core/exec_aten/testing_util/tensor_factory.h>
18 #include <executorch/runtime/core/exec_aten/testing_util/tensor_util.h>
19 #include <executorch/test/utils/DeathTest.h>
20 
21 #include <gtest/gtest.h>
22 
23 using namespace ::testing;
24 using exec_aten::ScalarType;
25 using exec_aten::Tensor;
26 using exec_aten::TensorImpl;
27 using exec_aten::TensorList;
28 using executorch::runtime::testing::IsCloseTo;
29 using executorch::runtime::testing::IsDataCloseTo;
30 using executorch::runtime::testing::IsDataEqualTo;
31 using executorch::runtime::testing::IsEqualTo;
32 using executorch::runtime::testing::IsListCloseTo;
33 using executorch::runtime::testing::IsListEqualTo;
34 using executorch::runtime::testing::tensor_data_is_close;
35 using executorch::runtime::testing::tensor_lists_are_close;
36 using executorch::runtime::testing::TensorFactory;
37 using executorch::runtime::testing::tensors_are_close;
38 
39 // Exhaustively test all of our comparison functions every time. Also flip the
40 // params around to demonstrate that the underlying checks are commutative.
41 
42 #define EXPECT_TENSORS_CLOSE_AND_EQUAL(t1__, t2__) \
43   EXPECT_TRUE(tensors_are_close((t1__), (t2__)));  \
44   EXPECT_TRUE(tensors_are_close((t2__), (t1__)));  \
45   EXPECT_THAT((t1__), IsCloseTo((t2__)));          \
46   EXPECT_THAT((t2__), IsCloseTo((t1__)));          \
47   EXPECT_TENSOR_CLOSE((t1__), (t2__));             \
48   EXPECT_TENSOR_CLOSE((t2__), (t1__));             \
49   ASSERT_TENSOR_CLOSE((t1__), (t2__));             \
50   ASSERT_TENSOR_CLOSE((t2__), (t1__));             \
51   EXPECT_THAT((t1__), IsEqualTo(t2__));            \
52   EXPECT_THAT((t2__), IsEqualTo(t1__));            \
53   EXPECT_TENSOR_EQ((t1__), (t2__));                \
54   EXPECT_TENSOR_EQ((t2__), (t1__));                \
55   ASSERT_TENSOR_EQ((t1__), (t2__));                \
56   ASSERT_TENSOR_EQ((t2__), (t1__))
57 
58 #define EXPECT_TENSORS_CLOSE_BUT_NOT_EQUAL(t1__, t2__) \
59   EXPECT_TRUE(tensors_are_close((t1__), (t2__)));      \
60   EXPECT_TRUE(tensors_are_close((t2__), (t1__)));      \
61   EXPECT_THAT((t1__), IsCloseTo((t2__)));              \
62   EXPECT_THAT((t2__), IsCloseTo((t1__)));              \
63   EXPECT_TENSOR_CLOSE((t1__), (t2__));                 \
64   EXPECT_TENSOR_CLOSE((t2__), (t1__));                 \
65   ASSERT_TENSOR_CLOSE((t1__), (t2__));                 \
66   ASSERT_TENSOR_CLOSE((t2__), (t1__));                 \
67   EXPECT_THAT((t1__), Not(IsEqualTo(t2__)));           \
68   EXPECT_THAT((t2__), Not(IsEqualTo(t1__)));           \
69   EXPECT_TENSOR_NE((t1__), (t2__));                    \
70   EXPECT_TENSOR_NE((t2__), (t1__));                    \
71   ASSERT_TENSOR_NE((t1__), (t2__));                    \
72   ASSERT_TENSOR_NE((t2__), (t1__))
73 
74 #define EXPECT_TENSORS_NOT_CLOSE_OR_EQUAL(t1__, t2__) \
75   EXPECT_FALSE(tensors_are_close((t1__), (t2__)));    \
76   EXPECT_FALSE(tensors_are_close((t2__), (t1__)));    \
77   EXPECT_THAT((t1__), Not(IsCloseTo((t2__))));        \
78   EXPECT_THAT((t2__), Not(IsCloseTo((t1__))));        \
79   EXPECT_TENSOR_NOT_CLOSE((t1__), (t2__));            \
80   EXPECT_TENSOR_NOT_CLOSE((t2__), (t1__));            \
81   ASSERT_TENSOR_NOT_CLOSE((t1__), (t2__));            \
82   ASSERT_TENSOR_NOT_CLOSE((t2__), (t1__));            \
83   EXPECT_THAT((t1__), Not(IsEqualTo(t2__)));          \
84   EXPECT_THAT((t2__), Not(IsEqualTo(t1__)));          \
85   EXPECT_TENSOR_NE((t1__), (t2__));                   \
86   EXPECT_TENSOR_NE((t2__), (t1__));                   \
87   ASSERT_TENSOR_NE((t1__), (t2__));                   \
88   ASSERT_TENSOR_NE((t2__), (t1__))
89 
90 #define EXPECT_TENSORS_DATA_CLOSE_AND_EQUAL(t1__, t2__) \
91   EXPECT_TRUE(tensor_data_is_close((t1__), (t2__)));    \
92   EXPECT_TRUE(tensor_data_is_close((t2__), (t1__)));    \
93   EXPECT_THAT((t1__), IsDataCloseTo((t2__)));           \
94   EXPECT_THAT((t2__), IsDataCloseTo((t1__)));           \
95   EXPECT_TENSOR_DATA_CLOSE((t1__), (t2__));             \
96   EXPECT_TENSOR_DATA_CLOSE((t2__), (t1__));             \
97   ASSERT_TENSOR_DATA_CLOSE((t1__), (t2__));             \
98   ASSERT_TENSOR_DATA_CLOSE((t2__), (t1__));             \
99   EXPECT_THAT((t1__), IsDataEqualTo(t2__));             \
100   EXPECT_THAT((t2__), IsDataEqualTo(t1__));             \
101   EXPECT_TENSOR_DATA_EQ((t1__), (t2__));                \
102   EXPECT_TENSOR_DATA_EQ((t2__), (t1__));                \
103   ASSERT_TENSOR_DATA_EQ((t1__), (t2__));                \
104   ASSERT_TENSOR_DATA_EQ((t2__), (t1__))
105 
106 #define EXPECT_TENSORS_DATA_CLOSE_BUT_NOT_EQUAL(t1__, t2__) \
107   EXPECT_TRUE(tensor_data_is_close((t1__), (t2__)));        \
108   EXPECT_TRUE(tensor_data_is_close((t2__), (t1__)));        \
109   EXPECT_THAT((t1__), IsDataCloseTo((t2__)));               \
110   EXPECT_THAT((t2__), IsDataCloseTo((t1__)));               \
111   EXPECT_TENSOR_DATA_CLOSE((t1__), (t2__));                 \
112   EXPECT_TENSOR_DATA_CLOSE((t2__), (t1__));                 \
113   ASSERT_TENSOR_DATA_CLOSE((t1__), (t2__));                 \
114   ASSERT_TENSOR_DATA_CLOSE((t2__), (t1__));                 \
115   EXPECT_THAT((t1__), Not(IsDataEqualTo(t2__)));            \
116   EXPECT_THAT((t2__), Not(IsDataEqualTo(t1__)));            \
117   EXPECT_TENSOR_DATA_NE((t1__), (t2__));                    \
118   EXPECT_TENSOR_DATA_NE((t2__), (t1__));                    \
119   ASSERT_TENSOR_DATA_NE((t1__), (t2__));                    \
120   ASSERT_TENSOR_DATA_NE((t2__), (t1__))
121 
122 #define EXPECT_TENSORS_DATA_NOT_CLOSE_OR_EQUAL(t1__, t2__) \
123   EXPECT_FALSE(tensor_data_is_close((t1__), (t2__)));      \
124   EXPECT_FALSE(tensor_data_is_close((t2__), (t1__)));      \
125   EXPECT_THAT((t1__), Not(IsDataCloseTo((t2__))));         \
126   EXPECT_THAT((t2__), Not(IsDataCloseTo((t1__))));         \
127   EXPECT_TENSOR_DATA_NOT_CLOSE((t1__), (t2__));            \
128   EXPECT_TENSOR_DATA_NOT_CLOSE((t2__), (t1__));            \
129   ASSERT_TENSOR_NOT_CLOSE((t1__), (t2__));                 \
130   ASSERT_TENSOR_NOT_CLOSE((t2__), (t1__));                 \
131   EXPECT_THAT((t1__), Not(IsDataEqualTo(t2__)));           \
132   EXPECT_THAT((t2__), Not(IsDataEqualTo(t1__)));           \
133   EXPECT_TENSOR_DATA_NE((t1__), (t2__));                   \
134   EXPECT_TENSOR_DATA_NE((t2__), (t1__));                   \
135   ASSERT_TENSOR_DATA_NE((t1__), (t2__));                   \
136   ASSERT_TENSOR_DATA_NE((t2__), (t1__))
137 
138 #define EXPECT_TENSOR_LISTS_CLOSE_AND_EQUAL(list1__, list2__) \
139   EXPECT_TRUE(tensor_lists_are_close(                         \
140       (list1__).data(),                                       \
141       (list1__).size(),                                       \
142       (list2__).data(),                                       \
143       (list2__).size()));                                     \
144   EXPECT_TRUE(tensor_lists_are_close(                         \
145       (list2__).data(),                                       \
146       (list2__).size(),                                       \
147       (list1__).data(),                                       \
148       (list1__).size()));                                     \
149   EXPECT_THAT((list1__), IsListCloseTo((list2__)));           \
150   EXPECT_THAT((list2__), IsListCloseTo((list1__)));           \
151   EXPECT_TENSOR_LISTS_CLOSE((list1__), (list2__));            \
152   EXPECT_TENSOR_LISTS_CLOSE((list2__), (list1__));            \
153   ASSERT_TENSOR_LISTS_CLOSE((list1__), (list2__));            \
154   ASSERT_TENSOR_LISTS_CLOSE((list2__), (list1__));            \
155   EXPECT_THAT((list1__), IsListEqualTo(list2__));             \
156   EXPECT_THAT((list2__), IsListEqualTo(list1__));             \
157   EXPECT_TENSOR_LISTS_EQ((list1__), (list2__));               \
158   EXPECT_TENSOR_LISTS_EQ((list2__), (list1__));               \
159   ASSERT_TENSOR_LISTS_EQ((list1__), (list2__));               \
160   ASSERT_TENSOR_LISTS_EQ((list2__), (list1__))
161 
162 #define EXPECT_TENSOR_LISTS_CLOSE_BUT_NOT_EQUAL(list1__, list2__) \
163   EXPECT_TRUE(tensor_lists_are_close(                             \
164       (list1__).data(),                                           \
165       (list1__).size(),                                           \
166       (list2__).data(),                                           \
167       (list2__).size()));                                         \
168   EXPECT_TRUE(tensor_lists_are_close(                             \
169       (list2__).data(),                                           \
170       (list2__).size(),                                           \
171       (list1__).data(),                                           \
172       (list1__).size()));                                         \
173   EXPECT_THAT((list1__), IsListCloseTo((list2__)));               \
174   EXPECT_THAT((list2__), IsListCloseTo((list1__)));               \
175   EXPECT_TENSOR_LISTS_CLOSE((list1__), (list2__));                \
176   EXPECT_TENSOR_LISTS_CLOSE((list2__), (list1__));                \
177   ASSERT_TENSOR_LISTS_CLOSE((list1__), (list2__));                \
178   ASSERT_TENSOR_LISTS_CLOSE((list2__), (list1__));                \
179   EXPECT_THAT((list1__), Not(IsListEqualTo(list2__)));            \
180   EXPECT_THAT((list2__), Not(IsListEqualTo(list1__)));            \
181   EXPECT_TENSOR_LISTS_NE((list1__), (list2__));                   \
182   EXPECT_TENSOR_LISTS_NE((list2__), (list1__));                   \
183   ASSERT_TENSOR_LISTS_NE((list1__), (list2__));                   \
184   ASSERT_TENSOR_LISTS_NE((list2__), (list1__))
185 
186 #define EXPECT_TENSOR_LISTS_NOT_CLOSE_OR_EQUAL(list1__, list2__) \
187   EXPECT_FALSE(tensor_lists_are_close(                           \
188       (list1__).data(),                                          \
189       (list1__).size(),                                          \
190       (list2__).data(),                                          \
191       (list2__).size()));                                        \
192   EXPECT_FALSE(tensor_lists_are_close(                           \
193       (list2__).data(),                                          \
194       (list2__).size(),                                          \
195       (list1__).data(),                                          \
196       (list1__).size()));                                        \
197   EXPECT_THAT((list1__), Not(IsListCloseTo((list2__))));         \
198   EXPECT_THAT((list2__), Not(IsListCloseTo((list1__))));         \
199   EXPECT_TENSOR_LISTS_NOT_CLOSE((list1__), (list2__));           \
200   EXPECT_TENSOR_LISTS_NOT_CLOSE((list2__), (list1__));           \
201   ASSERT_TENSOR_LISTS_NOT_CLOSE((list1__), (list2__));           \
202   ASSERT_TENSOR_LISTS_NOT_CLOSE((list2__), (list1__));           \
203   EXPECT_THAT((list1__), Not(IsListEqualTo(list2__)));           \
204   EXPECT_THAT((list2__), Not(IsListEqualTo(list1__)));           \
205   EXPECT_TENSOR_LISTS_NE((list1__), (list2__));                  \
206   EXPECT_TENSOR_LISTS_NE((list2__), (list1__));                  \
207   ASSERT_TENSOR_LISTS_NE((list1__), (list2__));                  \
208   ASSERT_TENSOR_LISTS_NE((list2__), (list1__))
209 
210 namespace {
211 // calculate numel given size
size_to_numel(std::vector<int32_t> sizes)212 int32_t size_to_numel(std::vector<int32_t> sizes) {
213   int32_t numel = 1;
214   for (auto size : sizes) {
215     numel *= size;
216   }
217   return numel;
218 }
219 
220 } // namespace
221 
222 // Mismatched shapes/types/strides.
223 
TEST(TensorUtilTest,DifferentDtypesAreNotCloseOrEqual)224 TEST(TensorUtilTest, DifferentDtypesAreNotCloseOrEqual) {
225   // Create two tensors with identical shape and data, but different dtypes.
226   TensorFactory<ScalarType::Int> tf_int;
227   Tensor a = tf_int.make(/*sizes=*/{2, 2}, /*data=*/{1, 2, 4, 8});
228 
229   TensorFactory<ScalarType::Long> tf_long;
230   Tensor b = tf_long.make(/*sizes=*/{2, 2}, /*data=*/{1, 2, 4, 8});
231 
232   EXPECT_TENSORS_NOT_CLOSE_OR_EQUAL(a, b);
233 }
234 
TEST(TensorUtilTest,DifferentSizesAreNotCloseOrEqual)235 TEST(TensorUtilTest, DifferentSizesAreNotCloseOrEqual) {
236   TensorFactory<ScalarType::Int> tf;
237 
238   // Create two tensors with identical dtype and data, but different shapes.
239   Tensor a = tf.make(/*sizes=*/{2, 2}, /*data=*/{1, 2, 4, 8});
240   Tensor b = tf.make(/*sizes=*/{4}, /*data=*/{1, 2, 4, 8});
241 
242   EXPECT_TENSORS_NOT_CLOSE_OR_EQUAL(a, b);
243 }
244 
TEST(TensorUtilTest,DifferentLayoutsDies)245 TEST(TensorUtilTest, DifferentLayoutsDies) {
246   TensorFactory<ScalarType::Int> tf;
247 
248   // Create two tensors with identical dtype, data and shapes, but different
249   // strides.
250   Tensor a = tf.make(
251       /*sizes=*/{2, 2}, /*data=*/{1, 2, 4, 8}, /*strided=*/{1, 2});
252   Tensor b = tf.make(
253       /*sizes=*/{2, 2}, /*data=*/{1, 2, 4, 8}, /*strided=*/{2, 1});
254 
255   // Current `tensors_are_close` does not support comparing two tensors with
256   // different stride.
257   // TODO(T132992348): support comparison between tensors of different strides
258   ET_EXPECT_DEATH(EXPECT_TENSORS_NOT_CLOSE_OR_EQUAL(a, b), "");
259   ET_EXPECT_DEATH(EXPECT_TENSORS_CLOSE_AND_EQUAL(a, b), "");
260 }
261 
262 // Int tensors, as a proxy for all non-floating-point types.
263 
TEST(TensorUtilTest,IntTensorIsCloseAndEqualToItself)264 TEST(TensorUtilTest, IntTensorIsCloseAndEqualToItself) {
265   TensorFactory<ScalarType::Int> tf;
266 
267   Tensor t = tf.make(/*sizes=*/{2, 2}, /*data=*/{1, 2, 4, 8});
268 
269   EXPECT_TENSORS_CLOSE_AND_EQUAL(t, t);
270 }
271 
TEST(TensorUtilTest,IdenticalIntTensorsAreCloseAndEqual)272 TEST(TensorUtilTest, IdenticalIntTensorsAreCloseAndEqual) {
273   TensorFactory<ScalarType::Int> tf;
274 
275   // Create two tensors with identical shape, dtype, and data.
276   Tensor a = tf.make(/*sizes=*/{2, 2}, /*data=*/{1, 2, 4, 8});
277   Tensor b = tf.make(/*sizes=*/{2, 2}, /*data=*/{1, 2, 4, 8});
278 
279   EXPECT_TENSORS_CLOSE_AND_EQUAL(a, b);
280 }
281 
TEST(TensorUtilTest,NonIdenticalIntTensorsAreNotCloseOrEqual)282 TEST(TensorUtilTest, NonIdenticalIntTensorsAreNotCloseOrEqual) {
283   TensorFactory<ScalarType::Int> tf;
284 
285   // Create two tensors with identical shape and dtype, but different data.
286   Tensor a = tf.make(/*sizes=*/{2, 2}, /*data=*/{1, 2, 4, 8});
287   Tensor b = tf.make(/*sizes=*/{2, 2}, /*data=*/{99, 2, 4, 8});
288 
289   EXPECT_TENSORS_NOT_CLOSE_OR_EQUAL(a, b);
290 }
291 
TEST(TensorUtilTest,EmptyTensorsAreCloseAndEqual)292 TEST(TensorUtilTest, EmptyTensorsAreCloseAndEqual) {
293   TensorFactory<ScalarType::Int> tf;
294 
295   // Create two tensors with identical shapes but no data.
296   Tensor a = tf.make(/*sizes=*/{0, 2}, /*data=*/{});
297   EXPECT_EQ(a.numel(), 0);
298   EXPECT_EQ(a.nbytes(), 0);
299   Tensor b = tf.make(/*sizes=*/{0, 2}, /*data=*/{});
300   EXPECT_EQ(b.numel(), 0);
301   EXPECT_EQ(b.nbytes(), 0);
302 
303   EXPECT_TENSORS_CLOSE_AND_EQUAL(a, b);
304 }
305 
306 // Float tensors, as a proxy for all floating-point types.
307 
TEST(TensorUtilTest,FloatTensorIsCloseAndEqualToItself)308 TEST(TensorUtilTest, FloatTensorIsCloseAndEqualToItself) {
309   TensorFactory<ScalarType::Float> tf;
310 
311   Tensor t = tf.make(/*sizes=*/{2, 2}, /*data=*/{1.1, 2.2, 4.4, 8.8});
312 
313   EXPECT_TENSORS_CLOSE_AND_EQUAL(t, t);
314 }
315 
TEST(TensorUtilTest,IdenticalFloatTensorsAreCloseAndEqual)316 TEST(TensorUtilTest, IdenticalFloatTensorsAreCloseAndEqual) {
317   TensorFactory<ScalarType::Float> tf;
318 
319   // Create two tensors with identical shape, dtype, and data.
320   Tensor a = tf.make(/*sizes=*/{2, 2}, /*data=*/{1.1, 2.2, 4.4, 8.8});
321   Tensor b = tf.make(/*sizes=*/{2, 2}, /*data=*/{1.1, 2.2, 4.4, 8.8});
322 
323   EXPECT_TENSORS_CLOSE_AND_EQUAL(a, b);
324 }
325 
TEST(TensorUtilTest,NearlyIdenticalFloatTensorsAreCloseButNotEqual)326 TEST(TensorUtilTest, NearlyIdenticalFloatTensorsAreCloseButNotEqual) {
327   TensorFactory<ScalarType::Float> tf;
328 
329   // Create two tensors with identical shape and dtype, but slightly different
330   // data.
331   Tensor a = tf.make(/*sizes=*/{2, 2}, /*data=*/{1.1, 2.2, 4.4, 8.8});
332   Tensor b = tf.make(
333       /*sizes=*/{2, 2},
334       {// First data element is slightly larger.
335        std::nextafter(1.1f, 100.0f),
336        // Remaining data elements are the same.
337        2.2,
338        4.4,
339        8.8});
340 
341   EXPECT_TENSORS_CLOSE_BUT_NOT_EQUAL(a, b);
342 }
343 
TEST(TensorUtilTest,NonIdenticalFloatTensorsAreNotCloseOrEqual)344 TEST(TensorUtilTest, NonIdenticalFloatTensorsAreNotCloseOrEqual) {
345   TensorFactory<ScalarType::Float> tf;
346 
347   // Create two tensors with identical shape and dtype, but different data.
348   Tensor a = tf.make(/*sizes=*/{2, 2}, /*data=*/{1.1, 2.2, 4.4, 8.8});
349   Tensor b = tf.make(/*sizes=*/{2, 2}, /*data=*/{99.99, 2.2, 4.4, 8.8});
350 
351   EXPECT_TENSORS_NOT_CLOSE_OR_EQUAL(a, b);
352 }
353 
TEST(TensorUtilTest,FloatNanElementsAreCloseAndEqual)354 TEST(TensorUtilTest, FloatNanElementsAreCloseAndEqual) {
355   TensorFactory<ScalarType::Float> tf;
356 
357   // Two identical tensors with NaN elements.
358   Tensor a = tf.make(/*sizes=*/{2, 2}, /*data=*/{1.1, NAN, 2.2, NAN});
359   Tensor b = tf.make(/*sizes=*/{2, 2}, /*data=*/{1.1, NAN, 2.2, NAN});
360 
361   EXPECT_TENSORS_CLOSE_AND_EQUAL(a, b);
362 }
363 
TEST(TensorUtilTest,FloatNanElementsAreNotEqualToNonNan)364 TEST(TensorUtilTest, FloatNanElementsAreNotEqualToNonNan) {
365   TensorFactory<ScalarType::Float> tf;
366 
367   // Regression test ensuring that NaN elements are not compared equal to
368   // non-NaN finite values.
369   Tensor a = tf.make(/*sizes=*/{2, 2}, /*data=*/{1.1, NAN, 2.2, NAN});
370   Tensor b = tf.make(/*sizes=*/{2, 2}, /*data=*/{1.1, 0.0, 2.2, 0.0});
371 
372   EXPECT_TENSORS_NOT_CLOSE_OR_EQUAL(a, b);
373 }
374 
TEST(TensorUtilTest,FloatInfiniteElementsAreCloseAndEqual)375 TEST(TensorUtilTest, FloatInfiniteElementsAreCloseAndEqual) {
376   constexpr auto kInfinity = std::numeric_limits<float>::infinity();
377 
378   TensorFactory<ScalarType::Float> tf;
379 
380   // Two identical tensors with infinite elements.
381   Tensor a =
382       tf.make(/*sizes=*/{2, 2}, /*data=*/{-kInfinity, 1.1, 2.2, kInfinity});
383   Tensor b =
384       tf.make(/*sizes=*/{2, 2}, /*data=*/{-kInfinity, 1.1, 2.2, kInfinity});
385 
386   EXPECT_TENSORS_CLOSE_AND_EQUAL(a, b);
387 }
388 
389 // Double: less test coverage since Float covers all of the branches, but
390 // demonstrate that it works.
391 
TEST(TensorUtilTest,NearlyIdenticalDoubleTensorsAreCloseButNotEqual)392 TEST(TensorUtilTest, NearlyIdenticalDoubleTensorsAreCloseButNotEqual) {
393   TensorFactory<ScalarType::Float> tf;
394 
395   // Create two tensors with identical shape and dtype, but slightly different
396   // data.
397   Tensor a = tf.make(/*sizes=*/{2, 2}, /*data=*/{1.1, 2.2, 4.4, 8.8});
398   Tensor b = tf.make(
399       /*sizes=*/{2, 2},
400       {// First data element is slightly larger.
401        std::nextafter(1.1f, 100.0f),
402        // Remaining data elements are the same.
403        2.2,
404        4.4,
405        8.8});
406 
407   EXPECT_TENSORS_CLOSE_BUT_NOT_EQUAL(a, b);
408 }
409 
TEST(TensorUtilTest,DoubleAndInfinitNanElementsAreCloseAndEqual)410 TEST(TensorUtilTest, DoubleAndInfinitNanElementsAreCloseAndEqual) {
411   constexpr auto kInfinity = std::numeric_limits<double>::infinity();
412 
413   TensorFactory<ScalarType::Double> tf;
414 
415   // Two identical tensors with NaN and infinite elements.
416   Tensor a =
417       tf.make(/*sizes=*/{2, 2}, /*data=*/{-kInfinity, NAN, 1.1, kInfinity});
418   Tensor b =
419       tf.make(/*sizes=*/{2, 2}, /*data=*/{-kInfinity, NAN, 1.1, kInfinity});
420 
421   EXPECT_TENSORS_CLOSE_AND_EQUAL(a, b);
422 }
423 
424 // Testing closeness with tolerances
425 
TEST(TensorUtilTest,TensorsAreCloseWithTol)426 TEST(TensorUtilTest, TensorsAreCloseWithTol) {
427   TensorFactory<ScalarType::Float> tf;
428   TensorFactory<ScalarType::Double> td;
429 
430   // Create two tensors with identical shape and dtype, but different data.
431   Tensor af = tf.make(/*sizes=*/{2, 2}, /*data=*/{1.0, 2.099999, 0.0, -0.05});
432   Tensor bf = tf.make(/*sizes=*/{2, 2}, /*data=*/{1.099999, 2.0, 0.05, 0.0});
433 
434   EXPECT_TENSOR_CLOSE_WITH_TOL(af, bf, 0.0, 0.1);
435 
436   // Create two tensors with identical shape and dtype, but different data.
437   Tensor ad = td.make(/*sizes=*/{2, 2}, /*data=*/{1.099, 2.199, NAN, -9.0});
438   Tensor bd = td.make(/*sizes=*/{2, 2}, /*data=*/{1.0, 2.0, NAN, -10.0});
439 
440   EXPECT_TENSOR_CLOSE_WITH_TOL(ad, bd, 0.1, 0.0);
441 }
442 
TEST(TensorUtilTest,TensorsAreNotCloseWithTol)443 TEST(TensorUtilTest, TensorsAreNotCloseWithTol) {
444   TensorFactory<ScalarType::Float> tf;
445   TensorFactory<ScalarType::Double> td;
446 
447   // Create two tensors with identical shape and dtype, but different data.
448   Tensor af = tf.make(/*sizes=*/{3}, /*data=*/{1.00, NAN, -10.0});
449   Tensor bf = tf.make(/*sizes=*/{3}, /*data=*/{1.11, NAN, -10.0});
450 
451   EXPECT_TENSOR_NOT_CLOSE_WITH_TOL(af, bf, 0.0, 0.1);
452 
453   // Create two tensors with identical shape and dtype, but different data.
454   Tensor ad = td.make(/*sizes=*/{3}, /*data=*/{1.0, 0.0, -10.0});
455   Tensor bd = td.make(/*sizes=*/{3}, /*data=*/{1.0, 0.0, -9.0});
456 
457   EXPECT_TENSOR_NOT_CLOSE_WITH_TOL(ad, bd, 0.1, 0.0);
458 
459   // Create two tensors with identical shape and dtype, but different data.
460   ad = tf.make(/*sizes=*/{3}, /*data=*/{1.0, 2.0, 0.00001});
461   bd = tf.make(/*sizes=*/{3}, /*data=*/{1.0, 2.0, 0.0});
462 
463   EXPECT_TENSOR_NOT_CLOSE_WITH_TOL(ad, bd, 0.1, 0.0);
464 }
465 
466 //
467 // Tests for shape-agnostic data equality.
468 //
469 
470 // Common testing for EXPECT_TENSOR_DATA_EQ in different input sizes and
471 // dtypes.
472 template <ScalarType DTYPE>
test_data_equal(std::vector<int32_t> t1_sizes,std::vector<int32_t> t2_sizes)473 void test_data_equal(
474     std::vector<int32_t> t1_sizes,
475     std::vector<int32_t> t2_sizes) {
476   TensorFactory<DTYPE> tf;
477 
478   // get corresponding ctype for input DTYPEs
479   using ctype = typename TensorFactory<DTYPE>::ctype;
480 
481   // Get the size of data of t1 and t2.
482   // Make sure the two sizes are equal.
483   auto numel = size_to_numel(t1_sizes);
484   ASSERT_EQ(numel, size_to_numel(t2_sizes));
485 
486   // Set up data vector for t1 and t2.
487   // Set them as a same random vector to test them generally.
488   std::vector<ctype> t1_data(numel);
489   std::generate(t1_data.begin(), t1_data.end(), std::rand);
490   std::vector<ctype> t2_data(numel);
491   t2_data = t1_data;
492 
493   Tensor t1 = tf.make(t1_sizes, t1_data);
494   Tensor t2 = tf.make(t2_sizes, t2_data);
495 
496   EXPECT_TENSORS_DATA_CLOSE_AND_EQUAL(t1, t2);
497 }
498 
TEST(TensorUtilTest,TensorDataEqualSizeEqual)499 TEST(TensorUtilTest, TensorDataEqualSizeEqual) {
500 #define TEST_ENTRY(ctype, dtype) \
501   test_data_equal<ScalarType::dtype>({3, 4, 5}, {3, 4, 5});
502   ET_FORALL_REAL_TYPES_AND(Bool, TEST_ENTRY);
503 #undef TEST_ENTRY
504 }
505 
TEST(TensorUtilTest,TensorDataEqualSizeUnequal)506 TEST(TensorUtilTest, TensorDataEqualSizeUnequal) {
507 #define TEST_ENTRY(ctype, dtype) \
508   test_data_equal<ScalarType::dtype>({3, 4, 5}, {3, 5, 4});
509   ET_FORALL_REAL_TYPES_AND(Bool, TEST_ENTRY);
510 #undef TEST_ENTRY
511 }
512 
TEST(TensorUtilTest,EmptyTensorsSupported)513 TEST(TensorUtilTest, EmptyTensorsSupported) {
514 #define TEST_ENTRY(ctype, dtype) \
515   test_data_equal<ScalarType::dtype>({3, 4, 0, 5}, {3, 4, 0, 5});
516   ET_FORALL_REAL_TYPES_AND(Bool, TEST_ENTRY);
517 #undef TEST_ENTRY
518 }
519 
TEST(TensorUtilTest,ZeroDimTensorsSupported)520 TEST(TensorUtilTest, ZeroDimTensorsSupported) {
521 #define TEST_ENTRY(ctype, dtype) test_data_equal<ScalarType::dtype>({}, {});
522   ET_FORALL_REAL_TYPES_AND(Bool, TEST_ENTRY);
523 #undef TEST_ENTRY
524 }
525 
526 // Common testing for EXPECT_TENSOR_DATA_CLOSE in different input sizes and
527 // dtypes.
528 template <
529     ScalarType DTYPE,
530     std::enable_if_t<
531         DTYPE == ScalarType::Float || DTYPE == ScalarType::Double,
532         bool> = true>
test_data_close_but_not_equal(std::vector<int32_t> t1_sizes,std::vector<int32_t> t2_sizes)533 void test_data_close_but_not_equal(
534     std::vector<int32_t> t1_sizes,
535     std::vector<int32_t> t2_sizes) {
536   TensorFactory<DTYPE> tf;
537 
538   // get corresponding ctype for input DTYPEs
539   using ctype = typename TensorFactory<DTYPE>::ctype;
540 
541   // get the size of data of t1 and t2
542   // make sure the two sizes are equal
543   auto numel = size_to_numel(t1_sizes);
544   ASSERT_EQ(numel, size_to_numel(t2_sizes));
545 
546   // set up data vector for t1 and t2
547   // set them as a almost same random vector (only the first element are
548   // different if the first element exists) to test them generally
549   std::vector<ctype> t1_data(numel);
550   std::generate(t1_data.begin(), t1_data.end(), std::rand);
551   std::vector<ctype> t2_data(numel);
552   t2_data = t1_data;
553 
554   // Set the first element of t2 slightly larger than 0
555   // the "first element" only work if t2_numel > 0
556   // The checking with ctype.max() is to prevent overflow
557   if (numel > 0) {
558     if (t2_data[0] < std::numeric_limits<ctype>::max() - 100) {
559       t2_data[0] = std::nextafter(t2_data[0], t2_data[0] + 100.0f);
560     } else {
561       t2_data[0] = std::nextafter(t2_data[0], t2_data[0] - 100.f);
562     }
563   }
564 
565   Tensor t1 = tf.make(t1_sizes, t1_data);
566   Tensor t2 = tf.make(t2_sizes, t2_data);
567 
568   EXPECT_TENSORS_DATA_CLOSE_AND_EQUAL(t1, t2);
569 }
570 
TEST(TensorUtilTest,TensorDataCloseNotEqualSizeEqual)571 TEST(TensorUtilTest, TensorDataCloseNotEqualSizeEqual) {
572 #define TEST_ENTRY(ctype, dtype) \
573   test_data_equal<ScalarType::dtype>({3, 4, 5}, {3, 4, 5});
574   ET_FORALL_FLOAT_TYPES(TEST_ENTRY);
575 #undef TEST_ENTRY
576 }
577 
TEST(TensorUtilTest,TensorDataCloseNotEqualSizeUnequal)578 TEST(TensorUtilTest, TensorDataCloseNotEqualSizeUnequal) {
579 #define TEST_ENTRY(ctype, dtype) \
580   test_data_equal<ScalarType::dtype>({3, 4, 5}, {3, 5, 4});
581   ET_FORALL_FLOAT_TYPES(TEST_ENTRY);
582 #undef TEST_ENTRY
583 }
584 
585 // Common testing for EXPECT_TENSOR_DATA_EQ in different input sizes and
586 // dtypes.
587 template <ScalarType DTYPE_T1, ScalarType DTYPE_T2>
test_data_equal_but_size_or_dtype_mismatch(std::vector<int32_t> t1_sizes,std::vector<int32_t> t2_sizes)588 void test_data_equal_but_size_or_dtype_mismatch(
589     std::vector<int32_t> t1_sizes,
590     std::vector<int32_t> t2_sizes) {
591   TensorFactory<DTYPE_T1> tf_t1;
592   TensorFactory<DTYPE_T2> tf_t2;
593 
594   Tensor t1 = tf_t1.zeros(t1_sizes);
595   Tensor t2 = tf_t2.zeros(t2_sizes);
596 
597   EXPECT_TENSORS_DATA_NOT_CLOSE_OR_EQUAL(t1, t2);
598 }
599 
TEST(TensorUtilTest,TensorDataTypeMismatched)600 TEST(TensorUtilTest, TensorDataTypeMismatched) {
601   std::vector<int32_t> sizes = {3, 4, 5, 6};
602   test_data_equal_but_size_or_dtype_mismatch<
603       ScalarType::Float,
604       ScalarType::Double>(sizes, sizes);
605   test_data_equal_but_size_or_dtype_mismatch<
606       ScalarType::Int,
607       ScalarType::Double>(sizes, sizes);
608 }
609 
TEST(TensorUtilTest,TensorSizeMismatched)610 TEST(TensorUtilTest, TensorSizeMismatched) {
611   std::vector<int32_t> sizes_t1 = {3, 4, 5, 6};
612   std::vector<int32_t> sizes_t2 = {3, 4, 5, 7};
613   test_data_equal_but_size_or_dtype_mismatch<
614       ScalarType::Float,
615       ScalarType::Float>(sizes_t1, sizes_t2);
616 }
617 
TEST(TensorUtilTest,TensorDataMismatched)618 TEST(TensorUtilTest, TensorDataMismatched) {
619   TensorFactory<ScalarType::Int> tf;
620   Tensor t1 = tf.make(/*size=*/{3, 2}, /*data=*/{1, 2, 3, 4, 5, 6});
621   Tensor t2 = tf.make(/*size=*/{3, 2}, /*data=*/{1, 2, 3, 1, 5, 6});
622   Tensor t3 = tf.make(/*size=*/{2, 3}, /*data=*/{1, 2, 3, 1, 5, 6});
623   EXPECT_TENSORS_DATA_NOT_CLOSE_OR_EQUAL(t1, t2);
624   EXPECT_TENSORS_DATA_NOT_CLOSE_OR_EQUAL(t1, t3);
625 
626   Tensor t_zero_dim = tf.make(/*size=*/{}, /*data=*/{0});
627   Tensor t_empty = tf.make(/*size=*/{0}, /*data=*/{});
628   EXPECT_TENSORS_DATA_NOT_CLOSE_OR_EQUAL(t_zero_dim, t_empty);
629 }
630 
631 // Testing data closeness with tolerances
632 
TEST(TensorUtilTest,TensorDataCloseWithTol)633 TEST(TensorUtilTest, TensorDataCloseWithTol) {
634   TensorFactory<ScalarType::Float> tf;
635   TensorFactory<ScalarType::Double> td;
636 
637   // Create two tensors with identical shape and dtype, but different data.
638   Tensor af = tf.make(/*sizes=*/{4, 1}, /*data=*/{1.0, 2.099, 0.0, -0.05});
639   Tensor bf = tf.make(/*sizes=*/{2, 2}, /*data=*/{1.099, 2.0, 0.05, 0.0});
640 
641   EXPECT_TENSOR_DATA_CLOSE_WITH_TOL(af, bf, 0.0, 0.1);
642 
643   // Create two tensors with identical shape and dtype, but different data.
644   Tensor ad = td.make(/*sizes=*/{2, 2}, /*data=*/{1.099, 2.199, NAN, -9.0});
645   Tensor bd = td.make(/*sizes=*/{4}, /*data=*/{1.0, 2.0, NAN, -10.0});
646 
647   EXPECT_TENSOR_DATA_CLOSE_WITH_TOL(ad, bd, 0.1, 0.0);
648 }
649 
TEST(TensorUtilTest,TensorDataNotCloseWithTol)650 TEST(TensorUtilTest, TensorDataNotCloseWithTol) {
651   TensorFactory<ScalarType::Float> tf;
652   TensorFactory<ScalarType::Double> td;
653 
654   // Create two tensors with identical shape and dtype, but different data.
655   Tensor af = tf.make(/*sizes=*/{3}, /*data=*/{1.00, 0.0, -10.0});
656   Tensor bf = tf.make(/*sizes=*/{3, 1}, /*data=*/{1.11, 0.0, -10.0});
657 
658   EXPECT_TENSOR_DATA_NOT_CLOSE_WITH_TOL(af, bf, 0.0, 0.1);
659 
660   // Create two tensors with identical shape and dtype, but different data.
661   Tensor ad = td.make(/*sizes=*/{2, 2}, /*data=*/{1.0, 0.0, -10.0, 0.0});
662   Tensor bd = td.make(/*sizes=*/{4}, /*data=*/{1.0, 0.0, -9.0, 0.0});
663 
664   EXPECT_TENSOR_DATA_NOT_CLOSE_WITH_TOL(ad, bd, 0.1, 0.0);
665 
666   // Create two tensors with identical shape and dtype, but different data.
667   ad = tf.make(/*sizes=*/{1, 4}, /*data=*/{1.0, 2.0, NAN, 0.00001});
668   bd = tf.make(/*sizes=*/{2, 2}, /*data=*/{1.0, 2.0, NAN, 0.0});
669 
670   EXPECT_TENSOR_DATA_NOT_CLOSE_WITH_TOL(ad, bd, 0.1, 0.0);
671 }
672 
673 //
674 // Tests for TensorList helpers.
675 //
676 
TEST(TensorUtilTest,TensorListsCloseAndEqual)677 TEST(TensorUtilTest, TensorListsCloseAndEqual) {
678   TensorFactory<ScalarType::Int> tf_int;
679   TensorFactory<ScalarType::Float> tf_float;
680 
681   // Two lists of tensors that should be close and equal. Elements have
682   // different shapes and dtypes.
683   std::vector<Tensor> vec1 = {
684       tf_int.zeros(/*sizes=*/{1, 2}),
685       tf_float.ones(/*sizes=*/{2, 1}),
686   };
687   TensorList list1(vec1.data(), vec1.size());
688   std::vector<Tensor> vec2 = {
689       tf_int.zeros(/*sizes=*/{1, 2}),
690       tf_float.ones(/*sizes=*/{2, 1}),
691   };
692   TensorList list2(vec2.data(), vec2.size());
693 
694   // Show that we can compare a mix of vectors and TensorLists.
695   EXPECT_TENSOR_LISTS_CLOSE_AND_EQUAL(list1, list2);
696   EXPECT_TENSOR_LISTS_CLOSE_AND_EQUAL(vec1, list2);
697   EXPECT_TENSOR_LISTS_CLOSE_AND_EQUAL(list1, vec2);
698   EXPECT_TENSOR_LISTS_CLOSE_AND_EQUAL(vec1, vec2);
699 }
700 
TEST(TensorUtilTest,EmptyTensorListsAreCloseAndEqual)701 TEST(TensorUtilTest, EmptyTensorListsAreCloseAndEqual) {
702   // Two empty lists.
703   TensorList list1;
704   EXPECT_EQ(list1.size(), 0);
705   TensorList list2;
706   EXPECT_EQ(list2.size(), 0);
707 
708   EXPECT_TENSOR_LISTS_CLOSE_AND_EQUAL(list1, list2);
709 }
710 
TEST(TensorUtilTest,TensorListsCloseButNotEqual)711 TEST(TensorUtilTest, TensorListsCloseButNotEqual) {
712   TensorFactory<ScalarType::Int> tf_int;
713   TensorFactory<ScalarType::Float> tf_float;
714 
715   // Two lists of tensors that should be close and equal. Elements have
716   // different shapes and dtypes.
717   std::vector<Tensor> vec1 = {
718       tf_int.zeros(/*sizes=*/{1, 2}),
719       tf_float.ones(/*sizes=*/{2, 1}),
720   };
721   TensorList list1(vec1.data(), vec1.size());
722   std::vector<Tensor> vec2 = {
723       tf_int.zeros(/*sizes=*/{1, 2}),
724       tf_float.ones(/*sizes=*/{2, 1}),
725   };
726   TensorList list2(vec2.data(), vec2.size());
727 
728   // Tweak a float value slightly.
729   vec1[1].mutable_data_ptr<float>()[0] = std::nextafter(1.0f, 100.0f);
730 
731   // Show that we can compare a mix of vectors and TensorLists.
732   EXPECT_TENSOR_LISTS_CLOSE_BUT_NOT_EQUAL(list1, list2);
733 }
734 
TEST(TensorUtilTest,TensorListsWithDifferentDataAreNotCloseOrEqual)735 TEST(TensorUtilTest, TensorListsWithDifferentDataAreNotCloseOrEqual) {
736   TensorFactory<ScalarType::Int> tf_int;
737   TensorFactory<ScalarType::Float> tf_float;
738 
739   std::vector<Tensor> vec1 = {
740       tf_int.zeros(/*sizes=*/{1, 2}),
741       tf_float.ones(/*sizes=*/{2, 1}),
742   };
743   TensorList list1(vec1.data(), vec1.size());
744 
745   std::vector<Tensor> vec2 = {
746       tf_int.zeros(/*sizes=*/{1, 2}),
747       tf_float.zeros(/*sizes=*/{2, 1}), // vs. ones() in the first list.
748   };
749   TensorList list2(vec2.data(), vec2.size());
750 
751   EXPECT_TENSOR_LISTS_NOT_CLOSE_OR_EQUAL(list1, list2);
752 }
753 
TEST(TensorUtilTest,TensorListsWithDifferentLengthsAreNotCloseOrEqual)754 TEST(TensorUtilTest, TensorListsWithDifferentLengthsAreNotCloseOrEqual) {
755   TensorFactory<ScalarType::Int> tf_int;
756   TensorFactory<ScalarType::Float> tf_float;
757 
758   std::vector<Tensor> vec1 = {
759       tf_int.zeros(/*sizes=*/{1, 2}),
760       tf_float.ones(/*sizes=*/{2, 1}),
761   };
762   TensorList list1(vec1.data(), vec1.size());
763 
764   std::vector<Tensor> vec2 = {
765       tf_int.zeros(/*sizes=*/{1, 2}),
766       // Missing second element.
767   };
768   TensorList list2(vec2.data(), vec2.size());
769 
770   EXPECT_TENSOR_LISTS_NOT_CLOSE_OR_EQUAL(list1, list2);
771 }
772 
773 // We don't need to test the ATen operator<<() implementations since they're
774 // tested elsewhere.
775 #ifndef USE_ATEN_LIB
776 
777 // Printing/formatting helpers.
778 
TEST(TensorUtilTest,ScalarTypeStreamSmokeTest)779 TEST(TensorUtilTest, ScalarTypeStreamSmokeTest) {
780   // Don't test everything, since operator<<(ScalarType) is just a wrapper
781   // around a separately-tested function. Just demonstrate that the stream
782   // wrapper works, and gives us a little more information for unknown types.
783   {
784     std::stringstream out;
785     out << ScalarType::Byte;
786     EXPECT_STREQ(out.str().c_str(), "Byte");
787   }
788   {
789     std::stringstream out;
790     out << static_cast<ScalarType>(127);
791     EXPECT_STREQ(out.str().c_str(), "Unknown(127)");
792   }
793 }
794 
TEST(TensorUtilTest,TensorStreamInt)795 TEST(TensorUtilTest, TensorStreamInt) {
796   TensorFactory<ScalarType::Int> tf;
797 
798   Tensor t = tf.make(/*sizes=*/{2, 2}, /*data=*/{1, 2, 4, 8});
799 
800   std::stringstream out;
801   out << t;
802   EXPECT_STREQ(
803       out.str().c_str(), "ETensor(sizes={2, 2}, dtype=Int, data={1, 2, 4, 8})");
804 }
805 
TEST(TensorUtilTest,TensorStreamDouble)806 TEST(TensorUtilTest, TensorStreamDouble) {
807   TensorFactory<ScalarType::Double> tf;
808 
809   Tensor t = tf.make(/*sizes=*/{2, 2}, /*data=*/{1.1, 2.2, 4.4, 8.8});
810 
811   std::stringstream out;
812   out << t;
813   EXPECT_STREQ(
814       out.str().c_str(),
815       "ETensor(sizes={2, 2}, dtype=Double, data={1.1, 2.2, 4.4, 8.8})");
816 }
817 
TEST(TensorUtilTest,TensorStreamBool)818 TEST(TensorUtilTest, TensorStreamBool) {
819   TensorFactory<ScalarType::Bool> tf;
820 
821   Tensor t = tf.make(/*sizes=*/{2, 2}, /*data=*/{true, false, true, false});
822 
823   std::stringstream out;
824   out << t;
825   EXPECT_STREQ(
826       out.str().c_str(),
827       "ETensor(sizes={2, 2}, dtype=Bool, data={1, 0, 1, 0})");
828 }
829 
TEST(TensorTest,TestZeroShapeTensorEquality)830 TEST(TensorTest, TestZeroShapeTensorEquality) {
831   TensorImpl::SizesType sizes[2] = {2, 2};
832   TensorImpl::StridesType strides[2] = {2, 1};
833   TensorImpl::DimOrderType dim_order[2] = {0, 1};
834 
835   TensorImpl t1(ScalarType::Float, 2, sizes, nullptr, dim_order, strides);
836   TensorImpl t2(ScalarType::Float, 2, sizes, nullptr, dim_order, strides);
837 
838   ET_EXPECT_DEATH({ EXPECT_TENSOR_EQ(Tensor(&t1), Tensor(&t2)); }, "");
839 
840   float data[] = {1.0, 2.0, 3.0, 4.0};
841 
842   t1.set_data(data);
843   t2.set_data(data);
844 
845   EXPECT_TENSOR_EQ(Tensor(&t1), Tensor(&t2));
846 }
847 
848 #endif // !USE_ATEN_LIB
849