traversal.cc 6.98 KB
Newer Older
sangwzh's avatar
sangwzh committed
1
// !!! This is a file automatically generated by hipify!!!
2
/**
3
 *  Copyright (c) 2020 by Contributors
4
5
 * @file array/cpu/traversal.cc
 * @brief Graph traversal implementation
6
7
 */

sangwzh's avatar
sangwzh committed
8
#include "traversal.h"
9

10
#include <dgl/graph_traversal.h>
11

12
13
14
15
16
17
18
19
#include <algorithm>
#include <queue>

namespace dgl {
namespace aten {
namespace impl {
namespace {
// A utility view class to wrap a vector into a queue.
20
template <typename DType>
21
22
23
24
struct VectorQueueWrapper {
  std::vector<DType>* vec;
  size_t head = 0;

25
  explicit VectorQueueWrapper(std::vector<DType>* vec) : vec(vec) {}
26

27
  void push(const DType& elem) { vec->push_back(elem); }
28

29
  DType top() const { return vec->operator[](head); }
30

31
  void pop() { ++head; }
32

33
  bool empty() const { return head == vec->size(); }
34

35
  size_t size() const { return vec->size() - head; }
36
37
38
39
};

// Internal function to merge multiple traversal traces into one ndarray.
// It is similar to zip the vectors together.
40
41
template <typename DType>
IdArray MergeMultipleTraversals(const std::vector<std::vector<DType>>& traces) {
42
43
44
45
46
47
  int64_t max_len = 0, total_len = 0;
  for (size_t i = 0; i < traces.size(); ++i) {
    const int64_t tracelen = traces[i].size();
    max_len = std::max(max_len, tracelen);
    total_len += traces[i].size();
  }
48
49
50
  IdArray ret = IdArray::Empty(
      {total_len}, DGLDataType{kDGLInt, sizeof(DType) * 8, 1},
      DGLContext{kDGLCPU, 0});
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
  DType* ret_data = static_cast<DType*>(ret->data);
  for (int64_t i = 0; i < max_len; ++i) {
    for (size_t j = 0; j < traces.size(); ++j) {
      const int64_t tracelen = traces[j].size();
      if (i >= tracelen) {
        continue;
      }
      *(ret_data++) = traces[j][i];
    }
  }
  return ret;
}

// Internal function to compute sections if multiple traversal traces
// are merged into one ndarray.
66
67
template <typename DType>
IdArray ComputeMergedSections(const std::vector<std::vector<DType>>& traces) {
68
69
70
71
72
  int64_t max_len = 0;
  for (size_t i = 0; i < traces.size(); ++i) {
    const int64_t tracelen = traces[i].size();
    max_len = std::max(max_len, tracelen);
  }
73
74
  IdArray ret = IdArray::Empty(
      {max_len}, DGLDataType{kDGLInt, 64, 1}, DGLContext{kDGLCPU, 0});
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
  int64_t* ret_data = static_cast<int64_t*>(ret->data);
  for (int64_t i = 0; i < max_len; ++i) {
    int64_t sec_len = 0;
    for (size_t j = 0; j < traces.size(); ++j) {
      const int64_t tracelen = traces[j].size();
      if (i < tracelen) {
        ++sec_len;
      }
    }
    *(ret_data++) = sec_len;
  }
  return ret;
}

}  // namespace

91
template <DGLDeviceType XPU, typename IdType>
92
93
94
95
Frontiers BFSNodesFrontiers(const CSRMatrix& csr, IdArray source) {
  std::vector<IdType> ids;
  std::vector<int64_t> sections;
  VectorQueueWrapper<IdType> queue(&ids);
96
97
98
99
100
101
102
  auto visit = [&](const int64_t v) {};
  auto make_frontier = [&]() {
    if (!queue.empty()) {
      // do not push zero-length frontier
      sections.push_back(queue.size());
    }
  };
103
104
105
106
107
108
109
110
  BFSTraverseNodes<IdType>(csr, source, &queue, visit, make_frontier);

  Frontiers front;
  front.ids = VecToIdArray(ids, sizeof(IdType) * 8);
  front.sections = VecToIdArray(sections, sizeof(int64_t) * 8);
  return front;
}

111
112
113
114
template Frontiers BFSNodesFrontiers<kDGLCPU, int32_t>(
    const CSRMatrix&, IdArray);
template Frontiers BFSNodesFrontiers<kDGLCPU, int64_t>(
    const CSRMatrix&, IdArray);
115

116
template <DGLDeviceType XPU, typename IdType>
117
118
119
120
121
122
Frontiers BFSEdgesFrontiers(const CSRMatrix& csr, IdArray source) {
  std::vector<IdType> ids;
  std::vector<int64_t> sections;
  // NOTE: std::queue has no top() method.
  std::vector<IdType> nodes;
  VectorQueueWrapper<IdType> queue(&nodes);
123
  auto visit = [&](const IdType e) { ids.push_back(e); };
124
125
  bool first_frontier = true;
  auto make_frontier = [&] {
126
127
128
129
130
131
132
    if (first_frontier) {
      first_frontier = false;  // do not push the first section when doing edges
    } else if (!queue.empty()) {
      // do not push zero-length frontier
      sections.push_back(queue.size());
    }
  };
133
134
135
136
137
138
139
140
  BFSTraverseEdges<IdType>(csr, source, &queue, visit, make_frontier);

  Frontiers front;
  front.ids = VecToIdArray(ids, sizeof(IdType) * 8);
  front.sections = VecToIdArray(sections, sizeof(int64_t) * 8);
  return front;
}

141
142
143
144
template Frontiers BFSEdgesFrontiers<kDGLCPU, int32_t>(
    const CSRMatrix&, IdArray);
template Frontiers BFSEdgesFrontiers<kDGLCPU, int64_t>(
    const CSRMatrix&, IdArray);
145

146
template <DGLDeviceType XPU, typename IdType>
147
148
149
150
Frontiers TopologicalNodesFrontiers(const CSRMatrix& csr) {
  std::vector<IdType> ids;
  std::vector<int64_t> sections;
  VectorQueueWrapper<IdType> queue(&ids);
151
152
153
154
155
156
157
  auto visit = [&](const uint64_t v) {};
  auto make_frontier = [&]() {
    if (!queue.empty()) {
      // do not push zero-length frontier
      sections.push_back(queue.size());
    }
  };
158
159
160
161
162
163
164
165
  TopologicalNodes<IdType>(csr, &queue, visit, make_frontier);

  Frontiers front;
  front.ids = VecToIdArray(ids, sizeof(IdType) * 8);
  front.sections = VecToIdArray(sections, sizeof(int64_t) * 8);
  return front;
}

166
167
168
169
template Frontiers TopologicalNodesFrontiers<kDGLCPU, int32_t>(
    const CSRMatrix&);
template Frontiers TopologicalNodesFrontiers<kDGLCPU, int64_t>(
    const CSRMatrix&);
170

171
template <DGLDeviceType XPU, typename IdType>
172
173
174
175
176
177
Frontiers DGLDFSEdges(const CSRMatrix& csr, IdArray source) {
  const int64_t len = source->shape[0];
  const IdType* src_data = static_cast<IdType*>(source->data);
  std::vector<std::vector<IdType>> edges(len);

  for (int64_t i = 0; i < len; ++i) {
178
    auto visit = [&](IdType e, int tag) { edges[i].push_back(e); };
179
180
181
182
183
184
185
186
187
    DFSLabeledEdges<IdType>(csr, src_data[i], false, false, visit);
  }

  Frontiers front;
  front.ids = MergeMultipleTraversals(edges);
  front.sections = ComputeMergedSections(edges);
  return front;
}

188
189
template Frontiers DGLDFSEdges<kDGLCPU, int32_t>(const CSRMatrix&, IdArray);
template Frontiers DGLDFSEdges<kDGLCPU, int64_t>(const CSRMatrix&, IdArray);
190

191
template <DGLDeviceType XPU, typename IdType>
192
193
194
Frontiers DGLDFSLabeledEdges(
    const CSRMatrix& csr, IdArray source, const bool has_reverse_edge,
    const bool has_nontree_edge, const bool return_labels) {
195
196
197
198
199
200
201
202
203
204
  const int64_t len = source->shape[0];
  const IdType* src_data = static_cast<IdType*>(source->data);
  std::vector<std::vector<IdType>> edges(len);
  std::vector<std::vector<int64_t>> tags;

  if (return_labels) {
    tags.resize(len);
  }

  for (int64_t i = 0; i < len; ++i) {
205
    auto visit = [&](IdType e, int64_t tag) {
206
207
208
209
210
      edges[i].push_back(e);
      if (return_labels) {
        tags[i].push_back(tag);
      }
    };
211
212
    DFSLabeledEdges<IdType>(
        csr, src_data[i], has_reverse_edge, has_nontree_edge, visit);
213
214
215
216
217
218
219
220
221
222
223
224
  }

  Frontiers front;
  front.ids = MergeMultipleTraversals(edges);
  front.sections = ComputeMergedSections(edges);
  if (return_labels) {
    front.tags = MergeMultipleTraversals(tags);
  }

  return front;
}

225
226
227
228
template Frontiers DGLDFSLabeledEdges<kDGLCPU, int32_t>(
    const CSRMatrix&, IdArray, const bool, const bool, const bool);
template Frontiers DGLDFSLabeledEdges<kDGLCPU, int64_t>(
    const CSRMatrix&, IdArray, const bool, const bool, const bool);
229
230
231
232

}  // namespace impl
}  // namespace aten
}  // namespace dgl