igraph 参考手册

用于使用 igraph C 库

搜索手册

第 8 章. 随机数

1. 关于 igraph 中的随机数

igraph 中的一些算法,例如从随机图模型中采样,需要随机数生成器 (RNG)。 igraph 包括一个灵活的 RNG 框架,允许连接任意随机数生成器,并附带了几个即用型生成器。该框架用于 igraph 的高级接口中,以与宿主语言自己的 RNG 集成。

2. 默认随机数生成器

2.1. igraph_rng_default — 查询默认随机数生成器。

igraph_rng_t *igraph_rng_default(void);

返回值: 

指向默认随机数生成器的指针。

另请参阅: 

2.2. igraph_rng_set_default — 设置默认的 igraph 随机数生成器。

void igraph_rng_set_default(igraph_rng_t *rng);

该函数复制给定 igraph_rng_t 对象的内部结构到 igraph 的内部默认 RNG 结构中。该结构本身仅包含两个指针,一个指向 RNG 的“方法”,另一个指向保存 RNG 内部状态的内存缓冲区。这意味着,如果在将其设置为默认值后,您继续从 RNG 生成随机数,它也会影响默认 RNG 的状态,因为两者共享相同的状态指针。但是,不要期望 igraph_rng_default() 返回与您在此处传入的指针相同的指针 - 状态是共享的,但整个结构不是。

参数: 

rng:

从现在起用作默认值的随机数生成器。在其仍用作默认值时调用 igraph_rng_destroy() 将导致崩溃和/或不可预测的结果。

时间复杂度:O(1)。

3. 创建随机数生成器

3.1. igraph_rng_init — 初始化随机数生成器。

igraph_error_t igraph_rng_init(igraph_rng_t *rng, const igraph_rng_type_t *type);

该函数为具有给定类型的随机数生成器分配内存,并将其种子设置为默认值。

参数: 

rng:

指向未初始化 RNG 的指针。

type:

RNG 的类型,例如 igraph_rngtype_mt19937igraph_rngtype_glibc2igraph_rngtype_pcg32igraph_rngtype_pcg64

返回值: 

错误代码。

3.2. igraph_rng_destroy — 释放与随机数生成器关联的内存。

void igraph_rng_destroy(igraph_rng_t *rng);

参数: 

rng:

要销毁的 RNG。不要销毁用作默认 igraph RNG 的 RNG。

时间复杂度:O(1)。

3.3. igraph_rng_seed — 播种随机数生成器。

igraph_error_t igraph_rng_seed(igraph_rng_t *rng, igraph_uint_t seed);

参数: 

rng:

RNG。

seed:

新的种子。

返回值: 

错误代码。

时间复杂度:通常为 O(1),但可能取决于 RNG 的类型。

3.4. igraph_rng_bits — 随机数生成器在单轮中可以产生的随机位数。

igraph_integer_t igraph_rng_bits(const igraph_rng_t* rng);

参数: 

rng:

RNG。

返回值: 

可以使用 RNG 在单轮中生成的随机位数。

时间复杂度:O(1)。

3.5. igraph_rng_max — 随机数生成器的最大可能整数。

igraph_uint_t igraph_rng_max(const igraph_rng_t *rng);

请注意,此数字仅用于提供信息;它返回可以通过 RNG 单次调用其内部函数生成的最大可能整数。它直接从 RNG 在单轮中可以生成的随机位数推导而来。当它小于其他 RNG 函数(如 igraph_rng_get_integer())所需的数量时,igraph 将多次调用 RNG 以生成更多随机位。

参数: 

rng:

RNG。

返回值: 

可以使用 RNG 在单轮中生成的最大可能整数。

时间复杂度:O(1)。

3.6. igraph_rng_name — 随机数生成器的类型。

const char *igraph_rng_name(const igraph_rng_t *rng);

参数: 

rng:

RNG。

返回值: 

生成器类型的名称。不要释放或更改返回的字符串。

时间复杂度:O(1)。

4. 生成随机数

4.1. igraph_rng_get_bool — 生成随机布尔值。

igraph_bool_t igraph_rng_get_bool(igraph_rng_t *rng);

仅当一次需要单个随机布尔值,即单个位时,才使用此函数。它对于生成多个位效率不高。

参数: 

rng:

指向用于生成的 RNG 的指针。在此处使用 igraph_rng_default() 以使用默认的 igraph RNG。

返回值: 

生成的位,作为真值。

4.2. igraph_rng_get_integer — 从区间生成整数随机数。

igraph_integer_t igraph_rng_get_integer(
    igraph_rng_t *rng, igraph_integer_t l, igraph_integer_t h
);

从区间 [l, h] 生成均匀分布的整数。

参数: 

rng:

指向用于生成的 RNG 的指针。在此处使用 igraph_rng_default() 以使用默认的 igraph RNG。

l:

下限,包括在内,也可以为负。

h:

上限,包括在内,也可以为负,但必须至少为 l

返回值: 

生成的随机整数。

时间复杂度:O(log2(h-l+1) / bits),其中 bits 是 igraph_rng_bits(rng) 的值。

4.3. igraph_rng_get_unif01 — 从单位区间均匀采样。

igraph_real_t igraph_rng_get_unif01(igraph_rng_t *rng);

[0, 1) 半开区间生成均匀分布的实数。

参数: 

rng:

指向要使用的 RNG 的指针。在此处使用 igraph_rng_default() 以使用默认的 igraph RNG。

返回值: 

生成的均匀分布的随机数。

时间复杂度:取决于 RNG 的类型。

4.4. igraph_rng_get_unif — 从给定区间采样实数。

igraph_real_t igraph_rng_get_unif(igraph_rng_t *rng,
                                  igraph_real_t l, igraph_real_t h);

[l, h) 半开区间生成均匀分布的实数。

参数: 

rng:

指向要使用的 RNG 的指针。在此处使用 igraph_rng_default() 以使用默认的 igraph RNG。

l:

下限,可以为负。

h:

上限,可以为负,但必须大于下限。

返回值: 

生成的均匀分布的随机数。

时间复杂度:取决于 RNG 的类型。

4.5. igraph_rng_get_normal — 从正态分布采样。

igraph_real_t igraph_rng_get_normal(igraph_rng_t *rng,
                                    igraph_real_t m, igraph_real_t s);

从具有概率密度的正态分布生成随机变量

exp( -(x - m)^2 / (2 s^2) ).

参数: 

rng:

指向要使用的 RNG 的指针。在此处使用 igraph_rng_default() 以使用默认的 igraph RNG。

m:

平均值。

s:

标准差。

返回值: 

生成的正态分布随机数。

时间复杂度:取决于 RNG 的类型。

4.6. igraph_rng_get_exp — 从指数分布采样。

igraph_real_t igraph_rng_get_exp(igraph_rng_t *rng, igraph_real_t rate);

从概率密度与以下成比例的指数分布生成随机变量

exp(-rate x).

参数: 

rng:

指向要使用的 RNG 的指针。在此处使用 igraph_rng_default() 以使用默认的 igraph RNG。

rate:

速率参数。

返回值: 

生成的样本。

时间复杂度:取决于 RNG。

4.7. igraph_rng_get_gamma — 从伽马分布采样。

igraph_real_t igraph_rng_get_gamma(igraph_rng_t *rng, igraph_real_t shape,
                                   igraph_real_t scale);

从概率密度与以下成比例的伽马分布生成随机变量

x^(shape-1) exp(-x / scale).

参数: 

rng:

指向要使用的 RNG 的指针。在此处使用 igraph_rng_default() 以使用默认的 igraph RNG。

shape:

形状参数。

scale:

比例参数。

返回值: 

生成的样本。

时间复杂度:取决于 RNG。

4.8. igraph_rng_get_binom — 从二项分布采样。

igraph_real_t igraph_rng_get_binom(igraph_rng_t *rng, igraph_integer_t n, igraph_real_t p);

从二项分布生成随机变量。数字 k 以概率生成

(n \choose k) p^k (1-p)^(n-k), k = 0, 1, ..., n

参数: 

rng:

指向要使用的 RNG 的指针。在此处使用 igraph_rng_default() 以使用默认的 igraph RNG。

n:

观测次数。

p:

事件的概率。

返回值: 

生成的二项分布随机数。

时间复杂度:取决于 RNG。

4.9. igraph_rng_get_geom — 从几何分布采样。

igraph_real_t igraph_rng_get_geom(igraph_rng_t *rng, igraph_real_t p);

从几何分布生成随机变量。数字 k 以概率生成

(1 - p)^k p, k = 0, 1, 2, ...

参数: 

rng:

指向要使用的 RNG 的指针。在此处使用 igraph_rng_default() 以使用默认的 igraph RNG。

p:

每次试验中成功的概率。必须大于零且小于或等于 1。

返回值: 

生成的几何分布随机数。

时间复杂度:取决于 RNG。

4.10. igraph_rng_get_pois — 从泊松分布采样。

igraph_real_t igraph_rng_get_pois(igraph_rng_t *rng, igraph_real_t rate);

从泊松分布生成随机变量。数字 k 以概率生成

rate^k * exp(-rate) / k!, k = 0, 1, 2, ...

参数: 

rng:

指向要使用的 RNG 的指针。在此处使用 igraph_rng_default() 以使用默认的 igraph RNG。

rate:

泊松分布的速率参数。不得为负。

返回值: 

生成的几何分布随机数。

时间复杂度:取决于 RNG。

5. 支持的随机数生成器

默认情况下,igraph 使用 MT19937 生成器。在 igraph 版本 0.6 之前,使用标准 C 库提供的生成器。这意味着 GNU libc 2 系统上的 GLIBC2 生成器,以及其他系统上的 BSD RAND 生成器。 RAND 生成器由于其较差的统计特性在版本 0.10 中被删除。 PCG32 生成器在版本 0.10 中添加。

5.1. igraph_rngtype_mt19937 — MT19937 随机数生成器。

const igraph_rng_type_t igraph_rngtype_mt19937 = {
    /* name= */      "MT19937",
    /* bits=  */     32,
    /* init= */      igraph_rng_mt19937_init,
    /* destroy= */   igraph_rng_mt19937_destroy,
    /* seed= */      igraph_rng_mt19937_seed,
    /* get= */       igraph_rng_mt19937_get,
    /* get_int= */   NULL,
    /* get_real= */  NULL,
    /* get_norm= */  NULL,
    /* get_geom= */  NULL,
    /* get_binom= */ NULL,
    /* get_exp= */   NULL,
    /* get_gamma= */ NULL,
    /* get_pois= */  NULL
};

Makoto Matsumoto 和 Takuji Nishimura 的 MT19937 生成器是扭曲的广义反馈移位寄存器算法的变体,被称为“梅森旋转”生成器。它具有 2^19937 - 1(约 10^6000)的梅森素数周期,并且在 623 个维度上是等分布的。它已通过了 diehard 统计测试。它每个生成器使用 624 个字的状态,并且速度与其他生成器相当。原始生成器使用 4357 的默认种子,并且在 igraph_rng_mt19937_seed() 中选择等于零的 s 会重现此结果。更高版本切换到 5489 作为默认种子,如果您需要,可以通过 igraph_rng_seed() 显式选择此种子。

有关更多信息,请参见 Makoto Matsumoto 和 Takuji Nishimura,“梅森旋转:一种 623 维等分布均匀伪随机数生成器”。 ACM Transactions on Modeling and Computer Simulation,第 8 卷,第 1 期(1998 年 1 月),第 3–30 页

生成器 igraph_rngtype_mt19937 使用上述两位作者于 2002 年发布的播种过程的第二次修订。原始播种过程可能会导致某些种子值的虚假伪像。

此生成器是从 GNU Scientific Library 移植的。

5.2. igraph_rngtype_glibc2 — GNU libc 2 中引入的随机数生成器。

const igraph_rng_type_t igraph_rngtype_glibc2 = {
    /* name= */      "LIBC",
    /* bits=  */     31,
    /* init= */      igraph_rng_glibc2_init,
    /* destroy= */   igraph_rng_glibc2_destroy,
    /* seed= */      igraph_rng_glibc2_seed,
    /* get= */       igraph_rng_glibc2_get,
    /* get_int= */   NULL,
    /* get_real= */  NULL,
    /* get_norm= */  NULL,
    /* get_geom= */  NULL,
    /* get_binom= */ NULL,
    /* get_exp= */   NULL,
    /* get_gamma= */ NULL,
    /* get_pois= */  NULL
};

这是一个具有 128 字节缓冲区的线性反馈移位寄存器生成器。在 igraph 版本 0.6 之前,该生成器是默认生成器,至少在依赖 GNU libc 的系统上是这样。该生成器是从 GNU Scientific Library 移植的。它是一个重新实现,不调用系统 glibc 生成器。

5.3. igraph_rngtype_pcg32 — PCG 随机数生成器(32 位版本)。

const igraph_rng_type_t igraph_rngtype_pcg32 = {
    /* name= */      "PCG32",
    /* bits=  */     32,
    /* init= */      igraph_rng_pcg32_init,
    /* destroy= */   igraph_rng_pcg32_destroy,
    /* seed= */      igraph_rng_pcg32_seed,
    /* get= */       igraph_rng_pcg32_get,
    /* get_int= */   NULL,
    /* get_real= */  NULL,
    /* get_norm= */  NULL,
    /* get_geom= */  NULL,
    /* get_binom= */ NULL,
    /* get_exp= */   NULL,
    /* get_gamma= */ NULL,
    /* get_pois= */  NULL
};

这是 PCG 随机数生成器的实现;有关更多详细信息,请参见 https://www.pcg-random.org。此实现在单次迭代中返回 32 个随机位。

该生成器是从作者在 https://github.com/imneme/pcg-c 上发布的原始源代码移植的。

5.4. igraph_rngtype_pcg64 — PCG 随机数生成器(64 位版本)。

const igraph_rng_type_t igraph_rngtype_pcg64 = {
    /* name= */      "PCG64",
    /* bits=  */     64,
    /* init= */      igraph_rng_pcg64_init,
    /* destroy= */   igraph_rng_pcg64_destroy,
    /* seed= */      igraph_rng_pcg64_seed,
    /* get= */       igraph_rng_pcg64_get,
    /* get_int= */   NULL,
    /* get_real= */  NULL,
    /* get_norm= */  NULL,
    /* get_geom= */  NULL,
    /* get_binom= */ NULL,
    /* get_exp= */   NULL,
    /* get_gamma= */ NULL,
    /* get_pois= */  NULL
};

这是 PCG 随机数生成器的实现;有关更多详细信息,请参见 https://www.pcg-random.org。此实现在单次迭代中返回 64 个随机位。它仅在具有提供 __uint128_t 类型的编译器的 64 位平台上可用。

PCG64 在采样浮点数或非常大的整数时通常提供比 PCG32 更好的性能,因为它可以在单次生成轮次中提供两倍的随机位数。

该生成器是从作者在 https://github.com/imneme/pcg-c 上发布的原始源代码移植的。

6. 用例

6.1. 正常(默认)使用

如果用户未显式使用任何 RNG 函数,而是调用一些随机 igraph 函数,则在 igraph 函数首次需要随机数时,将设置默认 RNG。此 RNG 的种子是 time(0) 函数调用的输出,使用标准 C 库中的 time 函数。这确保 igraph 每次调用 C 程序时都创建一个不同的随机图。

创建的默认生成器在内部存储,可以使用 igraph_rng_default() 函数查询。

6.2. 可重现的模拟

如果需要可重现的结果,则用户应使用 igraph_rng_seed() 函数在默认生成器 igraph_rng_default() 上显式设置默认随机数生成器的种子。将种子设置为相同的数字时,igraph 会生成完全相同的随机图(或一系列随机图)。

6.3. 更改默认生成器

默认情况下,igraph 使用 igraph_rng_default() 随机数生成器。可以通过使用已初始化的随机数生成器调用 igraph_rng_set_default() 随时更改此设置。请注意,旧的(替换的)生成器不会被销毁,因此不会释放任何内存。

6.4. 使用多个生成器

igraph 还提供了使用 igraph_rng_init() 函数设置多个随机数生成器的函数,然后从它们生成随机数,例如使用 igraph_rng_get_integer() 和/或 igraph_rng_get_unif() 调用。

请注意,初始化新的随机数生成器与 igraph 函数本身使用的生成器无关。如果要替换该生成器,请使用 igraph_rng_set_default()

6.5. 示例

示例 8.1.  文件 examples/simple/random_seed.c

#include <igraph.h>

int main(void) {

    igraph_t g1, g2;
    igraph_bool_t iso;

    /* Seed the default random number generator and create a random graph. */

    igraph_rng_seed(igraph_rng_default(), 1122);

    igraph_erdos_renyi_game_gnp(&g1, 100, 3.0 / 100, /*directed=*/ 0, /*loops=*/ 0);

    /* Seed the generator with the same seed again,
     * and create a graph with the same method. */

    igraph_rng_seed(igraph_rng_default(), 1122);

    igraph_erdos_renyi_game_gnp(&g2, 100, 3.0 / 100, /*directed=*/ 0, /*loops=*/ 0);

    /* The two graphs will be identical. */

    igraph_is_same_graph(&g1, &g2, &iso);

    if (!iso) {
        return 1;
    }

    /* Destroy no longer needed data structures. */

    igraph_destroy(&g2);
    igraph_destroy(&g1);

    return 0;
}