1 //===-- flang/unittests/Runtime/Reductions.cpp ----------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 #include "flang/Runtime/reduction.h"
10 #include "gtest/gtest.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"
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);
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
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);
69 for (auto x
: rawData
) {
72 naiveNorm2
= std::sqrt(naiveNorm2
);
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()};
79 (loc
, *array
, /*KIND=*/8, __FILE__
, __LINE__
, /*MASK=*/nullptr,
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);
86 *array
->Element
<double>(loc
.ZeroBasedIndexedElement
<SubscriptValue
>(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);
93 (loc
, *array
, /*KIND=*/8, __FILE__
, __LINE__
, /*MASK=*/nullptr,
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);
100 *array
->Element
<double>(loc
.ZeroBasedIndexedElement
<SubscriptValue
>(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);
107 (loc
, *array
, /*KIND=*/2, /*DIM=*/1, __FILE__
, __LINE__
, /*MASK=*/nullptr,
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
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})};
129 (loc
, *array
, /*KIND=*/2, /*DIM=*/3, __FILE__
, __LINE__
, /*MASK=*/&*mask
,
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
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()};
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})};
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);
180 // Test .TRUE. scalar MASK argument
181 auto trueMask
{MakeArray
<TypeCategory::Logical
, 4>(
182 std::vector
<int>{}, std::vector
<std::int32_t>{1})};
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);
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
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);
222 // Test .TRUE. scalar MASK argument
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);
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();
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);
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);
268 RTNAME(MaxlocCharacter
)
269 (res
, *array
, /*KIND=*/4, __FILE__
, __LINE__
, /*MASK=*/nullptr,
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);
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
,
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);
290 RTNAME(MinlocCharacter
)
291 (res
, *array
, /*KIND=*/4, __FILE__
, __LINE__
, /*MASK=*/nullptr,
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);
300 RTNAME(MinlocCharacter
)
301 (res
, *array
, /*KIND=*/4, __FILE__
, __LINE__
, /*MASK=*/nullptr,
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);
310 RTNAME(MinlocCharacter
)
311 (res
, *array
, /*KIND=*/4, __FILE__
, __LINE__
, /*MASK=*/&*mask
,
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);
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
);
326 (res
, *array
, target
, /*KIND=*/4, __FILE__
, __LINE__
, nullptr,
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
444 // Test scalar result for CountDim.
445 // A scalar result occurs when you have a rank 1 array and dim == 1.
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
);
456 (res
, *array
, target
, /*KIND=*/4, __FILE__
, __LINE__
, nullptr,
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);
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);
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()};
489 target
.Establish(TypeCategory::Real
, 8, static_cast<void *>(&value
), 0,
490 nullptr, CFI_attribute_pointer
);
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);
500 // Find last zero (even though it's negative)
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);
511 value
= std::numeric_limits
<double>::infinity();
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);
521 // Ensure that we can't find a NaN
522 value
= std::numeric_limits
<double>::quiet_NaN();
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);
532 // Find a value of a distinct type
534 target
.Establish(TypeCategory::Integer
, 4, static_cast<void *>(&intValue
), 0,
535 nullptr, CFI_attribute_pointer
);
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);
545 // Partial reductions
547 target
.Establish(TypeCategory::Real
, 8, static_cast<void *>(&value
), 0,
548 nullptr, CFI_attribute_pointer
);
550 (res
, *realArray
, target
, 8, /*DIM=*/1, __FILE__
, __LINE__
, nullptr,
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);
561 (res
, *realArray
, target
, 8, /*DIM=*/2, __FILE__
, __LINE__
, nullptr,
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);
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()};
580 (scalarResult
, *realArray1
, target
, 8, /*DIM=*/1, __FILE__
, __LINE__
, nullptr,
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})};
591 RTNAME(DotProductReal8
)(*realVector
, *realVector
, __FILE__
, __LINE__
),
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
625 using ElemType
= CppTypeFor
<TypeCategory::Real
, 16>;
626 std::vector
<int> shape
{3};
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);
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