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