1 | //===-- flang/unittests/Runtime/Reductions.cpp ----------------------------===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | #include "flang/Runtime/reduction.h" |
10 | #include "gtest/gtest.h" |
11 | #include "tools.h" |
12 | #include "flang/Common/float128.h" |
13 | #include "flang/Runtime/allocatable.h" |
14 | #include "flang/Runtime/cpp-type.h" |
15 | #include "flang/Runtime/descriptor.h" |
16 | #include "flang/Runtime/reduce.h" |
17 | #include "flang/Runtime/type-code.h" |
18 | #include <cstdint> |
19 | #include <cstring> |
20 | #include <string> |
21 | #include <vector> |
22 | |
23 | using namespace Fortran::runtime; |
24 | using Fortran::common::TypeCategory; |
25 | |
26 | TEST(Reductions, Int4Ops) { |
27 | auto array{MakeArray<TypeCategory::Integer, 4>( |
28 | std::vector<int>{2, 3}, std::vector<std::int32_t>{1, 2, 3, 4, 5, 6})}; |
29 | std::int32_t sum{RTNAME(SumInteger4)(*array, __FILE__, __LINE__)}; |
30 | EXPECT_EQ(sum, 21) << sum; |
31 | std::int32_t all{RTNAME(IAll4)(*array, __FILE__, __LINE__)}; |
32 | EXPECT_EQ(all, 0) << all; |
33 | std::int32_t any{RTNAME(IAny4)(*array, __FILE__, __LINE__)}; |
34 | EXPECT_EQ(any, 7) << any; |
35 | std::int32_t eor{RTNAME(IParity4)(*array, __FILE__, __LINE__)}; |
36 | EXPECT_EQ(eor, 7) << eor; |
37 | } |
38 | |
39 | TEST(Reductions, DimMaskProductInt4) { |
40 | std::vector<int> shape{2, 3}; |
41 | auto array{MakeArray<TypeCategory::Integer, 4>( |
42 | shape, std::vector<std::int32_t>{1, 2, 3, 4, 5, 6})}; |
43 | auto mask{MakeArray<TypeCategory::Logical, 1>( |
44 | shape, std::vector<bool>{true, false, false, true, true, true})}; |
45 | StaticDescriptor<1, true> statDesc; |
46 | Descriptor &prod{statDesc.descriptor()}; |
47 | RTNAME(ProductDim)(prod, *array, 1, __FILE__, __LINE__, &*mask); |
48 | EXPECT_EQ(prod.rank(), 1); |
49 | EXPECT_EQ(prod.GetDimension(0).LowerBound(), 1); |
50 | EXPECT_EQ(prod.GetDimension(0).Extent(), 3); |
51 | EXPECT_EQ(*prod.ZeroBasedIndexedElement<std::int32_t>(0), 1); |
52 | EXPECT_EQ(*prod.ZeroBasedIndexedElement<std::int32_t>(1), 4); |
53 | EXPECT_EQ(*prod.ZeroBasedIndexedElement<std::int32_t>(2), 30); |
54 | EXPECT_EQ(RTNAME(SumInteger4)(prod, __FILE__, __LINE__), 35); |
55 | prod.Destroy(); |
56 | } |
57 | |
58 | TEST(Reductions, DoubleMaxMinNorm2) { |
59 | std::vector<int> shape{3, 4, 2}; // rows, columns, planes |
60 | // 0 -3 6 -9 12 -15 18 -21 |
61 | // -1 4 -7 10 -13 16 -19 22 |
62 | // 2 -5 8 -11 14 -17 20 22 <- note last two are equal to test |
63 | // BACK= |
64 | std::vector<double> rawData{0, -1, 2, -3, 4, -5, 6, -7, 8, -9, 10, -11, 12, |
65 | -13, 14, -15, 16, -17, 18, -19, 20, -21, 22, 22}; |
66 | auto array{MakeArray<TypeCategory::Real, 8>(shape, rawData)}; |
67 | EXPECT_EQ(RTNAME(MaxvalReal8)(*array, __FILE__, __LINE__), 22.0); |
68 | EXPECT_EQ(RTNAME(MinvalReal8)(*array, __FILE__, __LINE__), -21.0); |
69 | double naiveNorm2{0}; |
70 | for (auto x : rawData) { |
71 | naiveNorm2 += x * x; |
72 | } |
73 | naiveNorm2 = std::sqrt(naiveNorm2); |
74 | double norm2Error{ |
75 | std::abs(naiveNorm2 - RTNAME(Norm2_8)(*array, __FILE__, __LINE__))}; |
76 | EXPECT_LE(norm2Error, 0.000001 * naiveNorm2); |
77 | StaticDescriptor<2, true> statDesc; |
78 | Descriptor &loc{statDesc.descriptor()}; |
79 | RTNAME(MaxlocReal8) |
80 | (loc, *array, /*KIND=*/8, __FILE__, __LINE__, /*MASK=*/nullptr, |
81 | /*BACK=*/false); |
82 | EXPECT_EQ(loc.rank(), 1); |
83 | EXPECT_EQ(loc.type().raw(), (TypeCode{TypeCategory::Integer, 8}.raw())); |
84 | EXPECT_EQ(loc.GetDimension(0).LowerBound(), 1); |
85 | EXPECT_EQ(loc.GetDimension(0).Extent(), 3); |
86 | EXPECT_EQ( |
87 | *array->Element<double>(loc.ZeroBasedIndexedElement<SubscriptValue>(0)), |
88 | 22.0); |
89 | EXPECT_EQ(*loc.ZeroBasedIndexedElement<std::int64_t>(0), 2); |
90 | EXPECT_EQ(*loc.ZeroBasedIndexedElement<std::int64_t>(1), 4); |
91 | EXPECT_EQ(*loc.ZeroBasedIndexedElement<std::int64_t>(2), 2); |
92 | loc.Destroy(); |
93 | RTNAME(MaxlocReal8) |
94 | (loc, *array, /*KIND=*/8, __FILE__, __LINE__, /*MASK=*/nullptr, |
95 | /*BACK=*/true); |
96 | EXPECT_EQ(loc.rank(), 1); |
97 | EXPECT_EQ(loc.type().raw(), (TypeCode{TypeCategory::Integer, 8}.raw())); |
98 | EXPECT_EQ(loc.GetDimension(0).LowerBound(), 1); |
99 | EXPECT_EQ(loc.GetDimension(0).Extent(), 3); |
100 | EXPECT_EQ( |
101 | *array->Element<double>(loc.ZeroBasedIndexedElement<SubscriptValue>(0)), |
102 | 22.0); |
103 | EXPECT_EQ(*loc.ZeroBasedIndexedElement<std::int64_t>(0), 3); |
104 | EXPECT_EQ(*loc.ZeroBasedIndexedElement<std::int64_t>(1), 4); |
105 | EXPECT_EQ(*loc.ZeroBasedIndexedElement<std::int64_t>(2), 2); |
106 | loc.Destroy(); |
107 | RTNAME(MinlocDim) |
108 | (loc, *array, /*KIND=*/2, /*DIM=*/1, __FILE__, __LINE__, /*MASK=*/nullptr, |
109 | /*BACK=*/false); |
110 | EXPECT_EQ(loc.rank(), 2); |
111 | EXPECT_EQ(loc.type().raw(), (TypeCode{TypeCategory::Integer, 2}.raw())); |
112 | EXPECT_EQ(loc.GetDimension(0).LowerBound(), 1); |
113 | EXPECT_EQ(loc.GetDimension(0).Extent(), 4); |
114 | EXPECT_EQ(loc.GetDimension(1).LowerBound(), 1); |
115 | EXPECT_EQ(loc.GetDimension(1).Extent(), 2); |
116 | EXPECT_EQ(*loc.ZeroBasedIndexedElement<std::int16_t>(0), 2); // -1 |
117 | EXPECT_EQ(*loc.ZeroBasedIndexedElement<std::int16_t>(1), 3); // -5 |
118 | EXPECT_EQ(*loc.ZeroBasedIndexedElement<std::int16_t>(2), 2); // -2 |
119 | EXPECT_EQ(*loc.ZeroBasedIndexedElement<std::int16_t>(3), 3); // -11 |
120 | EXPECT_EQ(*loc.ZeroBasedIndexedElement<std::int16_t>(4), 2); // -13 |
121 | EXPECT_EQ(*loc.ZeroBasedIndexedElement<std::int16_t>(5), 3); // -17 |
122 | EXPECT_EQ(*loc.ZeroBasedIndexedElement<std::int16_t>(6), 2); // -19 |
123 | EXPECT_EQ(*loc.ZeroBasedIndexedElement<std::int16_t>(7), 1); // -21 |
124 | loc.Destroy(); |
125 | auto mask{MakeArray<TypeCategory::Logical, 1>(shape, |
126 | std::vector<bool>{false, false, false, false, false, true, false, true, |
127 | false, false, true, true, true, false, false, true, false, true, true, |
128 | true, false, true, true, true})}; |
129 | RTNAME(MaxlocDim) |
130 | (loc, *array, /*KIND=*/2, /*DIM=*/3, __FILE__, __LINE__, /*MASK=*/&*mask, |
131 | false); |
132 | EXPECT_EQ(loc.rank(), 2); |
133 | EXPECT_EQ(loc.type().raw(), (TypeCode{TypeCategory::Integer, 2}.raw())); |
134 | EXPECT_EQ(loc.GetDimension(0).LowerBound(), 1); |
135 | EXPECT_EQ(loc.GetDimension(0).Extent(), 3); |
136 | EXPECT_EQ(loc.GetDimension(1).LowerBound(), 1); |
137 | EXPECT_EQ(loc.GetDimension(1).Extent(), 4); |
138 | EXPECT_EQ(*loc.ZeroBasedIndexedElement<std::int16_t>(0), 2); // 12 |
139 | EXPECT_EQ(*loc.ZeroBasedIndexedElement<std::int16_t>(1), 0); |
140 | EXPECT_EQ(*loc.ZeroBasedIndexedElement<std::int16_t>(2), 0); |
141 | EXPECT_EQ(*loc.ZeroBasedIndexedElement<std::int16_t>(3), 2); // -15 |
142 | EXPECT_EQ(*loc.ZeroBasedIndexedElement<std::int16_t>(4), 0); |
143 | EXPECT_EQ(*loc.ZeroBasedIndexedElement<std::int16_t>(5), 1); // -5 |
144 | EXPECT_EQ(*loc.ZeroBasedIndexedElement<std::int16_t>(6), 2); // 18 |
145 | EXPECT_EQ(*loc.ZeroBasedIndexedElement<std::int16_t>(7), 1); // -7 |
146 | EXPECT_EQ(*loc.ZeroBasedIndexedElement<std::int16_t>(8), 0); |
147 | EXPECT_EQ(*loc.ZeroBasedIndexedElement<std::int16_t>(9), 2); // -21 |
148 | EXPECT_EQ(*loc.ZeroBasedIndexedElement<std::int16_t>(10), 2); // 22 |
149 | EXPECT_EQ(*loc.ZeroBasedIndexedElement<std::int16_t>(11), 2); // 22 |
150 | loc.Destroy(); |
151 | // Test scalar result for MaxlocDim, MinlocDim, MaxvalDim, MinvalDim. |
152 | // A scalar result occurs when you have a rank 1 array and dim == 1. |
153 | std::vector<int> shape1{24}; |
154 | auto array1{MakeArray<TypeCategory::Real, 8>(shape1, rawData)}; |
155 | StaticDescriptor<1, true> statDesc0[1]; |
156 | Descriptor &scalarResult{statDesc0[0].descriptor()}; |
157 | RTNAME(MaxlocDim) |
158 | (scalarResult, *array1, /*KIND=*/2, /*DIM=*/1, __FILE__, __LINE__, |
159 | /*MASK=*/nullptr, /*BACK=*/false); |
160 | EXPECT_EQ(scalarResult.rank(), 0); |
161 | EXPECT_EQ(*scalarResult.ZeroBasedIndexedElement<std::int16_t>(0), 23); |
162 | scalarResult.Destroy(); |
163 | |
164 | // Test .FALSE. scalar MASK argument |
165 | auto falseMask{MakeArray<TypeCategory::Logical, 4>( |
166 | std::vector<int>{}, std::vector<std::int32_t>{0})}; |
167 | RTNAME(MaxlocDim) |
168 | (loc, *array, /*KIND=*/4, /*DIM=*/2, __FILE__, __LINE__, |
169 | /*MASK=*/&*falseMask, /*BACK=*/false); |
170 | EXPECT_EQ(loc.rank(), 2); |
171 | EXPECT_EQ(loc.type().raw(), (TypeCode{TypeCategory::Integer, 4}.raw())); |
172 | EXPECT_EQ(loc.GetDimension(0).LowerBound(), 1); |
173 | EXPECT_EQ(loc.GetDimension(0).Extent(), 3); |
174 | EXPECT_EQ(loc.GetDimension(1).LowerBound(), 1); |
175 | EXPECT_EQ(loc.GetDimension(1).Extent(), 2); |
176 | for (int i{0}; i < 6; ++i) { |
177 | EXPECT_EQ(*loc.ZeroBasedIndexedElement<std::int32_t>(0), 0); |
178 | } |
179 | loc.Destroy(); |
180 | |
181 | // Test .TRUE. scalar MASK argument |
182 | auto trueMask{MakeArray<TypeCategory::Logical, 4>( |
183 | std::vector<int>{}, std::vector<std::int32_t>{1})}; |
184 | RTNAME(MaxlocDim) |
185 | (loc, *array, /*KIND=*/4, /*DIM=*/2, __FILE__, __LINE__, |
186 | /*MASK=*/&*trueMask, /*BACK=*/false); |
187 | EXPECT_EQ(loc.rank(), 2); |
188 | EXPECT_EQ(loc.type().raw(), (TypeCode{TypeCategory::Integer, 4}.raw())); |
189 | EXPECT_EQ(loc.GetDimension(0).LowerBound(), 1); |
190 | EXPECT_EQ(loc.GetDimension(0).Extent(), 3); |
191 | EXPECT_EQ(loc.GetDimension(1).LowerBound(), 1); |
192 | EXPECT_EQ(loc.GetDimension(1).Extent(), 2); |
193 | EXPECT_EQ(*loc.ZeroBasedIndexedElement<std::int32_t>(0), 3); |
194 | EXPECT_EQ(*loc.ZeroBasedIndexedElement<std::int32_t>(1), 4); |
195 | EXPECT_EQ(*loc.ZeroBasedIndexedElement<std::int32_t>(2), 3); |
196 | EXPECT_EQ(*loc.ZeroBasedIndexedElement<std::int32_t>(3), 3); |
197 | EXPECT_EQ(*loc.ZeroBasedIndexedElement<std::int32_t>(4), 4); |
198 | EXPECT_EQ(*loc.ZeroBasedIndexedElement<std::int32_t>(5), 4); |
199 | loc.Destroy(); |
200 | |
201 | RTNAME(MinlocDim) |
202 | (scalarResult, *array1, /*KIND=*/2, /*DIM=*/1, __FILE__, __LINE__, |
203 | /*MASK=*/nullptr, /*BACK=*/true); |
204 | EXPECT_EQ(scalarResult.rank(), 0); |
205 | EXPECT_EQ(*scalarResult.ZeroBasedIndexedElement<std::int16_t>(0), 22); |
206 | scalarResult.Destroy(); |
207 | |
208 | // Test .FALSE. scalar MASK argument |
209 | RTNAME(MinlocDim) |
210 | (loc, *array, /*KIND=*/4, /*DIM=*/2, __FILE__, __LINE__, |
211 | /*MASK=*/&*falseMask, /*BACK=*/false); |
212 | EXPECT_EQ(loc.rank(), 2); |
213 | EXPECT_EQ(loc.type().raw(), (TypeCode{TypeCategory::Integer, 4}.raw())); |
214 | EXPECT_EQ(loc.GetDimension(0).LowerBound(), 1); |
215 | EXPECT_EQ(loc.GetDimension(0).Extent(), 3); |
216 | EXPECT_EQ(loc.GetDimension(1).LowerBound(), 1); |
217 | EXPECT_EQ(loc.GetDimension(1).Extent(), 2); |
218 | for (int i{0}; i < 6; ++i) { |
219 | EXPECT_EQ(*loc.ZeroBasedIndexedElement<std::int32_t>(0), 0); |
220 | } |
221 | loc.Destroy(); |
222 | |
223 | // Test .TRUE. scalar MASK argument |
224 | RTNAME(MinlocDim) |
225 | (loc, *array, /*KIND=*/4, /*DIM=*/2, __FILE__, __LINE__, |
226 | /*MASK=*/&*trueMask, /*BACK=*/false); |
227 | EXPECT_EQ(loc.rank(), 2); |
228 | EXPECT_EQ(loc.type().raw(), (TypeCode{TypeCategory::Integer, 4}.raw())); |
229 | EXPECT_EQ(loc.GetDimension(0).LowerBound(), 1); |
230 | EXPECT_EQ(loc.GetDimension(0).Extent(), 3); |
231 | EXPECT_EQ(loc.GetDimension(1).LowerBound(), 1); |
232 | EXPECT_EQ(loc.GetDimension(1).Extent(), 2); |
233 | EXPECT_EQ(*loc.ZeroBasedIndexedElement<std::int32_t>(0), 4); |
234 | EXPECT_EQ(*loc.ZeroBasedIndexedElement<std::int32_t>(1), 3); |
235 | EXPECT_EQ(*loc.ZeroBasedIndexedElement<std::int32_t>(2), 4); |
236 | EXPECT_EQ(*loc.ZeroBasedIndexedElement<std::int32_t>(3), 4); |
237 | EXPECT_EQ(*loc.ZeroBasedIndexedElement<std::int32_t>(4), 3); |
238 | EXPECT_EQ(*loc.ZeroBasedIndexedElement<std::int32_t>(5), 2); |
239 | loc.Destroy(); |
240 | |
241 | RTNAME(MaxvalDim) |
242 | (scalarResult, *array1, /*DIM=*/1, __FILE__, __LINE__, /*MASK=*/nullptr); |
243 | EXPECT_EQ(scalarResult.rank(), 0); |
244 | EXPECT_EQ(*scalarResult.ZeroBasedIndexedElement<double>(0), 22.0); |
245 | scalarResult.Destroy(); |
246 | RTNAME(MinvalDim) |
247 | (scalarResult, *array1, /*DIM=*/1, __FILE__, __LINE__, /*MASK=*/nullptr); |
248 | EXPECT_EQ(scalarResult.rank(), 0); |
249 | EXPECT_EQ(*scalarResult.ZeroBasedIndexedElement<double>(0), -21.0); |
250 | scalarResult.Destroy(); |
251 | } |
252 | |
253 | TEST(Reductions, Character) { |
254 | std::vector<int> shape{2, 3}; |
255 | auto array{MakeArray<TypeCategory::Character, 1>(shape, |
256 | std::vector<std::string>{"abc" , "def" , "ghi" , "jkl" , "mno" , "abc" }, 3)}; |
257 | StaticDescriptor<1, true> statDesc[2]; |
258 | Descriptor &res{statDesc[0].descriptor()}; |
259 | RTNAME(MaxvalCharacter)(res, *array, __FILE__, __LINE__); |
260 | EXPECT_EQ(res.rank(), 0); |
261 | EXPECT_EQ(res.type().raw(), (TypeCode{TypeCategory::Character, 1}.raw())); |
262 | EXPECT_EQ(std::memcmp(res.OffsetElement<char>(), "mno" , 3), 0); |
263 | res.Destroy(); |
264 | RTNAME(MinvalCharacter)(res, *array, __FILE__, __LINE__); |
265 | EXPECT_EQ(res.rank(), 0); |
266 | EXPECT_EQ(res.type().raw(), (TypeCode{TypeCategory::Character, 1}.raw())); |
267 | EXPECT_EQ(std::memcmp(res.OffsetElement<char>(), "abc" , 3), 0); |
268 | res.Destroy(); |
269 | RTNAME(MaxlocCharacter) |
270 | (res, *array, /*KIND=*/4, __FILE__, __LINE__, /*MASK=*/nullptr, |
271 | /*BACK=*/false); |
272 | EXPECT_EQ(res.rank(), 1); |
273 | EXPECT_EQ(res.type().raw(), (TypeCode{TypeCategory::Integer, 4}.raw())); |
274 | EXPECT_EQ(res.GetDimension(0).LowerBound(), 1); |
275 | EXPECT_EQ(res.GetDimension(0).Extent(), 2); |
276 | EXPECT_EQ(*res.ZeroBasedIndexedElement<std::int32_t>(0), 1); |
277 | EXPECT_EQ(*res.ZeroBasedIndexedElement<std::int32_t>(1), 3); |
278 | res.Destroy(); |
279 | auto mask{MakeArray<TypeCategory::Logical, 1>( |
280 | shape, std::vector<bool>{false, true, false, true, false, true})}; |
281 | RTNAME(MaxlocCharacter) |
282 | (res, *array, /*KIND=*/4, __FILE__, __LINE__, /*MASK=*/&*mask, |
283 | /*BACK=*/false); |
284 | EXPECT_EQ(res.rank(), 1); |
285 | EXPECT_EQ(res.type().raw(), (TypeCode{TypeCategory::Integer, 4}.raw())); |
286 | EXPECT_EQ(res.GetDimension(0).LowerBound(), 1); |
287 | EXPECT_EQ(res.GetDimension(0).Extent(), 2); |
288 | EXPECT_EQ(*res.ZeroBasedIndexedElement<std::int32_t>(0), 2); |
289 | EXPECT_EQ(*res.ZeroBasedIndexedElement<std::int32_t>(1), 2); |
290 | res.Destroy(); |
291 | RTNAME(MinlocCharacter) |
292 | (res, *array, /*KIND=*/4, __FILE__, __LINE__, /*MASK=*/nullptr, |
293 | /*BACK=*/false); |
294 | EXPECT_EQ(res.rank(), 1); |
295 | EXPECT_EQ(res.type().raw(), (TypeCode{TypeCategory::Integer, 4}.raw())); |
296 | EXPECT_EQ(res.GetDimension(0).LowerBound(), 1); |
297 | EXPECT_EQ(res.GetDimension(0).Extent(), 2); |
298 | EXPECT_EQ(*res.ZeroBasedIndexedElement<std::int32_t>(0), 1); |
299 | EXPECT_EQ(*res.ZeroBasedIndexedElement<std::int32_t>(1), 1); |
300 | res.Destroy(); |
301 | RTNAME(MinlocCharacter) |
302 | (res, *array, /*KIND=*/4, __FILE__, __LINE__, /*MASK=*/nullptr, |
303 | /*BACK=*/true); |
304 | EXPECT_EQ(res.rank(), 1); |
305 | EXPECT_EQ(res.type().raw(), (TypeCode{TypeCategory::Integer, 4}.raw())); |
306 | EXPECT_EQ(res.GetDimension(0).LowerBound(), 1); |
307 | EXPECT_EQ(res.GetDimension(0).Extent(), 2); |
308 | EXPECT_EQ(*res.ZeroBasedIndexedElement<std::int32_t>(0), 2); |
309 | EXPECT_EQ(*res.ZeroBasedIndexedElement<std::int32_t>(1), 3); |
310 | res.Destroy(); |
311 | RTNAME(MinlocCharacter) |
312 | (res, *array, /*KIND=*/4, __FILE__, __LINE__, /*MASK=*/&*mask, |
313 | /*BACK=*/true); |
314 | EXPECT_EQ(res.rank(), 1); |
315 | EXPECT_EQ(res.type().raw(), (TypeCode{TypeCategory::Integer, 4}.raw())); |
316 | EXPECT_EQ(res.GetDimension(0).LowerBound(), 1); |
317 | EXPECT_EQ(res.GetDimension(0).Extent(), 2); |
318 | EXPECT_EQ(*res.ZeroBasedIndexedElement<std::int32_t>(0), 2); |
319 | EXPECT_EQ(*res.ZeroBasedIndexedElement<std::int32_t>(1), 3); |
320 | res.Destroy(); |
321 | static const char targetChar[]{"abc" }; |
322 | Descriptor &target{statDesc[1].descriptor()}; |
323 | target.Establish(1, std::strlen(targetChar), |
324 | const_cast<void *>(static_cast<const void *>(&targetChar)), 0, nullptr, |
325 | CFI_attribute_pointer); |
326 | RTNAME(Findloc) |
327 | (res, *array, target, /*KIND=*/4, __FILE__, __LINE__, nullptr, |
328 | /*BACK=*/false); |
329 | EXPECT_EQ(res.rank(), 1); |
330 | EXPECT_EQ(res.type().raw(), (TypeCode{TypeCategory::Integer, 4}.raw())); |
331 | EXPECT_EQ(res.GetDimension(0).LowerBound(), 1); |
332 | EXPECT_EQ(res.GetDimension(0).Extent(), 2); |
333 | EXPECT_EQ(*res.ZeroBasedIndexedElement<std::int32_t>(0), 1); |
334 | EXPECT_EQ(*res.ZeroBasedIndexedElement<std::int32_t>(1), 1); |
335 | res.Destroy(); |
336 | RTNAME(Findloc) |
337 | (res, *array, target, /*KIND=*/4, __FILE__, __LINE__, nullptr, /*BACK=*/true); |
338 | EXPECT_EQ(res.rank(), 1); |
339 | EXPECT_EQ(res.type().raw(), (TypeCode{TypeCategory::Integer, 4}.raw())); |
340 | EXPECT_EQ(res.GetDimension(0).LowerBound(), 1); |
341 | EXPECT_EQ(res.GetDimension(0).Extent(), 2); |
342 | EXPECT_EQ(*res.ZeroBasedIndexedElement<std::int32_t>(0), 2); |
343 | EXPECT_EQ(*res.ZeroBasedIndexedElement<std::int32_t>(1), 3); |
344 | res.Destroy(); |
345 | } |
346 | |
347 | TEST(Reductions, Logical) { |
348 | std::vector<int> shape{2, 2}; |
349 | auto array{MakeArray<TypeCategory::Logical, 4>( |
350 | shape, std::vector<std::int32_t>{false, false, true, true})}; |
351 | ASSERT_EQ(array->ElementBytes(), std::size_t{4}); |
352 | EXPECT_EQ(RTNAME(All)(*array, __FILE__, __LINE__), false); |
353 | EXPECT_EQ(RTNAME(Any)(*array, __FILE__, __LINE__), true); |
354 | EXPECT_EQ(RTNAME(Parity)(*array, __FILE__, __LINE__), false); |
355 | EXPECT_EQ(RTNAME(Count)(*array, __FILE__, __LINE__), 2); |
356 | StaticDescriptor<2, true> statDesc[2]; |
357 | Descriptor &res{statDesc[0].descriptor()}; |
358 | RTNAME(AllDim)(res, *array, /*DIM=*/1, __FILE__, __LINE__); |
359 | EXPECT_EQ(res.rank(), 1); |
360 | EXPECT_EQ(res.type().raw(), (TypeCode{TypeCategory::Logical, 4}.raw())); |
361 | EXPECT_EQ(res.GetDimension(0).LowerBound(), 1); |
362 | EXPECT_EQ(res.GetDimension(0).Extent(), 2); |
363 | EXPECT_EQ(*res.ZeroBasedIndexedElement<std::int32_t>(0), 0); |
364 | EXPECT_EQ(*res.ZeroBasedIndexedElement<std::int32_t>(1), 1); |
365 | res.Destroy(); |
366 | RTNAME(AllDim)(res, *array, /*DIM=*/2, __FILE__, __LINE__); |
367 | EXPECT_EQ(res.rank(), 1); |
368 | EXPECT_EQ(res.type().raw(), (TypeCode{TypeCategory::Logical, 4}.raw())); |
369 | EXPECT_EQ(res.GetDimension(0).LowerBound(), 1); |
370 | EXPECT_EQ(res.GetDimension(0).Extent(), 2); |
371 | EXPECT_EQ(*res.ZeroBasedIndexedElement<std::int32_t>(0), 0); |
372 | EXPECT_EQ(*res.ZeroBasedIndexedElement<std::int32_t>(1), 0); |
373 | res.Destroy(); |
374 | // Test scalar result for AllDim. |
375 | // A scalar result occurs when you have a rank 1 array. |
376 | std::vector<int> shape1{4}; |
377 | auto array1{MakeArray<TypeCategory::Logical, 4>( |
378 | shape1, std::vector<std::int32_t>{false, false, true, true})}; |
379 | StaticDescriptor<1, true> statDesc0[1]; |
380 | Descriptor &scalarResult{statDesc0[0].descriptor()}; |
381 | RTNAME(AllDim)(scalarResult, *array1, /*DIM=*/1, __FILE__, __LINE__); |
382 | EXPECT_EQ(scalarResult.rank(), 0); |
383 | EXPECT_EQ(*scalarResult.ZeroBasedIndexedElement<std::int32_t>(0), 0); |
384 | scalarResult.Destroy(); |
385 | RTNAME(AnyDim)(res, *array, /*DIM=*/1, __FILE__, __LINE__); |
386 | EXPECT_EQ(res.rank(), 1); |
387 | EXPECT_EQ(res.type().raw(), (TypeCode{TypeCategory::Logical, 4}.raw())); |
388 | EXPECT_EQ(res.GetDimension(0).LowerBound(), 1); |
389 | EXPECT_EQ(res.GetDimension(0).Extent(), 2); |
390 | EXPECT_EQ(*res.ZeroBasedIndexedElement<std::int32_t>(0), 0); |
391 | EXPECT_EQ(*res.ZeroBasedIndexedElement<std::int32_t>(1), 1); |
392 | res.Destroy(); |
393 | RTNAME(AnyDim)(res, *array, /*DIM=*/2, __FILE__, __LINE__); |
394 | EXPECT_EQ(res.rank(), 1); |
395 | EXPECT_EQ(res.type().raw(), (TypeCode{TypeCategory::Logical, 4}.raw())); |
396 | EXPECT_EQ(res.GetDimension(0).LowerBound(), 1); |
397 | EXPECT_EQ(res.GetDimension(0).Extent(), 2); |
398 | EXPECT_EQ(*res.ZeroBasedIndexedElement<std::int32_t>(0), 1); |
399 | EXPECT_EQ(*res.ZeroBasedIndexedElement<std::int32_t>(1), 1); |
400 | res.Destroy(); |
401 | // Test scalar result for AnyDim. |
402 | // A scalar result occurs when you have a rank 1 array. |
403 | RTNAME(AnyDim)(scalarResult, *array1, /*DIM=*/1, __FILE__, __LINE__); |
404 | EXPECT_EQ(scalarResult.rank(), 0); |
405 | EXPECT_EQ(*scalarResult.ZeroBasedIndexedElement<std::int32_t>(0), 1); |
406 | scalarResult.Destroy(); |
407 | RTNAME(ParityDim)(res, *array, /*DIM=*/1, __FILE__, __LINE__); |
408 | EXPECT_EQ(res.rank(), 1); |
409 | EXPECT_EQ(res.type().raw(), (TypeCode{TypeCategory::Logical, 4}.raw())); |
410 | EXPECT_EQ(res.GetDimension(0).LowerBound(), 1); |
411 | EXPECT_EQ(res.GetDimension(0).Extent(), 2); |
412 | EXPECT_EQ(*res.ZeroBasedIndexedElement<std::int32_t>(0), 0); |
413 | EXPECT_EQ(*res.ZeroBasedIndexedElement<std::int32_t>(1), 0); |
414 | res.Destroy(); |
415 | RTNAME(ParityDim)(res, *array, /*DIM=*/2, __FILE__, __LINE__); |
416 | EXPECT_EQ(res.rank(), 1); |
417 | EXPECT_EQ(res.type().raw(), (TypeCode{TypeCategory::Logical, 4}.raw())); |
418 | EXPECT_EQ(res.GetDimension(0).LowerBound(), 1); |
419 | EXPECT_EQ(res.GetDimension(0).Extent(), 2); |
420 | EXPECT_EQ(*res.ZeroBasedIndexedElement<std::int32_t>(0), 1); |
421 | EXPECT_EQ(*res.ZeroBasedIndexedElement<std::int32_t>(1), 1); |
422 | res.Destroy(); |
423 | // Test scalar result for ParityDim. |
424 | // A scalar result occurs when you have a rank 1 array. |
425 | RTNAME(ParityDim)(scalarResult, *array1, /*DIM=*/1, __FILE__, __LINE__); |
426 | EXPECT_EQ(scalarResult.rank(), 0); |
427 | EXPECT_EQ(*scalarResult.ZeroBasedIndexedElement<std::int32_t>(0), 0); |
428 | scalarResult.Destroy(); |
429 | RTNAME(CountDim)(res, *array, /*DIM=*/1, /*KIND=*/4, __FILE__, __LINE__); |
430 | EXPECT_EQ(res.rank(), 1); |
431 | EXPECT_EQ(res.type().raw(), (TypeCode{TypeCategory::Integer, 4}.raw())); |
432 | EXPECT_EQ(res.GetDimension(0).LowerBound(), 1); |
433 | EXPECT_EQ(res.GetDimension(0).Extent(), 2); |
434 | EXPECT_EQ(*res.ZeroBasedIndexedElement<std::int32_t>(0), 0); |
435 | EXPECT_EQ(*res.ZeroBasedIndexedElement<std::int32_t>(1), 2); |
436 | res.Destroy(); |
437 | RTNAME(CountDim)(res, *array, /*DIM=*/2, /*KIND=*/8, __FILE__, __LINE__); |
438 | EXPECT_EQ(res.rank(), 1); |
439 | EXPECT_EQ(res.type().raw(), (TypeCode{TypeCategory::Integer, 8}.raw())); |
440 | EXPECT_EQ(res.GetDimension(0).LowerBound(), 1); |
441 | EXPECT_EQ(res.GetDimension(0).Extent(), 2); |
442 | EXPECT_EQ(*res.ZeroBasedIndexedElement<std::int64_t>(0), 1); |
443 | EXPECT_EQ(*res.ZeroBasedIndexedElement<std::int64_t>(1), 1); |
444 | res.Destroy(); |
445 | // Test scalar result for CountDim. |
446 | // A scalar result occurs when you have a rank 1 array and dim == 1. |
447 | RTNAME(CountDim) |
448 | (scalarResult, *array1, /*DIM=*/1, /*KIND=*/8, __FILE__, __LINE__); |
449 | EXPECT_EQ(scalarResult.rank(), 0); |
450 | EXPECT_EQ(*scalarResult.ZeroBasedIndexedElement<std::int64_t>(0), 2); |
451 | scalarResult.Destroy(); |
452 | bool boolValue{false}; |
453 | Descriptor &target{statDesc[1].descriptor()}; |
454 | target.Establish(TypeCategory::Logical, 1, static_cast<void *>(&boolValue), 0, |
455 | nullptr, CFI_attribute_pointer); |
456 | RTNAME(Findloc) |
457 | (res, *array, target, /*KIND=*/4, __FILE__, __LINE__, nullptr, |
458 | /*BACK=*/false); |
459 | EXPECT_EQ(res.rank(), 1); |
460 | EXPECT_EQ(res.type().raw(), (TypeCode{TypeCategory::Integer, 4}.raw())); |
461 | EXPECT_EQ(res.GetDimension(0).LowerBound(), 1); |
462 | EXPECT_EQ(res.GetDimension(0).Extent(), 2); |
463 | EXPECT_EQ(*res.ZeroBasedIndexedElement<std::int32_t>(0), 1); |
464 | EXPECT_EQ(*res.ZeroBasedIndexedElement<std::int32_t>(1), 1); |
465 | res.Destroy(); |
466 | boolValue = true; |
467 | RTNAME(Findloc) |
468 | (res, *array, target, /*KIND=*/4, __FILE__, __LINE__, nullptr, /*BACK=*/true); |
469 | EXPECT_EQ(res.rank(), 1); |
470 | EXPECT_EQ(res.type().raw(), (TypeCode{TypeCategory::Integer, 4}.raw())); |
471 | EXPECT_EQ(res.GetDimension(0).LowerBound(), 1); |
472 | EXPECT_EQ(res.GetDimension(0).Extent(), 2); |
473 | EXPECT_EQ(*res.ZeroBasedIndexedElement<std::int32_t>(0), 2); |
474 | EXPECT_EQ(*res.ZeroBasedIndexedElement<std::int32_t>(1), 2); |
475 | res.Destroy(); |
476 | } |
477 | |
478 | TEST(Reductions, FindlocNumeric) { |
479 | std::vector<int> shape{2, 3}; |
480 | auto realArray{MakeArray<TypeCategory::Real, 8>(shape, |
481 | std::vector<double>{0.0, -0.0, 1.0, 3.14, |
482 | std::numeric_limits<double>::quiet_NaN(), |
483 | std::numeric_limits<double>::infinity()})}; |
484 | ASSERT_EQ(realArray->ElementBytes(), sizeof(double)); |
485 | StaticDescriptor<2, true> statDesc[2]; |
486 | Descriptor &res{statDesc[0].descriptor()}; |
487 | // Find the first zero |
488 | Descriptor &target{statDesc[1].descriptor()}; |
489 | double value{0.0}; |
490 | target.Establish(TypeCategory::Real, 8, static_cast<void *>(&value), 0, |
491 | nullptr, CFI_attribute_pointer); |
492 | RTNAME(Findloc) |
493 | (res, *realArray, target, 8, __FILE__, __LINE__, nullptr, /*BACK=*/false); |
494 | EXPECT_EQ(res.rank(), 1); |
495 | EXPECT_EQ(res.type().raw(), (TypeCode{TypeCategory::Integer, 8}.raw())); |
496 | EXPECT_EQ(res.GetDimension(0).LowerBound(), 1); |
497 | EXPECT_EQ(res.GetDimension(0).UpperBound(), 2); |
498 | EXPECT_EQ(*res.ZeroBasedIndexedElement<SubscriptValue>(0), 1); |
499 | EXPECT_EQ(*res.ZeroBasedIndexedElement<SubscriptValue>(1), 1); |
500 | res.Destroy(); |
501 | // Find last zero (even though it's negative) |
502 | RTNAME(Findloc) |
503 | (res, *realArray, target, 8, __FILE__, __LINE__, nullptr, /*BACK=*/true); |
504 | EXPECT_EQ(res.rank(), 1); |
505 | EXPECT_EQ(res.type().raw(), (TypeCode{TypeCategory::Integer, 8}.raw())); |
506 | EXPECT_EQ(res.GetDimension(0).LowerBound(), 1); |
507 | EXPECT_EQ(res.GetDimension(0).UpperBound(), 2); |
508 | EXPECT_EQ(*res.ZeroBasedIndexedElement<SubscriptValue>(0), 2); |
509 | EXPECT_EQ(*res.ZeroBasedIndexedElement<SubscriptValue>(1), 1); |
510 | res.Destroy(); |
511 | // Find the +Inf |
512 | value = std::numeric_limits<double>::infinity(); |
513 | RTNAME(Findloc) |
514 | (res, *realArray, target, 8, __FILE__, __LINE__, nullptr, /*BACK=*/false); |
515 | EXPECT_EQ(res.rank(), 1); |
516 | EXPECT_EQ(res.type().raw(), (TypeCode{TypeCategory::Integer, 8}.raw())); |
517 | EXPECT_EQ(res.GetDimension(0).LowerBound(), 1); |
518 | EXPECT_EQ(res.GetDimension(0).UpperBound(), 2); |
519 | EXPECT_EQ(*res.ZeroBasedIndexedElement<SubscriptValue>(0), 2); |
520 | EXPECT_EQ(*res.ZeroBasedIndexedElement<SubscriptValue>(1), 3); |
521 | res.Destroy(); |
522 | // Ensure that we can't find a NaN |
523 | value = std::numeric_limits<double>::quiet_NaN(); |
524 | RTNAME(Findloc) |
525 | (res, *realArray, target, 8, __FILE__, __LINE__, nullptr, /*BACK=*/false); |
526 | EXPECT_EQ(res.rank(), 1); |
527 | EXPECT_EQ(res.type().raw(), (TypeCode{TypeCategory::Integer, 8}.raw())); |
528 | EXPECT_EQ(res.GetDimension(0).LowerBound(), 1); |
529 | EXPECT_EQ(res.GetDimension(0).UpperBound(), 2); |
530 | EXPECT_EQ(*res.ZeroBasedIndexedElement<SubscriptValue>(0), 0); |
531 | EXPECT_EQ(*res.ZeroBasedIndexedElement<SubscriptValue>(1), 0); |
532 | res.Destroy(); |
533 | // Find a value of a distinct type |
534 | int intValue{1}; |
535 | target.Establish(TypeCategory::Integer, 4, static_cast<void *>(&intValue), 0, |
536 | nullptr, CFI_attribute_pointer); |
537 | RTNAME(Findloc) |
538 | (res, *realArray, target, 8, __FILE__, __LINE__, nullptr, /*BACK=*/false); |
539 | EXPECT_EQ(res.rank(), 1); |
540 | EXPECT_EQ(res.type().raw(), (TypeCode{TypeCategory::Integer, 8}.raw())); |
541 | EXPECT_EQ(res.GetDimension(0).LowerBound(), 1); |
542 | EXPECT_EQ(res.GetDimension(0).UpperBound(), 2); |
543 | EXPECT_EQ(*res.ZeroBasedIndexedElement<SubscriptValue>(0), 1); |
544 | EXPECT_EQ(*res.ZeroBasedIndexedElement<SubscriptValue>(1), 2); |
545 | res.Destroy(); |
546 | // Partial reductions |
547 | value = 1.0; |
548 | target.Establish(TypeCategory::Real, 8, static_cast<void *>(&value), 0, |
549 | nullptr, CFI_attribute_pointer); |
550 | RTNAME(FindlocDim) |
551 | (res, *realArray, target, 8, /*DIM=*/1, __FILE__, __LINE__, nullptr, |
552 | /*BACK=*/false); |
553 | EXPECT_EQ(res.rank(), 1); |
554 | EXPECT_EQ(res.type().raw(), (TypeCode{TypeCategory::Integer, 8}.raw())); |
555 | EXPECT_EQ(res.GetDimension(0).LowerBound(), 1); |
556 | EXPECT_EQ(res.GetDimension(0).UpperBound(), 3); |
557 | EXPECT_EQ(*res.ZeroBasedIndexedElement<SubscriptValue>(0), 0); |
558 | EXPECT_EQ(*res.ZeroBasedIndexedElement<SubscriptValue>(1), 1); |
559 | EXPECT_EQ(*res.ZeroBasedIndexedElement<SubscriptValue>(2), 0); |
560 | res.Destroy(); |
561 | RTNAME(FindlocDim) |
562 | (res, *realArray, target, 8, /*DIM=*/2, __FILE__, __LINE__, nullptr, |
563 | /*BACK=*/true); |
564 | EXPECT_EQ(res.rank(), 1); |
565 | EXPECT_EQ(res.type().raw(), (TypeCode{TypeCategory::Integer, 8}.raw())); |
566 | EXPECT_EQ(res.GetDimension(0).LowerBound(), 1); |
567 | EXPECT_EQ(res.GetDimension(0).UpperBound(), 2); |
568 | EXPECT_EQ(*res.ZeroBasedIndexedElement<SubscriptValue>(0), 2); |
569 | EXPECT_EQ(*res.ZeroBasedIndexedElement<SubscriptValue>(1), 0); |
570 | res.Destroy(); |
571 | // Test scalar result for FindlocDim. |
572 | // A scalar result occurs when you have a rank 1 array, value, and dim == 1. |
573 | std::vector<int> shape1{6}; |
574 | auto realArray1{MakeArray<TypeCategory::Real, 8>(shape1, |
575 | std::vector<double>{0.0, -0.0, 1.0, 3.14, |
576 | std::numeric_limits<double>::quiet_NaN(), |
577 | std::numeric_limits<double>::infinity()})}; |
578 | StaticDescriptor<1, true> statDesc0[1]; |
579 | Descriptor &scalarResult{statDesc0[0].descriptor()}; |
580 | RTNAME(FindlocDim) |
581 | (scalarResult, *realArray1, target, 8, /*DIM=*/1, __FILE__, __LINE__, nullptr, |
582 | /*BACK=*/false); |
583 | EXPECT_EQ(scalarResult.rank(), 0); |
584 | EXPECT_EQ(*scalarResult.ZeroBasedIndexedElement<SubscriptValue>(0), 3); |
585 | scalarResult.Destroy(); |
586 | } |
587 | |
588 | TEST(Reductions, DotProduct) { |
589 | auto realVector{MakeArray<TypeCategory::Real, 8>( |
590 | std::vector<int>{4}, std::vector<double>{0.0, -0.0, 1.0, -2.0})}; |
591 | EXPECT_EQ( |
592 | RTNAME(DotProductReal8)(*realVector, *realVector, __FILE__, __LINE__), |
593 | 5.0); |
594 | auto complexVector{MakeArray<TypeCategory::Complex, 4>(std::vector<int>{4}, |
595 | std::vector<std::complex<float>>{ |
596 | {0.0}, {-0.0, -0.0}, {1.0, -2.0}, {-2.0, 4.0}})}; |
597 | std::complex<double> result8; |
598 | RTNAME(CppDotProductComplex8) |
599 | (result8, *realVector, *complexVector, __FILE__, __LINE__); |
600 | EXPECT_EQ(result8, (std::complex<double>{5.0, -10.0})); |
601 | RTNAME(CppDotProductComplex8) |
602 | (result8, *complexVector, *realVector, __FILE__, __LINE__); |
603 | EXPECT_EQ(result8, (std::complex<double>{5.0, 10.0})); |
604 | std::complex<float> result4; |
605 | RTNAME(CppDotProductComplex4) |
606 | (result4, *complexVector, *complexVector, __FILE__, __LINE__); |
607 | EXPECT_EQ(result4, (std::complex<float>{25.0, 0.0})); |
608 | auto logicalVector1{MakeArray<TypeCategory::Logical, 1>( |
609 | std::vector<int>{4}, std::vector<bool>{false, false, true, true})}; |
610 | EXPECT_TRUE(RTNAME(DotProductLogical)( |
611 | *logicalVector1, *logicalVector1, __FILE__, __LINE__)); |
612 | auto logicalVector2{MakeArray<TypeCategory::Logical, 1>( |
613 | std::vector<int>{4}, std::vector<bool>{true, true, false, false})}; |
614 | EXPECT_TRUE(RTNAME(DotProductLogical)( |
615 | *logicalVector2, *logicalVector2, __FILE__, __LINE__)); |
616 | EXPECT_FALSE(RTNAME(DotProductLogical)( |
617 | *logicalVector1, *logicalVector2, __FILE__, __LINE__)); |
618 | EXPECT_FALSE(RTNAME(DotProductLogical)( |
619 | *logicalVector2, *logicalVector1, __FILE__, __LINE__)); |
620 | } |
621 | |
622 | #if LDBL_MANT_DIG == 113 || HAS_FLOAT128 |
623 | TEST(Reductions, ExtremaReal16) { |
624 | // The identity value for Min/Maxval for REAL(16) was mistakenly |
625 | // set to 0.0. |
626 | using ElemType = CppTypeFor<TypeCategory::Real, 16>; |
627 | std::vector<int> shape{3}; |
628 | // 1.0 2.0 3.0 |
629 | std::vector<ElemType> rawMinData{1.0, 2.0, 3.0}; |
630 | auto minArray{MakeArray<TypeCategory::Real, 16>(shape, rawMinData)}; |
631 | EXPECT_EQ(RTNAME(MinvalReal16)(*minArray, __FILE__, __LINE__), 1.0); |
632 | // -1.0 -2.0 -3.0 |
633 | std::vector<ElemType> rawMaxData{-1.0, -2.0, -3.0}; |
634 | auto maxArray{MakeArray<TypeCategory::Real, 16>(shape, rawMaxData)}; |
635 | EXPECT_EQ(RTNAME(MaxvalReal16)(*maxArray, __FILE__, __LINE__), -1.0); |
636 | } |
637 | #endif // LDBL_MANT_DIG == 113 || HAS_FLOAT128 |
638 | |
639 | static std::int32_t IAdd(const std::int32_t *x, const std::int32_t *y) { |
640 | return *x + *y; |
641 | } |
642 | |
643 | static std::int32_t IMultiply(const std::int32_t *x, const std::int32_t *y) { |
644 | return *x * *y; |
645 | } |
646 | |
647 | TEST(Reductions, ReduceInt4) { |
648 | auto intVector{MakeArray<TypeCategory::Integer, 4>( |
649 | std::vector<int>{4}, std::vector<std::int32_t>{1, 2, 3, 4})}; |
650 | EXPECT_EQ(RTNAME(ReduceInteger4)(*intVector, IAdd, __FILE__, __LINE__), 10); |
651 | EXPECT_EQ( |
652 | RTNAME(ReduceInteger4)(*intVector, IMultiply, __FILE__, __LINE__), 24); |
653 | } |
654 | TEST(Reductions, ReduceInt4Dim) { |
655 | auto intMatrix{MakeArray<TypeCategory::Integer, 4>( |
656 | std::vector<int>{2, 2}, std::vector<std::int32_t>{1, 2, 3, 4})}; |
657 | StaticDescriptor<1, true> statDesc; |
658 | Descriptor &sums{statDesc.descriptor()}; |
659 | RTNAME(ReduceInteger4Dim)(sums, *intMatrix, IAdd, __FILE__, __LINE__, 1); |
660 | EXPECT_EQ(sums.rank(), 1); |
661 | EXPECT_EQ(sums.GetDimension(0).LowerBound(), 1); |
662 | EXPECT_EQ(sums.GetDimension(0).Extent(), 2); |
663 | EXPECT_EQ(*sums.ZeroBasedIndexedElement<std::int32_t>(0), 3); |
664 | EXPECT_EQ(*sums.ZeroBasedIndexedElement<std::int32_t>(1), 7); |
665 | sums.Destroy(); |
666 | RTNAME(ReduceInteger4Dim)(sums, *intMatrix, IAdd, __FILE__, __LINE__, 2); |
667 | EXPECT_EQ(sums.rank(), 1); |
668 | EXPECT_EQ(sums.GetDimension(0).LowerBound(), 1); |
669 | EXPECT_EQ(sums.GetDimension(0).Extent(), 2); |
670 | EXPECT_EQ(*sums.ZeroBasedIndexedElement<std::int32_t>(0), 4); |
671 | EXPECT_EQ(*sums.ZeroBasedIndexedElement<std::int32_t>(1), 6); |
672 | sums.Destroy(); |
673 | } |
674 | |