Metis
安装
官方文档
方法一:Metis从安装到使用全教程(Linux): 这个里面有使用介绍,但是安装后,可以按照教程例子测试了。如果需要在程序中调用,好像不好使,可能是需要配置环境变量啥的。
方法二:ubuntu安装metis: 简单暴力,好用,适合需要在代码中调用的需求。
sudo apt-get install libmetis-dev
安装完,仍然需要做如下配置:
include/metis.h 中修改以下代码,做到与自己计算机位数匹配(32bit or 64 bit).
不知道位置的可以按如下查询:
whereis metis # 查找命令
metis: /usr/include/metis.h
sudo vim /usr/include/metis.h
//if your system is 64 bit.
#define IDXTYPEWIDTH 64
//if your system is 32 bit
#define IDXTYPEWIDTH 32
示例
图划分软件Metis的使用
数据集
7 11
5 3 2
1 3 4
5 4 2 1
2 3 6 7
1 3 6
5 4 7
6 4
7 11 001
5 1 3 2 2 1
1 1 3 2 4 1
5 3 4 2 2 2 1 2
2 1 3 2 6 2 7 5
1 1 3 3 6 2
5 2 4 2 7 6
6 6 4 5
注意上面的提供的代码是邻接表格式的,第一行表示顶点和表的边的数量(7,11),后面每行表示行号对应的顶点的邻居点及边权,例如,第二行表示第一个顶点的三条边: 1->(5,1),1->(3,2), 1->(2,1)。
然而Metis接收的数据格式是CSR,相关介绍见:稀疏矩阵存储格式总结+存储效率对比:COO,CSR,DIA,ELL,HYB. 下面的示例代码中完成了格式的转换。
代码:
#include <metis.h>
#include <vector>
#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
using namespace std;
vector<idx_t> func(vector<idx_t> &xadj, vector<idx_t> &adjncy, vector<idx_t> &adjwgt, decltype(METIS_PartGraphKway) *METIS_PartGraphFunc) {
idx_t nVertices = xadj.size() - 1; // 节点数
idx_t nEdges = adjncy.size() / 2; // 边数
idx_t nWeights = 1; // 节点权重维数
idx_t nParts = 2; // 子图个数≥2
idx_t objval; // 目标函数值
vector<idx_t> part(nVertices, 0); // 划分结果
int ret = METIS_PartGraphFunc(&nVertices, &nWeights, xadj.data(), adjncy.data(),
NULL, NULL, adjwgt.data(), &nParts, NULL,
NULL, NULL, &objval, part.data());
if (ret != rstatus_et::METIS_OK) { cout << "METIS_ERROR" << endl; }
cout << "METIS_OK" << endl;
cout << "objval: " << objval << endl;
for (unsigned part_i = 0; part_i < part.size(); part_i++) {
cout << part_i + 1 << " " << part[part_i] << endl;
}
return part;
}
int main() {
ifstream ingraph("graph.txt");
int vexnum, edgenum;
string line;
getline(ingraph, line);
istringstream tmp(line);
tmp >> vexnum >> edgenum;
vector<idx_t> xadj(0);
vector<idx_t> adjncy(0); // 压缩图表示
vector<idx_t> adjwgt(0); // 节点权重
idx_t a, w;
for (int i = 0; i < vexnum; i++) {
xadj.push_back(adjncy.size()); // 对应csr的: row offsets, csr格式见:https://www.cnblogs.com/xbinworld/p/4273506.html
getline(ingraph, line);
istringstream tmp(line);
while (tmp >> a >> w) {
adjncy.push_back(a - 1); // 节点id从0开始 // column indices
adjwgt.push_back(w); // values
}
}
xadj.push_back(adjncy.size());
ingraph.close();
vector<idx_t> part = func(xadj, adjncy, adjwgt, METIS_PartGraphRecursive);
//vector<idx_t> part = func(xadj, adjncy, adjwgt, METIS_PartGraphKway);
ofstream outpartition("partition.txt");
for (int i = 0; i < part.size(); i++) { outpartition << i + 1 << " " << part[i] << endl; }
outpartition.close();
return 0;
}
运行命令:
g++ test2.cc -lmetis
./a.out
运行结果:
METIS_OK
objval: 5
1 1
2 1
3 1
4 0
5 1
6 0
7 0
相关接口函数
Parmetis
安装
官网
官方PDF!!!
方案一:
Installing and using the ParMetis library
c++ - ParMETIS:对 `ParMETIS_V3_PartMeshKway’的 undefined reference
方案二:
sudo apt-get install libparmetis-dev # 安装
mpic++ test_parmetis.cc -lparmetis # 运行案例
pymetis
摘抄自
PyMetis is a Python wrapper for the Metis graph partititioning software by George Karypis, Vipin Kumar and others. It includes version 5.1.0 of Metis and wraps it using the Pybind11 wrapper generator library. So far, it only wraps the most basic graph partitioning functionality (which is enough for my current use), but extending it in case you need more should be quite straightforward. Using PyMetis to partition your meshes is really easy–essentially all you need to pass into PyMetis is an adjacency list for the graph and the number of parts you would like.
例子
import numpy as np
import pymetis
adjacency_list = [np.array([4, 2, 1]),
np.array([0, 2, 3]),
np.array([4, 3, 1, 0]),
np.array([1, 2, 5, 6]),
np.array([0, 2, 5]),
np.array([4, 3, 6]),
np.array([5, 3])]
n_cuts, membership = pymetis.part_graph(2, adjacency=adjacency_list)
# n_cuts = 3
# membership = [1, 1, 1, 0, 1, 0, 0]
nodes_part_0 = np.argwhere(np.array(membership) == 0).ravel() # [3, 5, 6]
nodes_part_1 = np.argwhere(np.array(membership) == 1).ravel() # [0, 1, 2, 4]
part_graph
def part_graph(nparts, adjacency=None, xadj=None, adjncy=None,
vweights=None, eweights=None, recursive=None):
"""Return a partition (cutcount, part_vert) into nparts for an input graph.
The input graph is given in either a Pythonic way as the `adjacency' parameter
or in the direct C-like way that Metis likes as `xadj' and `adjncy'. It
is an error to specify both graph inputs.
The Pythonic graph specifier `adjacency' is required to have the following
properties:
- len(adjacency) needs to return the number of vertices
- adjacency[i] needs to be an iterable of vertices adjacent to vertex i.
Both directions of an undirected graph edge are required to be stored.
If you would like to use *eweights* (edge weights), you need to use the
xadj/adjncy way of specifying graph connectivity. This works as follows:
The adjacency structure of the graph is stored as follows: The
adjacency list of vertex *i* is stored in array *adjncy* starting at
index ``xadj[i]`` and ending at (but not including) index ``xadj[i +
1]``. That is, for each vertex i, its adjacency list is stored in
consecutive locations in the array *adjncy*, and the array *xadj* is
used to point to where it begins and where it ends.
The weights of the edges (if any) are stored in an additional array
called *eweights*. This array contains *2m* elements (where *m* is the
number of edges, taking into account the undirected nature of the
graph), and the weight of edge ``adjncy[j]`` is stored at location
``adjwgt[j]``. The edge-weights must be integers greater than zero. If
all the edges of the graph have the same weight (i.e., the graph is
unweighted), then the adjwgt can be set to ``None``.
(quoted with slight adaptations from the Metis docs)
"""
xadj, adjncy = _prepare_graph(adjacency, xadj, adjncy)
if recursive is None:
if nparts > 8:
recursive = False
else:
recursive = True
from pymetis._internal import part_graph
if nparts == 1:
# metis has a bug in this case--it disregards the index base
return 0, [0] * (len(xadj)-1)
return part_graph(nparts, xadj, adjncy, vweights, eweights, recursive)