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 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 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 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 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 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 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 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