fps.cpp 1.48 KB
Newer Older
rusty1s's avatar
rusty1s committed
1
2
#include <torch/extension.h>

rusty1s's avatar
rusty1s committed
3
#include "compat.h"
rusty1s's avatar
rusty1s committed
4
5
6
7
8
9
10
#include "utils.h"

at::Tensor get_dist(at::Tensor x, ptrdiff_t index) {
  return (x - x[index]).norm(2, 1);
}

at::Tensor fps(at::Tensor x, at::Tensor batch, float ratio, bool random) {
rusty1s's avatar
rusty1s committed
11
  auto batch_size = batch[-1].DATA_PTR<int64_t>()[0] + 1;
rusty1s's avatar
rusty1s committed
12
13
14
15
16
17

  auto deg = degree(batch, batch_size);
  auto cum_deg = at::cat({at::zeros(1, deg.options()), deg.cumsum(0)}, 0);
  auto k = (deg.toType(at::kFloat) * ratio).ceil().toType(at::kLong);
  auto cum_k = at::cat({at::zeros(1, k.options()), k.cumsum(0)}, 0);

rusty1s's avatar
rusty1s committed
18
  auto out = at::empty(cum_k[-1].DATA_PTR<int64_t>()[0], batch.options());
rusty1s's avatar
rusty1s committed
19

rusty1s's avatar
rusty1s committed
20
21
22
23
  auto cum_deg_d = cum_deg.DATA_PTR<int64_t>();
  auto k_d = k.DATA_PTR<int64_t>();
  auto cum_k_d = cum_k.DATA_PTR<int64_t>();
  auto out_d = out.DATA_PTR<int64_t>();
rusty1s's avatar
rusty1s committed
24
25
26
27
28
29
30

  for (ptrdiff_t b = 0; b < batch_size; b++) {
    auto index = at::range(cum_deg_d[b], cum_deg_d[b + 1] - 1, out.options());
    auto y = x.index_select(0, index);

    ptrdiff_t start = 0;
    if (random) {
rusty1s's avatar
rusty1s committed
31
      start = at::randperm(y.size(0), batch.options()).DATA_PTR<int64_t>()[0];
rusty1s's avatar
rusty1s committed
32
33
34
35
36
37
    }

    out_d[cum_k_d[b]] = cum_deg_d[b] + start;
    auto dist = get_dist(y, start);

    for (ptrdiff_t i = 1; i < k_d[b]; i++) {
rusty1s's avatar
rusty1s committed
38
      ptrdiff_t argmax = dist.argmax().DATA_PTR<int64_t>()[0];
rusty1s's avatar
rusty1s committed
39
40
41
42
43
44
45
46
47
48
49
      out_d[cum_k_d[b] + i] = cum_deg_d[b] + argmax;
      dist = at::min(dist, get_dist(y, argmax));
    }
  }

  return out;
}

PYBIND11_MODULE(TORCH_EXTENSION_NAME, m) {
  m.def("fps", &fps, "Farthest Point Sampling (CPU)");
}