File: test_algorithm.cu

package info (click to toggle)
xgboost 3.0.0-1
  • links: PTS, VCS
  • area: main
  • in suites: trixie
  • size: 13,796 kB
  • sloc: cpp: 67,502; python: 35,503; java: 4,676; ansic: 1,426; sh: 1,320; xml: 1,197; makefile: 204; javascript: 19
file content (95 lines) | stat: -rw-r--r-- 3,417 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
/**
 * Copyright 2023 by XGBoost Contributors
 */
#include <gtest/gtest.h>
#include <thrust/copy.h>      // copy
#include <thrust/sequence.h>  // sequence
#include <thrust/sort.h>      // is_sorted

#include <algorithm>          // is_sorted
#include <cstddef>            // size_t

#include "../../../src/common/algorithm.cuh"
#include "../../../src/common/device_helpers.cuh"
#include "../helpers.h"  // MakeCUDACtx

namespace xgboost {
namespace common {
void TestSegmentedArgSort() {
  auto ctx = MakeCUDACtx(0);

  size_t constexpr kElements = 100, kGroups = 3;
  dh::device_vector<size_t> sorted_idx(kElements, 0);
  dh::device_vector<size_t> offset_ptr(kGroups + 1, 0);
  offset_ptr[0] = 0;
  offset_ptr[1] = 2;
  offset_ptr[2] = 78;
  offset_ptr[kGroups] = kElements;
  auto d_offset_ptr = dh::ToSpan(offset_ptr);

  auto d_sorted_idx = dh::ToSpan(sorted_idx);
  dh::LaunchN(sorted_idx.size(), [=] XGBOOST_DEVICE(size_t idx) {
    auto group = dh::SegmentId(d_offset_ptr, idx);
    d_sorted_idx[idx] = idx - d_offset_ptr[group];
  });

  dh::device_vector<float> values(kElements, 0.0f);
  thrust::sequence(values.begin(), values.end(), 0.0f);
  SegmentedArgSort<false, true>(&ctx, dh::ToSpan(values), d_offset_ptr, d_sorted_idx);

  std::vector<size_t> h_sorted_index(sorted_idx.size());
  thrust::copy(sorted_idx.begin(), sorted_idx.end(), h_sorted_index.begin());

  for (size_t i = 1; i < kGroups + 1; ++i) {
    auto group_sorted_idx = common::Span<size_t>(h_sorted_index)
                                .subspan(offset_ptr[i - 1], offset_ptr[i] - offset_ptr[i - 1]);
    ASSERT_TRUE(std::is_sorted(group_sorted_idx.begin(), group_sorted_idx.end(), std::greater<>{}));
    ASSERT_EQ(group_sorted_idx.back(), 0);
    for (auto j : group_sorted_idx) {
      ASSERT_LT(j, group_sorted_idx.size());
    }
  }
}

TEST(Algorithm, SegmentedArgSort) { TestSegmentedArgSort(); }

TEST(Algorithm, GpuArgSort) {
  auto ctx = MakeCUDACtx(0);

  dh::device_vector<float> values(20);
  dh::Iota(dh::ToSpan(values), ctx.CUDACtx()->Stream());  // accending
  dh::device_vector<size_t> sorted_idx(20);
  ArgSort<false>(&ctx, dh::ToSpan(values), dh::ToSpan(sorted_idx));  // sort to descending
  ASSERT_TRUE(thrust::is_sorted(ctx.CUDACtx()->CTP(), sorted_idx.begin(), sorted_idx.end(),
                                thrust::greater<size_t>{}));

  dh::Iota(dh::ToSpan(values), ctx.CUDACtx()->Stream());
  dh::device_vector<size_t> groups(3);
  groups[0] = 0;
  groups[1] = 10;
  groups[2] = 20;
  SegmentedArgSort<false, false>(&ctx, dh::ToSpan(values), dh::ToSpan(groups),
                                 dh::ToSpan(sorted_idx));
  ASSERT_FALSE(thrust::is_sorted(thrust::device, sorted_idx.begin(), sorted_idx.end(),
                                 thrust::greater<size_t>{}));
  ASSERT_TRUE(
      thrust::is_sorted(sorted_idx.begin(), sorted_idx.begin() + 10, thrust::greater<size_t>{}));
  ASSERT_TRUE(
      thrust::is_sorted(sorted_idx.begin() + 10, sorted_idx.end(), thrust::greater<size_t>{}));
}

TEST(Algorithm, SegmentedSequence) {
  dh::device_vector<std::size_t> idx(16);
  dh::device_vector<std::size_t> ptr(3);
  Context ctx = MakeCUDACtx(0);
  ptr[0] = 0;
  ptr[1] = 4;
  ptr[2] = idx.size();
  SegmentedSequence(&ctx, dh::ToSpan(ptr), dh::ToSpan(idx));
  ASSERT_EQ(idx[0], 0);
  ASSERT_EQ(idx[4], 0);
  ASSERT_EQ(idx[3], 3);
  ASSERT_EQ(idx[15], 11);
}
}  // namespace common
}  // namespace xgboost