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