用于使用 igraph C 库
以下短示例程序演示了 igraph 库的基本用法。将其保存到名为 igraph_test.c
的文件中。
#include <igraph.h> int main(void) { igraph_integer_t num_vertices = 1000; igraph_integer_t num_edges = 1000; igraph_real_t diameter; igraph_t graph; igraph_rng_seed(igraph_rng_default(), 42); igraph_erdos_renyi_game_gnm( &graph, num_vertices, num_edges, IGRAPH_UNDIRECTED, IGRAPH_NO_LOOPS ); igraph_diameter( &graph, &diameter, /* from = */ NULL, /* to = */ NULL, /* vertex_path = */ NULL, /* edge_path = */ NULL, IGRAPH_UNDIRECTED, /* unconn= */ true ); printf("Diameter of a random graph with average degree %g: %g\n", 2.0 * igraph_ecount(&graph) / igraph_vcount(&graph), (double) diameter); igraph_destroy(&graph); return 0; }
此示例说明了几个要点
首先,使用 igraph 库的程序应包含 igraph.h
头文件。
其次,igraph 使用 igraph_integer_t 类型表示整数,而不是 int 或 long int,并且它还使用 igraph_real_t 类型表示实数,而不是 double。根据 igraph 的编译方式以及您使用的是 32 位还是 64 位系统,igraph_integer_t 可能是 32 位或 64 位整数。
第三,igraph 图对象由 igraph_t 数据类型表示。
第四,igraph_erdos_renyi_game_gnm()
创建一个图,igraph_destroy()
销毁它,即释放与其关联的内存。
要编译此程序,您需要一个 C 编译器。或者,可以使用 CMake 自动执行编译。
使用 CMake 很方便,因为它可以自动发现所有操作系统上必需的编译标志。许多 IDE 支持 CMake,并且可以直接使用 CMake 项目。要为此示例程序创建一个 CMake 项目,请创建一个名为 CMakeLists.txt
的文件,其内容如下
cmake_minimum_required(VERSION 3.18) project(igraph_test) find_package(igraph REQUIRED) add_executable(igraph_test igraph_test.c) target_link_libraries(igraph_test PUBLIC igraph::igraph)
要编译该项目,请在 igraph 源代码树的根目录中创建一个名为 build
的新目录,然后切换到该目录
mkdir build cd build
运行 CMake 来配置项目
cmake ..
如果 igraph 安装在非标准位置,请使用 -DCMAKE_PREFIX_PATH=...
选项指定其前缀。前缀必须与编译 igraph 时指定的 CMAKE_INSTALL_PREFIX
目录相同。
如果配置成功,请使用以下命令构建程序
cmake --build .
igraph 的一部分是用 C++ 实现的;因此,任何依赖于 igraph 的 CMake 目标都应使用 C++ 链接器。此外,仅当 CMake 项目中启用了 C++ 时,igraph 中的 OpenMP 支持才能正常工作。如果在 CMake 项目中未启用 C++ 支持,则在主机上查找 igraph 的脚本将引发错误。
默认情况下,当 CMake 的 project
命令中未显式指定任何语言时,将启用 C++ 支持,例如 project(igraph_test)
。如果您确实显式指定了一些语言,请确保还包括 CXX
,例如 project(igraph_test C CXX)
。
在大多数类 Unix 系统上,默认的 C 编译器称为 cc。要编译测试程序,您需要类似于以下内容的命令
cc igraph_test.c -I/usr/local/include/igraph -L/usr/local/lib -ligraph -o igraph_test
确切的形式取决于 igraph 安装在您系统上的位置,它是作为共享库还是静态库编译的,以及它链接到的外部库。 -I
开关后的目录是包含 igraph.h
文件的目录,而 -L
之后的目录应包含库文件本身,通常是名为 libigraph.a
(macOS 和 Linux 上的静态库), libigraph.so
(Linux 上的共享库), libigraph.dylib
(macOS 上的共享库), igraph.lib
(Windows 上的静态库) 或 igraph.dll
(Windows 上的共享库) 的文件。如果 igraph 是作为静态库编译的,则还需要手动链接到其所有依赖项。
如果您的系统具有 pkg-config 实用程序,则可以通过发出以下命令来获取必要的编译选项
pkg-config --libs --cflags igraph
(如果 igraph 是作为共享库构建的) 或
pkg-config --static --libs --cflags igraph
(如果 igraph 是作为静态库构建的)。
生成图对象的函数称为图生成器。随机(即随机化)图生成器称为 “游戏”。
igraph 可以处理有向图和无向图。大多数图生成器都能够创建这两种类型的图,并且大多数其他函数通常也能够处理这两种图。例如,igraph_get_shortest_paths()
,它计算从一个顶点到其他顶点的最短路径,可以计算有向或无向路径。
igraph 具有创建图的复杂方法。最简单的图是确定性规则结构,例如星形图 (igraph_star()
), 环形图 (igraph_ring()
), 格子 (igraph_square_lattice()
) 或树 (igraph_kary_tree()
)。
以下示例创建一个无向规则圆形格子,向其添加一些随机边,并计算在添加随机边之前和之后图中所有顶点对之间最短路径的平均长度。(消息是,一些随机边可以大大缩短路径长度。)
#include <igraph.h> int main(void) { igraph_t graph; igraph_vector_int_t dimvector; igraph_vector_int_t edges; igraph_vector_bool_t periodic; igraph_real_t avg_path_len; igraph_vector_int_init(&dimvector, 2); VECTOR(dimvector)[0]=30; VECTOR(dimvector)[1]=30; igraph_vector_bool_init(&periodic, 2); igraph_vector_bool_fill(&periodic, true); igraph_square_lattice(&graph, &dimvector, 0, IGRAPH_UNDIRECTED, /* mutual= */ false, &periodic); igraph_average_path_length(&graph, &avg_path_len, NULL, IGRAPH_UNDIRECTED, /* unconn= */ true); printf("Average path length (lattice): %g\n", (double) avg_path_len); igraph_rng_seed(igraph_rng_default(), 42); /* seed RNG before first use */ igraph_vector_int_init(&edges, 20); for (igraph_integer_t i=0; i < igraph_vector_int_size(&edges); i++) { VECTOR(edges)[i] = RNG_INTEGER(0, igraph_vcount(&graph) - 1); } igraph_add_edges(&graph, &edges, NULL); igraph_average_path_length(&graph, &avg_path_len, NULL, IGRAPH_UNDIRECTED, /* unconn= */ true); printf("Average path length (randomized lattice): %g\n", (double) avg_path_len); igraph_vector_bool_destroy(&periodic); igraph_vector_int_destroy(&dimvector); igraph_vector_int_destroy(&edges); igraph_destroy(&graph); return 0; }
此示例说明了一些新要点。igraph 使用 igraph_vector_t 及其相关类型 (igraph_vector_int_t, igraph_vector_bool_t 等) 代替纯 C 数组。 igraph_vector_t 在几乎所有方面都优于常规数组。向量由 igraph_vector_init()
函数创建,并且像图一样,如果不再需要它们,应通过调用 igraph_vector_destroy()
来销毁它们。可以使用 VECTOR()
函数(现在它是一个宏)索引向量。对于 igraph_vector_t,向量的元素类型为 igraph_real_t,对于 igraph_vector_int_t,向量的元素类型为 igraph_integer_t。正如您可能期望的那样,igraph_vector_bool_t 保存 igraph_bool_t 值。可以调整向量的大小,并且大多数 igraph 函数将结果返回到向量中会自动调整其大小以达到它们需要的大小。
igraph_square_lattice()
接受一个整数向量参数,用于指定格子的维度。在此示例中,我们生成一个 30x30 的二维周期性格子。有关其他参数,请参阅参考手册中 igraph_square_lattice()
的文档。
图中的顶点由 顶点 ID 标识,顶点 ID 是 0
和 n - 1
之间的整数,其中 n
是图中顶点的数量。可以使用 igraph_vcount()
检索顶点计数,如示例所示。
igraph_add_edges()
函数只是接受一个图和一个顶点 ID 向量,用于定义新边。第一条边位于向量中的前两个顶点 ID 之间,第二条边位于后两个顶点 ID 之间,依此类推。通过这种方式,我们将十条随机边添加到格子中。
请注意,此示例程序可能会添加 环边,即指向顶点自身的边,或 多重边,即同一顶点对之间的多个边。igraph_t 当然可以表示环和多重边,尽管某些例程需要简单图,即不包含任何这些边的图。这是因为某些结构属性对于非简单图来说定义不明确。可以通过调用 igraph_simplify()
来删除环和多重边。
在我们的下一个示例中,我们将计算友谊图中的各种中心性度量。友谊图来自著名的 Zachary 空手道俱乐部研究。(如果您想了解更多信息,请在网上搜索“Zachary 空手道”。)中心性度量量化了图中各个顶点的位置的中心性。
#include <igraph.h> int main(void) { igraph_t graph; igraph_vector_int_t v; igraph_vector_int_t result; igraph_vector_t result_real; igraph_integer_t edges[] = { 0,1, 0,2, 0,3, 0,4, 0,5, 0,6, 0,7, 0,8, 0,10, 0,11, 0,12, 0,13, 0,17, 0,19, 0,21, 0,31, 1, 2, 1, 3, 1, 7, 1,13, 1,17, 1,19, 1,21, 1,30, 2, 3, 2, 7, 2,27, 2,28, 2,32, 2, 9, 2, 8, 2,13, 3, 7, 3,12, 3,13, 4, 6, 4,10, 5, 6, 5,10, 5,16, 6,16, 8,30, 8,32, 8,33, 9,33, 13,33, 14,32, 14,33, 15,32, 15,33, 18,32, 18,33, 19,33, 20,32, 20,33, 22,32, 22,33, 23,25, 23,27, 23,32, 23,33, 23,29, 24,25, 24,27, 24,31, 25,31, 26,29, 26,33, 27,33, 28,31, 28,33, 29,32, 29,33, 30,32, 30,33, 31,32, 31,33, 32,33 }; igraph_vector_int_view(&v, edges, sizeof(edges) / sizeof(edges[0])); igraph_create(&graph, &v, 0, IGRAPH_UNDIRECTED); igraph_vector_int_init(&result, 0); igraph_vector_init(&result_real, 0); igraph_degree(&graph, &result, igraph_vss_all(), IGRAPH_ALL, IGRAPH_LOOPS); printf("Maximum degree is %10" IGRAPH_PRId ", vertex %2" IGRAPH_PRId ".\n", igraph_vector_int_max(&result), igraph_vector_int_which_max(&result)); igraph_closeness(&graph, &result_real, NULL, NULL, igraph_vss_all(), IGRAPH_ALL, /* weights= */ NULL, /* normalized= */ false); printf("Maximum closeness is %10g, vertex %2" IGRAPH_PRId ".\n", (double) igraph_vector_max(&result_real), igraph_vector_which_max(&result_real)); igraph_betweenness(&graph, &result_real, igraph_vss_all(), IGRAPH_UNDIRECTED, /* weights= */ NULL); printf("Maximum betweenness is %10g, vertex %2" IGRAPH_PRId ".\n", (double) igraph_vector_max(&result_real), igraph_vector_which_max(&result_real)); igraph_vector_int_destroy(&result); igraph_vector_destroy(&result_real); igraph_destroy(&graph); return 0; }
此示例演示了一些新操作。首先,它展示了一种创建图的方法,该图是由存储在纯 C 数组中的边列表创建的。函数 igraph_vector_view()
创建 C 数组的视图。它不会复制任何数据,这意味着您不能在此方法创建的向量上调用 igraph_vector_destroy()
。然后,此向量用于创建无向图。
然后,计算顶点的度数、接近度和介数中心性,并打印最高值。请注意,必须首先初始化向量 result
,这些函数将结果写入该向量中,并且这些函数还会调整其大小以能够保存结果。
请注意,为了打印 igraph_integer_t 类型的值,我们使用了 IGRAPH_PRId
格式宏常量。此宏类似于 stdint.h
中定义的标准 PRI
常量,并且在 igraph 支持的每个平台上扩展为正确的 printf
格式说明符。
igraph_vss_all()
参数告诉函数计算图中每个顶点的属性。它是 顶点选择器 的简写,由类型 igraph_vs_t 表示。顶点选择器有助于对顶点的子集执行操作。您可以在以下章节之一中阅读有关它们的更多信息。
← 第 2 章。 安装 | 第 4 章。 基本数据类型和接口 → |