1 //===-- flang/unittests/RuntimeGTest/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 RTNAME(MinlocDim) 162 (scalarResult, *array1, /*KIND=*/2, /*DIM=*/1, __FILE__, __LINE__, 163 /*MASK=*/nullptr, /*BACK=*/true); 164 EXPECT_EQ(scalarResult.rank(), 0); 165 EXPECT_EQ(*scalarResult.ZeroBasedIndexedElement<std::int16_t>(0), 22); 166 scalarResult.Destroy(); 167 RTNAME(MaxvalDim) 168 (scalarResult, *array1, /*DIM=*/1, __FILE__, __LINE__, /*MASK=*/nullptr); 169 EXPECT_EQ(scalarResult.rank(), 0); 170 EXPECT_EQ(*scalarResult.ZeroBasedIndexedElement<double>(0), 22.0); 171 scalarResult.Destroy(); 172 RTNAME(MinvalDim) 173 (scalarResult, *array1, /*DIM=*/1, __FILE__, __LINE__, /*MASK=*/nullptr); 174 EXPECT_EQ(scalarResult.rank(), 0); 175 EXPECT_EQ(*scalarResult.ZeroBasedIndexedElement<double>(0), -21.0); 176 scalarResult.Destroy(); 177 } 178 179 TEST(Reductions, Character) { 180 std::vector<int> shape{2, 3}; 181 auto array{MakeArray<TypeCategory::Character, 1>(shape, 182 std::vector<std::string>{"abc", "def", "ghi", "jkl", "mno", "abc"}, 3)}; 183 StaticDescriptor<1, true> statDesc[2]; 184 Descriptor &res{statDesc[0].descriptor()}; 185 RTNAME(MaxvalCharacter)(res, *array, __FILE__, __LINE__); 186 EXPECT_EQ(res.rank(), 0); 187 EXPECT_EQ(res.type().raw(), (TypeCode{TypeCategory::Character, 1}.raw())); 188 EXPECT_EQ(std::memcmp(res.OffsetElement<char>(), "mno", 3), 0); 189 res.Destroy(); 190 RTNAME(MinvalCharacter)(res, *array, __FILE__, __LINE__); 191 EXPECT_EQ(res.rank(), 0); 192 EXPECT_EQ(res.type().raw(), (TypeCode{TypeCategory::Character, 1}.raw())); 193 EXPECT_EQ(std::memcmp(res.OffsetElement<char>(), "abc", 3), 0); 194 res.Destroy(); 195 RTNAME(Maxloc) 196 (res, *array, /*KIND=*/4, __FILE__, __LINE__, /*MASK=*/nullptr, 197 /*BACK=*/false); 198 EXPECT_EQ(res.rank(), 1); 199 EXPECT_EQ(res.type().raw(), (TypeCode{TypeCategory::Integer, 4}.raw())); 200 EXPECT_EQ(res.GetDimension(0).LowerBound(), 1); 201 EXPECT_EQ(res.GetDimension(0).Extent(), 2); 202 EXPECT_EQ(*res.ZeroBasedIndexedElement<std::int32_t>(0), 1); 203 EXPECT_EQ(*res.ZeroBasedIndexedElement<std::int32_t>(1), 3); 204 res.Destroy(); 205 auto mask{MakeArray<TypeCategory::Logical, 1>( 206 shape, std::vector<bool>{false, true, false, true, false, true})}; 207 RTNAME(Maxloc) 208 (res, *array, /*KIND=*/4, __FILE__, __LINE__, /*MASK=*/&*mask, 209 /*BACK=*/false); 210 EXPECT_EQ(res.rank(), 1); 211 EXPECT_EQ(res.type().raw(), (TypeCode{TypeCategory::Integer, 4}.raw())); 212 EXPECT_EQ(res.GetDimension(0).LowerBound(), 1); 213 EXPECT_EQ(res.GetDimension(0).Extent(), 2); 214 EXPECT_EQ(*res.ZeroBasedIndexedElement<std::int32_t>(0), 2); 215 EXPECT_EQ(*res.ZeroBasedIndexedElement<std::int32_t>(1), 2); 216 res.Destroy(); 217 RTNAME(Minloc) 218 (res, *array, /*KIND=*/4, __FILE__, __LINE__, /*MASK=*/nullptr, 219 /*BACK=*/false); 220 EXPECT_EQ(res.rank(), 1); 221 EXPECT_EQ(res.type().raw(), (TypeCode{TypeCategory::Integer, 4}.raw())); 222 EXPECT_EQ(res.GetDimension(0).LowerBound(), 1); 223 EXPECT_EQ(res.GetDimension(0).Extent(), 2); 224 EXPECT_EQ(*res.ZeroBasedIndexedElement<std::int32_t>(0), 1); 225 EXPECT_EQ(*res.ZeroBasedIndexedElement<std::int32_t>(1), 1); 226 res.Destroy(); 227 RTNAME(Minloc) 228 (res, *array, /*KIND=*/4, __FILE__, __LINE__, /*MASK=*/nullptr, 229 /*BACK=*/true); 230 EXPECT_EQ(res.rank(), 1); 231 EXPECT_EQ(res.type().raw(), (TypeCode{TypeCategory::Integer, 4}.raw())); 232 EXPECT_EQ(res.GetDimension(0).LowerBound(), 1); 233 EXPECT_EQ(res.GetDimension(0).Extent(), 2); 234 EXPECT_EQ(*res.ZeroBasedIndexedElement<std::int32_t>(0), 2); 235 EXPECT_EQ(*res.ZeroBasedIndexedElement<std::int32_t>(1), 3); 236 res.Destroy(); 237 RTNAME(Minloc) 238 (res, *array, /*KIND=*/4, __FILE__, __LINE__, /*MASK=*/&*mask, 239 /*BACK=*/true); 240 EXPECT_EQ(res.rank(), 1); 241 EXPECT_EQ(res.type().raw(), (TypeCode{TypeCategory::Integer, 4}.raw())); 242 EXPECT_EQ(res.GetDimension(0).LowerBound(), 1); 243 EXPECT_EQ(res.GetDimension(0).Extent(), 2); 244 EXPECT_EQ(*res.ZeroBasedIndexedElement<std::int32_t>(0), 2); 245 EXPECT_EQ(*res.ZeroBasedIndexedElement<std::int32_t>(1), 3); 246 res.Destroy(); 247 static const char targetChar[]{"abc"}; 248 Descriptor &target{statDesc[1].descriptor()}; 249 target.Establish(1, std::strlen(targetChar), 250 const_cast<void *>(static_cast<const void *>(&targetChar)), 0, nullptr, 251 CFI_attribute_pointer); 252 RTNAME(Findloc) 253 (res, *array, target, /*KIND=*/4, __FILE__, __LINE__, nullptr, 254 /*BACK=*/false); 255 EXPECT_EQ(res.rank(), 1); 256 EXPECT_EQ(res.type().raw(), (TypeCode{TypeCategory::Integer, 4}.raw())); 257 EXPECT_EQ(res.GetDimension(0).LowerBound(), 1); 258 EXPECT_EQ(res.GetDimension(0).Extent(), 2); 259 EXPECT_EQ(*res.ZeroBasedIndexedElement<std::int32_t>(0), 1); 260 EXPECT_EQ(*res.ZeroBasedIndexedElement<std::int32_t>(1), 1); 261 res.Destroy(); 262 RTNAME(Findloc) 263 (res, *array, target, /*KIND=*/4, __FILE__, __LINE__, nullptr, /*BACK=*/true); 264 EXPECT_EQ(res.rank(), 1); 265 EXPECT_EQ(res.type().raw(), (TypeCode{TypeCategory::Integer, 4}.raw())); 266 EXPECT_EQ(res.GetDimension(0).LowerBound(), 1); 267 EXPECT_EQ(res.GetDimension(0).Extent(), 2); 268 EXPECT_EQ(*res.ZeroBasedIndexedElement<std::int32_t>(0), 2); 269 EXPECT_EQ(*res.ZeroBasedIndexedElement<std::int32_t>(1), 3); 270 res.Destroy(); 271 } 272 273 TEST(Reductions, Logical) { 274 std::vector<int> shape{2, 2}; 275 auto array{MakeArray<TypeCategory::Logical, 4>( 276 shape, std::vector<std::int32_t>{false, false, true, true})}; 277 ASSERT_EQ(array->ElementBytes(), std::size_t{4}); 278 EXPECT_EQ(RTNAME(All)(*array, __FILE__, __LINE__), false); 279 EXPECT_EQ(RTNAME(Any)(*array, __FILE__, __LINE__), true); 280 EXPECT_EQ(RTNAME(Parity)(*array, __FILE__, __LINE__), false); 281 EXPECT_EQ(RTNAME(Count)(*array, __FILE__, __LINE__), 2); 282 StaticDescriptor<2, true> statDesc[2]; 283 Descriptor &res{statDesc[0].descriptor()}; 284 RTNAME(AllDim)(res, *array, /*DIM=*/1, __FILE__, __LINE__); 285 EXPECT_EQ(res.rank(), 1); 286 EXPECT_EQ(res.type().raw(), (TypeCode{TypeCategory::Logical, 4}.raw())); 287 EXPECT_EQ(res.GetDimension(0).LowerBound(), 1); 288 EXPECT_EQ(res.GetDimension(0).Extent(), 2); 289 EXPECT_EQ(*res.ZeroBasedIndexedElement<std::int32_t>(0), 0); 290 EXPECT_EQ(*res.ZeroBasedIndexedElement<std::int32_t>(1), 1); 291 res.Destroy(); 292 RTNAME(AllDim)(res, *array, /*DIM=*/2, __FILE__, __LINE__); 293 EXPECT_EQ(res.rank(), 1); 294 EXPECT_EQ(res.type().raw(), (TypeCode{TypeCategory::Logical, 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), 0); 298 EXPECT_EQ(*res.ZeroBasedIndexedElement<std::int32_t>(1), 0); 299 res.Destroy(); 300 // Test scalar result for AllDim. 301 // A scalar result occurs when you have a rank 1 array. 302 std::vector<int> shape1{4}; 303 auto array1{MakeArray<TypeCategory::Logical, 4>( 304 shape1, std::vector<std::int32_t>{false, false, true, true})}; 305 StaticDescriptor<1, true> statDesc0[1]; 306 Descriptor &scalarResult{statDesc0[0].descriptor()}; 307 RTNAME(AllDim)(scalarResult, *array1, /*DIM=*/1, __FILE__, __LINE__); 308 EXPECT_EQ(scalarResult.rank(), 0); 309 EXPECT_EQ(*scalarResult.ZeroBasedIndexedElement<std::int32_t>(0), 0); 310 scalarResult.Destroy(); 311 RTNAME(AnyDim)(res, *array, /*DIM=*/1, __FILE__, __LINE__); 312 EXPECT_EQ(res.rank(), 1); 313 EXPECT_EQ(res.type().raw(), (TypeCode{TypeCategory::Logical, 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), 0); 317 EXPECT_EQ(*res.ZeroBasedIndexedElement<std::int32_t>(1), 1); 318 res.Destroy(); 319 RTNAME(AnyDim)(res, *array, /*DIM=*/2, __FILE__, __LINE__); 320 EXPECT_EQ(res.rank(), 1); 321 EXPECT_EQ(res.type().raw(), (TypeCode{TypeCategory::Logical, 4}.raw())); 322 EXPECT_EQ(res.GetDimension(0).LowerBound(), 1); 323 EXPECT_EQ(res.GetDimension(0).Extent(), 2); 324 EXPECT_EQ(*res.ZeroBasedIndexedElement<std::int32_t>(0), 1); 325 EXPECT_EQ(*res.ZeroBasedIndexedElement<std::int32_t>(1), 1); 326 res.Destroy(); 327 // Test scalar result for AnyDim. 328 // A scalar result occurs when you have a rank 1 array. 329 RTNAME(AnyDim)(scalarResult, *array1, /*DIM=*/1, __FILE__, __LINE__); 330 EXPECT_EQ(scalarResult.rank(), 0); 331 EXPECT_EQ(*scalarResult.ZeroBasedIndexedElement<std::int32_t>(0), 1); 332 scalarResult.Destroy(); 333 RTNAME(ParityDim)(res, *array, /*DIM=*/1, __FILE__, __LINE__); 334 EXPECT_EQ(res.rank(), 1); 335 EXPECT_EQ(res.type().raw(), (TypeCode{TypeCategory::Logical, 4}.raw())); 336 EXPECT_EQ(res.GetDimension(0).LowerBound(), 1); 337 EXPECT_EQ(res.GetDimension(0).Extent(), 2); 338 EXPECT_EQ(*res.ZeroBasedIndexedElement<std::int32_t>(0), 0); 339 EXPECT_EQ(*res.ZeroBasedIndexedElement<std::int32_t>(1), 0); 340 res.Destroy(); 341 RTNAME(ParityDim)(res, *array, /*DIM=*/2, __FILE__, __LINE__); 342 EXPECT_EQ(res.rank(), 1); 343 EXPECT_EQ(res.type().raw(), (TypeCode{TypeCategory::Logical, 4}.raw())); 344 EXPECT_EQ(res.GetDimension(0).LowerBound(), 1); 345 EXPECT_EQ(res.GetDimension(0).Extent(), 2); 346 EXPECT_EQ(*res.ZeroBasedIndexedElement<std::int32_t>(0), 1); 347 EXPECT_EQ(*res.ZeroBasedIndexedElement<std::int32_t>(1), 1); 348 res.Destroy(); 349 // Test scalar result for ParityDim. 350 // A scalar result occurs when you have a rank 1 array. 351 RTNAME(ParityDim)(scalarResult, *array1, /*DIM=*/1, __FILE__, __LINE__); 352 EXPECT_EQ(scalarResult.rank(), 0); 353 EXPECT_EQ(*scalarResult.ZeroBasedIndexedElement<std::int32_t>(0), 0); 354 scalarResult.Destroy(); 355 RTNAME(CountDim)(res, *array, /*DIM=*/1, /*KIND=*/4, __FILE__, __LINE__); 356 EXPECT_EQ(res.rank(), 1); 357 EXPECT_EQ(res.type().raw(), (TypeCode{TypeCategory::Integer, 4}.raw())); 358 EXPECT_EQ(res.GetDimension(0).LowerBound(), 1); 359 EXPECT_EQ(res.GetDimension(0).Extent(), 2); 360 EXPECT_EQ(*res.ZeroBasedIndexedElement<std::int32_t>(0), 0); 361 EXPECT_EQ(*res.ZeroBasedIndexedElement<std::int32_t>(1), 2); 362 res.Destroy(); 363 RTNAME(CountDim)(res, *array, /*DIM=*/2, /*KIND=*/8, __FILE__, __LINE__); 364 EXPECT_EQ(res.rank(), 1); 365 EXPECT_EQ(res.type().raw(), (TypeCode{TypeCategory::Integer, 8}.raw())); 366 EXPECT_EQ(res.GetDimension(0).LowerBound(), 1); 367 EXPECT_EQ(res.GetDimension(0).Extent(), 2); 368 EXPECT_EQ(*res.ZeroBasedIndexedElement<std::int64_t>(0), 1); 369 EXPECT_EQ(*res.ZeroBasedIndexedElement<std::int64_t>(1), 1); 370 res.Destroy(); 371 // Test scalar result for CountDim. 372 // A scalar result occurs when you have a rank 1 array and dim == 1. 373 RTNAME(CountDim) 374 (scalarResult, *array1, /*DIM=*/1, /*KIND=*/8, __FILE__, __LINE__); 375 EXPECT_EQ(scalarResult.rank(), 0); 376 EXPECT_EQ(*scalarResult.ZeroBasedIndexedElement<std::int64_t>(0), 2); 377 scalarResult.Destroy(); 378 bool boolValue{false}; 379 Descriptor &target{statDesc[1].descriptor()}; 380 target.Establish(TypeCategory::Logical, 1, static_cast<void *>(&boolValue), 0, 381 nullptr, CFI_attribute_pointer); 382 RTNAME(Findloc) 383 (res, *array, target, /*KIND=*/4, __FILE__, __LINE__, nullptr, 384 /*BACK=*/false); 385 EXPECT_EQ(res.rank(), 1); 386 EXPECT_EQ(res.type().raw(), (TypeCode{TypeCategory::Integer, 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), 1); 390 EXPECT_EQ(*res.ZeroBasedIndexedElement<std::int32_t>(1), 1); 391 res.Destroy(); 392 boolValue = true; 393 RTNAME(Findloc) 394 (res, *array, target, /*KIND=*/4, __FILE__, __LINE__, nullptr, /*BACK=*/true); 395 EXPECT_EQ(res.rank(), 1); 396 EXPECT_EQ(res.type().raw(), (TypeCode{TypeCategory::Integer, 4}.raw())); 397 EXPECT_EQ(res.GetDimension(0).LowerBound(), 1); 398 EXPECT_EQ(res.GetDimension(0).Extent(), 2); 399 EXPECT_EQ(*res.ZeroBasedIndexedElement<std::int32_t>(0), 2); 400 EXPECT_EQ(*res.ZeroBasedIndexedElement<std::int32_t>(1), 2); 401 res.Destroy(); 402 } 403 404 TEST(Reductions, FindlocNumeric) { 405 std::vector<int> shape{2, 3}; 406 auto realArray{MakeArray<TypeCategory::Real, 8>(shape, 407 std::vector<double>{0.0, -0.0, 1.0, 3.14, 408 std::numeric_limits<double>::quiet_NaN(), 409 std::numeric_limits<double>::infinity()})}; 410 ASSERT_EQ(realArray->ElementBytes(), sizeof(double)); 411 StaticDescriptor<2, true> statDesc[2]; 412 Descriptor &res{statDesc[0].descriptor()}; 413 // Find the first zero 414 Descriptor &target{statDesc[1].descriptor()}; 415 double value{0.0}; 416 target.Establish(TypeCategory::Real, 8, static_cast<void *>(&value), 0, 417 nullptr, CFI_attribute_pointer); 418 RTNAME(Findloc) 419 (res, *realArray, target, 8, __FILE__, __LINE__, nullptr, /*BACK=*/false); 420 EXPECT_EQ(res.rank(), 1); 421 EXPECT_EQ(res.type().raw(), (TypeCode{TypeCategory::Integer, 8}.raw())); 422 EXPECT_EQ(res.GetDimension(0).LowerBound(), 1); 423 EXPECT_EQ(res.GetDimension(0).UpperBound(), 2); 424 EXPECT_EQ(*res.ZeroBasedIndexedElement<SubscriptValue>(0), 1); 425 EXPECT_EQ(*res.ZeroBasedIndexedElement<SubscriptValue>(1), 1); 426 res.Destroy(); 427 // Find last zero (even though it's negative) 428 RTNAME(Findloc) 429 (res, *realArray, target, 8, __FILE__, __LINE__, nullptr, /*BACK=*/true); 430 EXPECT_EQ(res.rank(), 1); 431 EXPECT_EQ(res.type().raw(), (TypeCode{TypeCategory::Integer, 8}.raw())); 432 EXPECT_EQ(res.GetDimension(0).LowerBound(), 1); 433 EXPECT_EQ(res.GetDimension(0).UpperBound(), 2); 434 EXPECT_EQ(*res.ZeroBasedIndexedElement<SubscriptValue>(0), 2); 435 EXPECT_EQ(*res.ZeroBasedIndexedElement<SubscriptValue>(1), 1); 436 res.Destroy(); 437 // Find the +Inf 438 value = std::numeric_limits<double>::infinity(); 439 RTNAME(Findloc) 440 (res, *realArray, target, 8, __FILE__, __LINE__, nullptr, /*BACK=*/false); 441 EXPECT_EQ(res.rank(), 1); 442 EXPECT_EQ(res.type().raw(), (TypeCode{TypeCategory::Integer, 8}.raw())); 443 EXPECT_EQ(res.GetDimension(0).LowerBound(), 1); 444 EXPECT_EQ(res.GetDimension(0).UpperBound(), 2); 445 EXPECT_EQ(*res.ZeroBasedIndexedElement<SubscriptValue>(0), 2); 446 EXPECT_EQ(*res.ZeroBasedIndexedElement<SubscriptValue>(1), 3); 447 res.Destroy(); 448 // Ensure that we can't find a NaN 449 value = std::numeric_limits<double>::quiet_NaN(); 450 RTNAME(Findloc) 451 (res, *realArray, target, 8, __FILE__, __LINE__, nullptr, /*BACK=*/false); 452 EXPECT_EQ(res.rank(), 1); 453 EXPECT_EQ(res.type().raw(), (TypeCode{TypeCategory::Integer, 8}.raw())); 454 EXPECT_EQ(res.GetDimension(0).LowerBound(), 1); 455 EXPECT_EQ(res.GetDimension(0).UpperBound(), 2); 456 EXPECT_EQ(*res.ZeroBasedIndexedElement<SubscriptValue>(0), 0); 457 EXPECT_EQ(*res.ZeroBasedIndexedElement<SubscriptValue>(1), 0); 458 res.Destroy(); 459 // Find a value of a distinct type 460 int intValue{1}; 461 target.Establish(TypeCategory::Integer, 4, static_cast<void *>(&intValue), 0, 462 nullptr, CFI_attribute_pointer); 463 RTNAME(Findloc) 464 (res, *realArray, target, 8, __FILE__, __LINE__, nullptr, /*BACK=*/false); 465 EXPECT_EQ(res.rank(), 1); 466 EXPECT_EQ(res.type().raw(), (TypeCode{TypeCategory::Integer, 8}.raw())); 467 EXPECT_EQ(res.GetDimension(0).LowerBound(), 1); 468 EXPECT_EQ(res.GetDimension(0).UpperBound(), 2); 469 EXPECT_EQ(*res.ZeroBasedIndexedElement<SubscriptValue>(0), 1); 470 EXPECT_EQ(*res.ZeroBasedIndexedElement<SubscriptValue>(1), 2); 471 res.Destroy(); 472 // Partial reductions 473 value = 1.0; 474 target.Establish(TypeCategory::Real, 8, static_cast<void *>(&value), 0, 475 nullptr, CFI_attribute_pointer); 476 RTNAME(FindlocDim) 477 (res, *realArray, target, 8, /*DIM=*/1, __FILE__, __LINE__, nullptr, 478 /*BACK=*/false); 479 EXPECT_EQ(res.rank(), 1); 480 EXPECT_EQ(res.type().raw(), (TypeCode{TypeCategory::Integer, 8}.raw())); 481 EXPECT_EQ(res.GetDimension(0).LowerBound(), 1); 482 EXPECT_EQ(res.GetDimension(0).UpperBound(), 3); 483 EXPECT_EQ(*res.ZeroBasedIndexedElement<SubscriptValue>(0), 0); 484 EXPECT_EQ(*res.ZeroBasedIndexedElement<SubscriptValue>(1), 1); 485 EXPECT_EQ(*res.ZeroBasedIndexedElement<SubscriptValue>(2), 0); 486 res.Destroy(); 487 RTNAME(FindlocDim) 488 (res, *realArray, target, 8, /*DIM=*/2, __FILE__, __LINE__, nullptr, 489 /*BACK=*/true); 490 EXPECT_EQ(res.rank(), 1); 491 EXPECT_EQ(res.type().raw(), (TypeCode{TypeCategory::Integer, 8}.raw())); 492 EXPECT_EQ(res.GetDimension(0).LowerBound(), 1); 493 EXPECT_EQ(res.GetDimension(0).UpperBound(), 2); 494 EXPECT_EQ(*res.ZeroBasedIndexedElement<SubscriptValue>(0), 2); 495 EXPECT_EQ(*res.ZeroBasedIndexedElement<SubscriptValue>(1), 0); 496 res.Destroy(); 497 // Test scalar result for FindlocDim. 498 // A scalar result occurs when you have a rank 1 array, value, and dim == 1. 499 std::vector<int> shape1{6}; 500 auto realArray1{MakeArray<TypeCategory::Real, 8>(shape1, 501 std::vector<double>{0.0, -0.0, 1.0, 3.14, 502 std::numeric_limits<double>::quiet_NaN(), 503 std::numeric_limits<double>::infinity()})}; 504 StaticDescriptor<1, true> statDesc0[1]; 505 Descriptor &scalarResult{statDesc0[0].descriptor()}; 506 RTNAME(FindlocDim) 507 (scalarResult, *realArray1, target, 8, /*DIM=*/1, __FILE__, __LINE__, nullptr, 508 /*BACK=*/false); 509 EXPECT_EQ(scalarResult.rank(), 0); 510 EXPECT_EQ(*scalarResult.ZeroBasedIndexedElement<SubscriptValue>(0), 3); 511 scalarResult.Destroy(); 512 } 513 514 TEST(Reductions, DotProduct) { 515 auto realVector{MakeArray<TypeCategory::Real, 8>( 516 std::vector<int>{4}, std::vector<double>{0.0, -0.0, 1.0, -2.0})}; 517 EXPECT_EQ( 518 RTNAME(DotProductReal8)(*realVector, *realVector, __FILE__, __LINE__), 519 5.0); 520 auto complexVector{MakeArray<TypeCategory::Complex, 4>(std::vector<int>{4}, 521 std::vector<std::complex<float>>{ 522 {0.0}, {-0.0, -0.0}, {1.0, -2.0}, {-2.0, 4.0}})}; 523 std::complex<double> result8; 524 RTNAME(CppDotProductComplex8) 525 (result8, *realVector, *complexVector, __FILE__, __LINE__); 526 EXPECT_EQ(result8, (std::complex<double>{5.0, -10.0})); 527 RTNAME(CppDotProductComplex8) 528 (result8, *complexVector, *realVector, __FILE__, __LINE__); 529 EXPECT_EQ(result8, (std::complex<double>{5.0, 10.0})); 530 std::complex<float> result4; 531 RTNAME(CppDotProductComplex4) 532 (result4, *complexVector, *complexVector, __FILE__, __LINE__); 533 EXPECT_EQ(result4, (std::complex<float>{25.0, 0.0})); 534 auto logicalVector1{MakeArray<TypeCategory::Logical, 1>( 535 std::vector<int>{4}, std::vector<bool>{false, false, true, true})}; 536 EXPECT_TRUE(RTNAME(DotProductLogical)( 537 *logicalVector1, *logicalVector1, __FILE__, __LINE__)); 538 auto logicalVector2{MakeArray<TypeCategory::Logical, 1>( 539 std::vector<int>{4}, std::vector<bool>{true, true, false, false})}; 540 EXPECT_TRUE(RTNAME(DotProductLogical)( 541 *logicalVector2, *logicalVector2, __FILE__, __LINE__)); 542 EXPECT_FALSE(RTNAME(DotProductLogical)( 543 *logicalVector1, *logicalVector2, __FILE__, __LINE__)); 544 EXPECT_FALSE(RTNAME(DotProductLogical)( 545 *logicalVector2, *logicalVector1, __FILE__, __LINE__)); 546 } 547