igraph 参考手册

用于使用 igraph C 库

搜索手册

第 31 章。高级 igraph 编程

1. 在多线程程序中使用 igraph

如果 igraph 库已启用线程局部存储编译,即 IGRAPH_ENABLE_TLS 设置已切换为 ON 且当前平台支持此功能,则认为该库是线程安全的。要检查 igraph 构建是否为线程安全,请使用 IGRAPH_THREAD_SAFE 宏。链接到 igraph 依赖项的外部版本时,用户有责任检查这些依赖项是否也编译为线程安全。

1.1. IGRAPH_THREAD_SAFE — 指定 igraph 是否以线程安全模式构建。

#define IGRAPH_THREAD_SAFE 

如果当前 igraph 库的构建以线程安全模式构建,则此宏定义为 1,如果不是,则定义为 0。线程安全的 igraph 库尝试使用线程局部数据结构而不是全局数据结构,但请注意,这不能(并且无法)保证 igraph 链接到的第三方库。

1.2. 线程安全的 ARPACK 库

请注意,igraph 只有在使用内部 ARPACK 库(即 igraph 附带的库)构建时才是线程安全的。标准的 ARPACK 库不是线程安全的。

1.3. 随机数生成器的线程安全性

igraph 使用的默认随机数生成器 保证是线程安全的。您需要为要从中使用的每个线程设置不同的随机数生成器实例。如果您设置随机数生成器的种子以确保可重复性,这一点尤其重要;在线程之间共享随机数生成器会破坏可重复性,因为各种线程的调度顺序是随机的,因此它们仍然会从共享的随机数生成器以不可预测的顺序接收随机数。

2. 进度处理程序

2.1.  关于进度处理程序

报告某些长时间计算的进度通常很有用,以便用户可以跟踪计算并猜测总运行时间。在编写本文时,一些 igraph 函数支持此功能,希望将来会有更多函数支持此功能。

要查看计算的进度,用户必须安装进度处理程序,因为默认情况下未安装任何进度处理程序。如果 igraph 函数支持进度报告,则它会定期调用已安装的进度处理程序,并将百分比值传递给它,即已执行的计算的百分比。要安装进度处理程序,您需要调用 igraph_set_progress_handler()。目前有一个预定义的进度处理程序,称为 igraph_progress_handler_stderr()

2.2. 设置进度处理程序

2.2.1. igraph_progress_handler_t — 进度处理程序函数的类型

typedef igraph_error_t igraph_progress_handler_t(const char *message, igraph_real_t percent,
                                      void *data);

这是 igraph 进度处理程序函数的类型。目前有一个这样的预定义函数,igraph_progress_handler_stderr(),但用户可以编写和设置更复杂的函数。

参数: 

message:

一个字符串,描述报告进度的函数或算法。如果从同一个函数报告,则当前的 igraph 函数始终使用名称 message 参数。

percent:

数字,算法或函数完成的百分比。

数据:

用户定义的数据。报告进度的当前 igraph 函数在此处传递一个空指针。用户可以编写自己的进度处理程序和具有进度报告的函数,然后在此处传递一些有意义的上下文。

返回值: 

如果进度处理程序的返回值不是 IGRAPH_SUCCESS,则 igraph_progress() 返回错误代码 IGRAPH_INTERRUPTED。在这种情况下,IGRAPH_PROGRESS() 宏释放所有内存并以错误代码 IGRAPH_INTERRUPTED 完成 igraph 函数。

2.2.2. igraph_set_progress_handler — 安装进度处理程序,或删除当前处理程序。

igraph_progress_handler_t *
igraph_set_progress_handler(igraph_progress_handler_t new_handler);

有一个简单的预定义进度处理程序:igraph_progress_handler_stderr()

参数: 

new_handler:

指向 igraph_progress_handler_t 类型的函数的指针,要安装的进度处理程序函数。要卸载当前的进度处理程序,此参数可以是一个空指针。

返回值: 

指向先前安装的进度处理程序函数的指针。

时间复杂度:O(1)。

2.2.3. igraph_progress_handler_stderr — 一个简单的预定义进度处理程序。

igraph_error_t igraph_progress_handler_stderr(const char *message, igraph_real_t percent,
                                   void* data);

这个简单的进度处理程序首先打印 message,然后在简短消息中将完成百分比值打印到标准错误。

参数: 

message:

一个字符串,描述报告进度的函数或算法。如果从同一个函数报告,则当前的 igraph 函数始终使用相同的 message 参数。

percent:

数字,算法或函数完成的百分比。

数据:

用户定义的数据。报告进度的当前 igraph 函数在此处传递一个空指针。用户可以编写自己的进度处理程序和具有进度报告的函数,然后在此处传递一些有意义的上下文。

返回值: 

此函数始终返回 IGRAPH_SUCCESS

时间复杂度:O(1)。

2.3. 调用进度处理程序

2.3.1. IGRAPH_PROGRESS — 报告进度。

#define IGRAPH_PROGRESS(message, percent, data)

从 igraph 函数报告进度的标准方法

参数: 

message:

字符串,引用正在进行的计算的文本消息。

percent:

数值标量,已完成的百分比。

数据:

用户定义的数据,这可以在用户定义的进度处理程序函数中使用,来自用户编写的 igraph 函数。

返回值: 

如果进度处理程序返回 IGRAPH_INTERRUPTED,则此宏释放 igraph 为临时数据分配的内存,并以 IGRAPH_INTERRUPTED 返回给调用方。

2.3.2. igraph_progress — 报告进度

igraph_error_t igraph_progress(const char *message, igraph_real_t percent, void *data);

请注意,报告进度的常用方法是 IGRAPH_PROGRESS 宏,因为它处理进度处理程序的返回值。

参数: 

message:

一个字符串,描述报告进度的函数或算法。如果从同一个函数报告,则当前的 igraph 函数始终使用名称 message 参数。

percent:

数字,算法或函数完成的百分比。

数据:

用户定义的数据。报告进度的当前 igraph 函数在此处传递一个空指针。用户可以编写自己的进度处理程序和具有进度报告的函数,然后在此处传递一些有意义的上下文。

返回值: 

如果安装了进度处理程序并且未返回 IGRAPH_SUCCESS,则返回 IGRAPH_INTERRUPTED

时间复杂度:O(1)。

2.3.3. igraph_progressf — 报告进度,类似于 printf 的版本

igraph_error_t igraph_progressf(const char *message, igraph_real_t percent, void *data,
                     ...);

这是 igraph_progress() 的更灵活的版本,带有类似于 printf 的模板字符串。首先用附加参数填充模板字符串,然后调用 igraph_progress()

请注意,message 字符串的长度有一个上限,目前为 1000 个字符。

参数: 

message:

一个字符串,描述报告进度的函数或算法。对于此函数,这是一个模板字符串,使用与标准 libc printf 函数相同的语法。

percent:

数字,算法或函数完成的百分比。

数据:

用户定义的数据。报告进度的当前 igraph 函数在此处传递一个空指针。用户可以编写自己的进度处理程序和具有进度报告的函数,然后在此处传递一些有意义的上下文。

...:

message 参数中指定的附加参数。

返回值: 

如果安装了进度处理程序并且未返回 IGRAPH_SUCCESS,则返回 IGRAPH_INTERRUPTED。 \return

2.4.  编写进度处理程序

要编写新的进度处理程序,需要创建 igraph_progress_handler_t 类型的函数。然后可以使用 igraph_set_progress_handler() 函数安装新的进度处理程序。

可以假设来自计算的第一个进度处理程序调用将以零作为 percentage 参数调用,并且来自函数的最后一个调用将以 100 作为 percentage 参数。但是请注意,如果在计算过程中发生错误,则可能会省略 100 个百分比调用。

2.5.  编写具有进度报告的 igraph 函数

如果要编写使用 igraph 并支持进度报告的函数,则需要在函数中包含 igraph_progress() 调用,通常通过 IGRAPH_PROGRESS() 宏。

好的做法是在计算之前始终包含对 igraph_progress() 的调用,并将 percentage 参数设置为零;并在计算完成后,另一次调用 percentage 值设置为 100。

同样好的做法是不要过于频繁地调用 igraph_progress(),因为这会减慢计算速度。在线性或对数线性时间复杂度的函数中可能不值得支持进度报告,因为即使有大量数据,它们也很快。对于具有二次或更高时间复杂度的函数,请确保进度报告的时间复杂度是恒定的或至少是线性的。实际上,这意味着最多具有 O(n) 个进度检查,并且最多 100 个 igraph_progress() 调用。

2.6.  多线程程序

在多线程程序中,如果支持线程局部存储并且 igraph 是线程安全的,则每个线程都有自己的进度处理程序。有关检查 igraph 构建是否为线程安全,请参见 IGRAPH_THREAD_SAFE 宏。

3. 状态处理程序

3.1.  状态报告

除了可以通过 igraph_progress() 报告 igraph 计算的进度外,还可以从 igraph 函数中报告简单的状态消息,而无需判断已经执行了多少计算。为此,需要安装状态处理程序函数。

状态处理程序函数必须是 igraph_status_handler_t 类型,并且可以通过调用 igraph_set_status_handler() 来安装它们。目前有一个简单的预定义状态处理程序函数,称为 igraph_status_handler_stderr(),但是用户可以定义新的函数。

igraph 函数通过调用 IGRAPH_STATUS()IGRAPH_STATUSF() 宏来报告其状态。

3.2. 设置状态处理程序

3.2.1. igraph_status_handler_t — igraph 状态处理程序函数的类型

typedef igraph_error_t igraph_status_handler_t(const char *message, void *data);

参数: 

message:

状态消息。

数据:

附加上下文,具有用户定义的语义。现有的 igraph 函数在此处传递一个空指针。

返回值: 

错误代码。如果您在此处返回除 IGRAPH_SUCCESS 以外的任何其他代码,则当前计算将中止。

3.2.2. igraph_set_status_handler — 安装或卸载状态处理程序函数。

igraph_status_handler_t *
igraph_set_status_handler(igraph_status_handler_t new_handler);

要卸载当前安装的状态处理程序,请使用空指针调用此函数。

参数: 

new_handler:

要安装的状态处理程序函数。

返回值: 

先前安装的状态处理程序函数。

时间复杂度:O(1)。

3.2.3. igraph_status_handler_stderr — 一个简单的预定义状态处理程序函数。

igraph_error_t igraph_status_handler_stderr(const char *message, void *data);

一个简单的状态处理程序函数,将状态消息写入标准错误。

参数: 

message:

状态消息。

数据:

附加上下文,具有用户定义的语义。现有的 igraph 函数在此处传递一个空指针。

返回值: 

错误代码。

时间复杂度:O(1)。

3.3. 调用状态处理程序

3.3.1. IGRAPH_STATUS — 报告 igraph 函数的状态。

#define IGRAPH_STATUS(message, data)

通常,从 igraph 函数中仅调用此函数几次。例如,如果一个算法有三个主要步骤,那么逻辑上应该调用它三次,以表示这三个主要步骤。

参数: 

message:

状态消息。

数据:

附加上下文,具有用户定义的语义。现有的 igraph 函数在此处传递一个空指针。

返回值: 

如果状态处理程序返回的值不是 IGRAPH_SUCCESS,则调用此宏的函数也会返回,错误代码为 IGRAPH_INTERRUPTED

3.3.2. IGRAPH_STATUSF — 报告来自 igraph 函数的状态

#define IGRAPH_STATUSF(args)

这是 IGRAPH_STATUS() 的更灵活版本,具有 printf 式的语法。由于此宏采用可变数量的参数,因此必须将它们全部作为单个参数提供,并用括号括起来。然后使用给定的参数调用 igraph_statusf()

参数: 

args:

要传递给 igraph_statusf() 的参数。

返回值: 

如果状态处理程序返回的值不是 IGRAPH_SUCCESS,则调用此宏的函数也会返回,错误代码为 IGRAPH_INTERRUPTED

3.3.3. igraph_status — 报告来自 igraph 函数的状态。

igraph_error_t igraph_status(const char *message, void *data);

它调用已安装的状态处理程序函数(如果存在)。否则,它什么也不做。请注意,从 igraph 函数报告状态的标准方法是 IGRAPH_STATUSIGRAPH_STATUSF 宏,因为如果状态处理程序返回 IGRAPH_INTERRUPTED,则它们会处理调用函数的终止。

参数: 

message:

状态消息。

数据:

附加上下文,具有用户定义的语义。现有的 igraph 函数在此处传递一个空指针。

返回值: 

错误代码。如果调用了状态处理程序函数并且它没有返回 IGRAPH_SUCCESS,则 igraph_status() 返回 IGRAPH_INTERRUPTED

时间复杂度:O(1)。

3.3.4. igraph_statusf — 报告状态,更灵活的 printf 式版本。

igraph_error_t igraph_statusf(const char *message, void *data, ...);

这是 igraph_status() 的更灵活的版本,它的语法类似于 printf 标准 C 库函数。它将附加参数的值替换为 message 模板字符串,并调用 igraph_status()

参数: 

message:

状态消息模板字符串,语法与 printf 函数的语法相同。

数据:

附加上下文,具有用户定义的语义。现有的 igraph 函数在此处传递一个空指针。

...:

用于填充 message 参数中给出的模板的附加参数。

返回值: 

错误代码。如果调用了状态处理程序函数并且它没有返回 IGRAPH_SUCCESS,则 igraph_status() 返回 IGRAPH_INTERRUPTED