metis_partition.cc 3.77 KB
Newer Older
1
/**
2
 *  Copyright (c) 2020 by Contributors
3
4
 * @file graph/metis_partition.cc
 * @brief Call Metis partitioning
5
6
 */

7
#include <dgl/graph_op.h>
8
#include <dgl/packed_func_ext.h>
9
10
#include <metis.h>

11
#include "../c_api_common.h"
12

13
14
15
16
using namespace dgl::runtime;

namespace dgl {

17
18
#if !defined(_WIN32)

19
IdArray MetisPartition(GraphPtr g, int k, NDArray vwgt_arr, bool obj_cut) {
20
21
22
23
24
25
26
27
  // The index type of Metis needs to be compatible with DGL index type.
  CHECK_EQ(sizeof(idx_t), sizeof(dgl_id_t));
  ImmutableGraphPtr ig = std::dynamic_pointer_cast<ImmutableGraph>(g);
  CHECK(ig) << "The input graph must be an immutable graph.";
  // This is a symmetric graph, so in-csr and out-csr are the same.
  const auto mat = ig->GetInCSR()->ToCSRMatrix();

  idx_t nvtxs = g->NumVertices();
28
29
30
  idx_t ncon = 1;  // # balacing constraints.
  idx_t *xadj = static_cast<idx_t *>(mat.indptr->data);
  idx_t *adjncy = static_cast<idx_t *>(mat.indices->data);
31
32
33
  idx_t nparts = k;
  IdArray part_arr = aten::NewIdArray(nvtxs);
  idx_t objval = 0;
34
  idx_t *part = static_cast<idx_t *>(part_arr->data);
35
36
37
38
39
40
41
42
43

  int64_t vwgt_len = vwgt_arr->shape[0];
  CHECK_EQ(sizeof(idx_t), vwgt_arr->dtype.bits / 8)
      << "The vertex weight array doesn't have right type";
  CHECK(vwgt_len % g->NumVertices() == 0)
      << "The vertex weight array doesn't have right number of elements";
  idx_t *vwgt = NULL;
  if (vwgt_len > 0) {
    ncon = vwgt_len / g->NumVertices();
44
    vwgt = static_cast<idx_t *>(vwgt_arr->data);
45
46
  }

Da Zheng's avatar
Da Zheng committed
47
48
49
  idx_t options[METIS_NOPTIONS];
  METIS_SetDefaultOptions(options);
  options[METIS_OPTION_ONDISK] = 1;
50
51
52
  options[METIS_OPTION_NITER] = 1;
  options[METIS_OPTION_NIPARTS] = 1;
  options[METIS_OPTION_DROPEDGES] = 1;
Da Zheng's avatar
Da Zheng committed
53

54
55
56
57
58
59
  if (obj_cut) {
    options[METIS_OPTION_OBJTYPE] = METIS_OBJTYPE_CUT;
  } else {
    options[METIS_OPTION_OBJTYPE] = METIS_OBJTYPE_VOL;
  }

60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
  int ret = METIS_PartGraphKway(
      &nvtxs,  // The number of vertices
      &ncon,   // The number of balancing constraints.
      xadj,    // indptr
      adjncy,  // indices
      vwgt,    // the weights of the vertices
      NULL,    // The size of the vertices for computing
      // the total communication volume
      NULL,     // The weights of the edges
      &nparts,  // The number of partitions.
      NULL,     // the desired weight for each partition and constraint
      NULL,     // the allowed load imbalance tolerance
      options,  // the array of options
      &objval,  // the edge-cut or the total communication volume of
      // the partitioning solution
      part);
76
77
78
79
80
81
82
83
84
85
86

  if (obj_cut) {
    LOG(INFO) << "Partition a graph with " << g->NumVertices() << " nodes and "
              << g->NumEdges() << " edges into " << k << " parts and "
              << "get " << objval << " edge cuts";
  } else {
    LOG(INFO) << "Partition a graph with " << g->NumVertices() << " nodes and "
              << g->NumEdges() << " edges into " << k << " parts and "
              << "the communication volume is " << objval;
  }

87
88
89
90
91
92
93
94
95
96
97
98
99
100
  switch (ret) {
    case METIS_OK:
      return part_arr;
    case METIS_ERROR_INPUT:
      LOG(FATAL) << "Error in Metis partitioning: input error";
    case METIS_ERROR_MEMORY:
      LOG(FATAL) << "Error in Metis partitioning: cannot allocate memory";
    default:
      LOG(FATAL) << "Error in Metis partitioning: other errors";
  }
  // return an array of 0 elements to indicate the error.
  return aten::NullArray();
}

101
102
#endif  // !defined(_WIN32)

103
DGL_REGISTER_GLOBAL("transform._CAPI_DGLMetisPartition")
104
105
106
107
108
    .set_body([](DGLArgs args, DGLRetValue *rv) {
      GraphRef g = args[0];
      int k = args[1];
      NDArray vwgt = args[2];
      bool obj_cut = args[3];
109
#if !defined(_WIN32)
110
      *rv = MetisPartition(g.sptr(), k, vwgt, obj_cut);
111
#else
112
      LOG(FATAL) << "Metis partition does not support Windows.";
113
#endif  // !defined(_WIN32)
114
    });
115

116
}  // namespace dgl