Add graph references

This commit is contained in:
Abdelrahman Said
2026-06-28 13:49:01 +01:00
parent 0a9807e448
commit a11edf0c53
2578 changed files with 868045 additions and 0 deletions
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,43 @@
/*
igraph library.
Copyright (C) 2025 The igraph development team <igraph@igraph.org>
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "random/random_internal.h"
#include <ctime>
#include <random>
/* This function attempts to produce an unpredictable number suitable for
* seeding the RNG upon startup. It makes an effort to avoid producing the
* same number when called within different processes, even if called
* approximately at the same time. However, it cannot guarantee this on
* all systems under all circumstancs.
*
* This function cannot fail.
*/
igraph_uint_t igraph_i_get_random_seed(void) {
try {
// Try to use C++'s std::random_device. This may fail, either because
// the systems's random device ran out of entropy or because the system
// does not offer this functionality.
return std::random_device()();
} catch (...) {
// If random_device fails, use a time-based seed. A combination of
// time() (calendar time, low resolution) and clock() (processor time
// used, higher resolution) reduces the risk of seed collisions.
return igraph_uint_t(std::clock()) + igraph_uint_t(std::time(NULL));
}
}
@@ -0,0 +1,35 @@
/*
igraph library.
Copyright (C) 2021-2025 The igraph development team <igraph@igraph.org>
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef IGRAPH_RANDOM_INTERNAL_H
#define IGRAPH_RANDOM_INTERNAL_H
#include "igraph_decls.h"
#include "igraph_types.h"
#include "igraph_vector.h"
IGRAPH_BEGIN_C_DECLS
igraph_error_t igraph_i_random_sample_real(
igraph_vector_t *res, igraph_real_t l, igraph_real_t h,
igraph_int_t length);
igraph_uint_t igraph_i_get_random_seed(void);
IGRAPH_END_C_DECLS
#endif
@@ -0,0 +1,144 @@
/*
igraph library.
Copyright (C) 2022 The igraph development team <igraph@igraph.org>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "igraph_random.h"
#include "igraph_memory.h"
#include "igraph_types.h"
typedef struct {
int i, j;
long int x[31];
} igraph_i_rng_glibc2_state_t;
static unsigned long int igraph_i_rng_glibc2_get(int *i, int *j, int n, long int *x) {
unsigned long int k;
/* The original implementation used x[*i] += x[*j] here. Considering that
* x is signed, this is undefined behaviour according to the C standard.
* Therefore, we temporarily cast to unsigned long int to achieve what the
* original intention was */
x[*i] = ((unsigned long int)x[*i]) + ((unsigned long int)x[*j]);
k = (x[*i] >> 1) & 0x7FFFFFFF;
(*i)++;
if (*i == n) {
*i = 0;
}
(*j)++ ;
if (*j == n) {
*j = 0;
}
return k;
}
static igraph_uint_t igraph_rng_glibc2_get(void *vstate) {
igraph_i_rng_glibc2_state_t *state =
(igraph_i_rng_glibc2_state_t*) vstate;
return igraph_i_rng_glibc2_get(&state->i, &state->j, 31, state->x);
}
/* this function is independent of the bit size */
static void igraph_i_rng_glibc2_init(long int *x, int n,
unsigned long int s) {
int i;
if (s == 0) {
s = 1;
}
x[0] = (long) s;
for (i = 1 ; i < n ; i++) {
const long int h = s / 127773;
const long int t = 16807 * ((long) s - h * 127773) - h * 2836;
if (t < 0) {
s = (unsigned long) t + 2147483647 ;
} else {
s = (unsigned long) t ;
}
x[i] = s ;
}
}
static igraph_error_t igraph_rng_glibc2_seed(void *vstate, igraph_uint_t seed) {
igraph_i_rng_glibc2_state_t *state =
(igraph_i_rng_glibc2_state_t*) vstate;
int i;
igraph_i_rng_glibc2_init(state->x, 31, (unsigned long) seed);
state->i = 3;
state->j = 0;
for (i = 0; i < 10 * 31; i++) {
igraph_rng_glibc2_get(state);
}
return IGRAPH_SUCCESS;
}
static igraph_error_t igraph_rng_glibc2_init(void **state) {
igraph_i_rng_glibc2_state_t *st;
st = IGRAPH_CALLOC(1, igraph_i_rng_glibc2_state_t);
IGRAPH_CHECK_OOM(st, "Cannot initialize GNU libc 2 RNG.");
(*state) = st;
igraph_rng_glibc2_seed(st, 0);
return IGRAPH_SUCCESS;
}
static void igraph_rng_glibc2_destroy(void *vstate) {
igraph_i_rng_glibc2_state_t *state =
(igraph_i_rng_glibc2_state_t*) vstate;
IGRAPH_FREE(state);
}
/**
* \var igraph_rngtype_glibc2
* \brief The random number generator introduced in GNU libc 2.
*
* This is a linear feedback shift register generator with a 128-byte
* buffer. This generator was the default prior to igraph version 0.6,
* at least on systems relying on GNU libc.
*
* This generator was ported from the GNU Scientific Library. It is a
* reimplementation and does not call the system glibc generator.
*/
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
};
@@ -0,0 +1,179 @@
/*
igraph library.
Copyright (C) 2022 The igraph development team <igraph@igraph.org>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "igraph_random.h"
#include "igraph_memory.h"
#include "igraph_types.h"
#include <string.h> /* memset() */
#include <ctype.h>
#define N 624 /* Period parameters */
#define M 397
/* most significant w-r bits */
static const uint32_t UPPER_MASK = UINT32_C(0x80000000);
/* least significant r bits */
static const uint32_t LOWER_MASK = UINT32_C(0x7fffffff);
typedef struct {
uint32_t mt[N];
int mti;
} igraph_i_rng_mt19937_state_t;
static igraph_uint_t igraph_rng_mt19937_get(void *vstate) {
igraph_i_rng_mt19937_state_t *state = vstate;
uint32_t k;
uint32_t *const mt = state->mt;
#define MAGIC(y) (((y) & 0x1) ? UINT32_C(0x9908b0df) : 0)
if (state->mti >= N) {
/* generate N words at one time */
int kk;
for (kk = 0; kk < N - M; kk++) {
uint32_t y = (mt[kk] & UPPER_MASK) | (mt[kk + 1] & LOWER_MASK);
mt[kk] = mt[kk + M] ^ (y >> 1) ^ MAGIC(y);
}
for (; kk < N - 1; kk++) {
uint32_t y = (mt[kk] & UPPER_MASK) | (mt[kk + 1] & LOWER_MASK);
mt[kk] = mt[kk + (M - N)] ^ (y >> 1) ^ MAGIC(y);
}
{
uint32_t y = (mt[N - 1] & UPPER_MASK) | (mt[0] & LOWER_MASK);
mt[N - 1] = mt[M - 1] ^ (y >> 1) ^ MAGIC(y);
}
state->mti = 0;
}
#undef MAGIC
/* Tempering */
k = mt[state->mti];
k ^= (k >> 11);
k ^= (k << 7) & UINT32_C(0x9d2c5680);
k ^= (k << 15) & UINT32_C(0xefc60000);
k ^= (k >> 18);
state->mti++;
return k;
}
static igraph_error_t igraph_rng_mt19937_seed(void *vstate, igraph_uint_t seed) {
igraph_i_rng_mt19937_state_t *state = vstate;
int i;
memset(state, 0, sizeof(igraph_i_rng_mt19937_state_t));
if (seed == 0) {
seed = 4357; /* the default seed is 4357 */
}
state->mt[0] = seed & UINT32_C(0xffffffff);
for (i = 1; i < N; i++) {
/* See Knuth's "Art of Computer Programming" Vol. 2, 3rd
Ed. p.106 for multiplier. */
state->mt[i] =
(UINT32_C(1812433253) * (state->mt[i - 1] ^ (state->mt[i - 1] >> 30)) +
(uint32_t) i);
state->mt[i] &= UINT32_C(0xffffffff);
}
state->mti = i;
return IGRAPH_SUCCESS;
}
static igraph_error_t igraph_rng_mt19937_init(void **state) {
igraph_i_rng_mt19937_state_t *st;
st = IGRAPH_CALLOC(1, igraph_i_rng_mt19937_state_t);
IGRAPH_CHECK_OOM(st, "Cannot initialize MT19937 RNG.");
(*state) = st;
igraph_rng_mt19937_seed(st, 0);
return IGRAPH_SUCCESS;
}
static void igraph_rng_mt19937_destroy(void *vstate) {
igraph_i_rng_mt19937_state_t *state =
(igraph_i_rng_mt19937_state_t*) vstate;
IGRAPH_FREE(state);
}
/**
* \var igraph_rngtype_mt19937
* \brief The MT19937 random number generator.
*
* The MT19937 generator of Makoto Matsumoto and Takuji Nishimura is a
* variant of the twisted generalized feedback shift-register
* algorithm, and is known as the “Mersenne Twister” generator. It has
* a Mersenne prime period of 2^19937 - 1 (about 10^6000) and is
* equi-distributed in 623 dimensions. It has passed the diehard
* statistical tests. It uses 624 words of state per generator and is
* comparable in speed to the other generators. The original generator
* used a default seed of 4357 and choosing \c s equal to zero in
* \c igraph_rng_mt19937_seed() reproduces this. Later versions switched to
* 5489 as the default seed, you can choose this explicitly via
* \ref igraph_rng_seed() instead if you require it.
*
* </para><para>
* For more information see,
* Makoto Matsumoto and Takuji Nishimura, “Mersenne Twister: A
* 623-dimensionally equidistributed uniform pseudorandom number
* generator”. ACM Transactions on Modeling and Computer Simulation,
* Vol. 8, No. 1 (Jan. 1998), Pages 330
*
* </para><para>
* The generator \c igraph_rngtype_mt19937 uses the second revision of the
* seeding procedure published by the two authors above in 2002. The
* original seeding procedures could cause spurious artifacts for some
* seed values.
*
* </para><para>
* This generator was ported from the GNU Scientific Library.
*/
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
};
#undef N
#undef M
@@ -0,0 +1,122 @@
/*
igraph library.
Copyright (C) 2022 The igraph development team <igraph@igraph.org>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "igraph_random.h"
#include "igraph_memory.h"
#include "igraph_types.h"
#include "pcg/pcg_variants.h"
/* The original implementation of the 32-bit PCG random number generator in this
* file was obtained from https://github.com/imneme/pcg-c
*
* PCG is dual-licensed under Apache-2.0 and MIT Licenses. MIT is compatible
* with igraph's GPLv2 license. License notices for PCG are to be found in the
* pcg_variants.h header
*/
static const pcg32_random_t pcg32_initializer = PCG32_INITIALIZER;
static igraph_uint_t igraph_rng_pcg32_get(void *vstate) {
pcg32_random_t *state = (pcg32_random_t*) vstate;
return pcg32_random_r(state);
}
static igraph_error_t igraph_rng_pcg32_seed(void *vstate, igraph_uint_t seed) {
pcg32_random_t *state = (pcg32_random_t*) vstate;
/* PCG32 is seeded by a 64-bit state and a 64-bit sequence number (well, only
* 63 bits are used from the sequence number, though). Since the unified
* igraph RNG seeding interface provides a single igraph_uint_t as the seed,
* we use the seed to fill in the sequence number and use the state from
* PCG32_INITIALIZER */
if (seed == 0) {
/* If you feel the temptation to unify the two branches by running
* seed = pcg32_initializer.inc >> 1, don't.
* seed is an igraph_uint_t, so it can be 32-bit or 64-bit.
* pcg32_initializer.inc is always 64-bit.
*/
pcg32_srandom_r(state, pcg32_initializer.state, pcg32_initializer.inc >> 1);
} else {
pcg32_srandom_r(state, pcg32_initializer.state, seed);
}
return IGRAPH_SUCCESS;
}
static igraph_error_t igraph_rng_pcg32_init(void **state) {
pcg32_random_t *st;
st = IGRAPH_CALLOC(1, pcg32_random_t);
IGRAPH_CHECK_OOM(st, "Cannot initialize PCG32 RNG.");
(*state) = st;
igraph_rng_pcg32_seed(st, 0);
return IGRAPH_SUCCESS;
}
static void igraph_rng_pcg32_destroy(void *vstate) {
pcg32_random_t *state = (pcg32_random_t*) vstate;
IGRAPH_FREE(state);
}
/**
* \var igraph_rngtype_pcg32
* \brief The PCG random number generator (32-bit version).
*
* This is an implementation of the PCG random number generator; see
* https://www.pcg-random.org for more details. This implementation returns
* 32 random bits in a single iteration.
*
* </para><para>
* The generator was ported from the original source code published by the
* authors at https://github.com/imneme/pcg-c.
*/
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
};
/***** Default RNG, used upon igraph startup *****/
#define addr(a) (&a)
static pcg32_random_t igraph_i_rng_default_state = PCG32_INITIALIZER;
igraph_rng_t igraph_i_rng_default = {
addr(igraph_rngtype_pcg32),
addr(igraph_i_rng_default_state),
/* is_seeded = */ false
};
#undef addr
@@ -0,0 +1,138 @@
/*
igraph library.
Copyright (C) 2022 The igraph development team <igraph@igraph.org>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "igraph_random.h"
#include "igraph_memory.h"
#include "igraph_types.h"
#include "config.h"
/* The original implementation of the 64-bit PCG random number generator in this
* file was obtained from https://github.com/imneme/pcg-c
*
* PCG is dual-licensed under Apache-2.0 and MIT Licenses. MIT is compatible
* with igraph's GPLv2 license. License notices for PCG are to be found in the
* pcg_variants.h header
*/
#if IGRAPH_INTEGER_SIZE == 64 && defined(HAVE___UINT128_T)
#include "pcg/pcg_variants.h"
static const pcg64_random_t pcg64_initializer = PCG64_INITIALIZER;
static igraph_uint_t igraph_rng_pcg64_get(void *vstate) {
pcg64_random_t *state = (pcg64_random_t*) vstate;
return pcg64_random_r(state);
}
static igraph_error_t igraph_rng_pcg64_seed(void *vstate, igraph_uint_t seed) {
pcg64_random_t *state = (pcg64_random_t*) vstate;
if (seed == 0) {
seed = (pcg64_initializer.inc >> 1);
}
/* PCG64 is seeded by a 128-bit state and a 128-bit sequence number (well, only
* 63 bits are used from the sequence number, though). Since the unified
* igraph RNG seeding interface provides a single igraph_uint_t as the seed,
* we use the seed to fill in the sequence number and use the state from
* PCG64_INITIALIZER */
pcg64_srandom_r(state, pcg64_initializer.state, seed);
return IGRAPH_SUCCESS;
}
static igraph_error_t igraph_rng_pcg64_init(void **state) {
pcg64_random_t *st;
st = IGRAPH_CALLOC(1, pcg64_random_t);
IGRAPH_CHECK_OOM(st, "Cannot initialize PCG64 RNG.");
(*state) = st;
igraph_rng_pcg64_seed(st, 0);
return IGRAPH_SUCCESS;
}
static void igraph_rng_pcg64_destroy(void *vstate) {
pcg64_random_t *state = (pcg64_random_t*) vstate;
IGRAPH_FREE(state);
}
#else
/* Dummy implementation if the compiler does not support __uint128_t */
static igraph_uint_t igraph_rng_pcg64_get(void *vstate) {
IGRAPH_UNUSED(vstate);
return 0;
}
static igraph_error_t igraph_rng_pcg64_seed(void *vstate, igraph_uint_t seed) {
IGRAPH_UNUSED(vstate); IGRAPH_UNUSED(seed);
IGRAPH_ERROR("64-bit PCG generator needs __uint128_t.", IGRAPH_UNIMPLEMENTED);
}
static igraph_error_t igraph_rng_pcg64_init(void **state) {
IGRAPH_UNUSED(state);
IGRAPH_ERROR("64-bit PCG generator needs __uint128_t.", IGRAPH_UNIMPLEMENTED);
}
static void igraph_rng_pcg64_destroy(void *vstate) {
IGRAPH_UNUSED(vstate);
}
#endif
/**
* \var igraph_rngtype_pcg64
* \brief The PCG random number generator (64-bit version).
*
* This is an implementation of the PCG random number generator; see
* https://www.pcg-random.org for more details. This implementation returns
* 64 random bits in a single iteration. It is only available on 64-bit plaforms
* with compilers that provide the __uint128_t type.
*
* </para><para>
* PCG64 typically provides better performance than PCG32 when sampling floating
* point numbers or very large integers, as it can provide twice as many random
* bits in a single generation round.
*
* </para><para>
* The generator was ported from the original source code published by the
* authors at https://github.com/imneme/pcg-c.
*/
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
};
@@ -0,0 +1,192 @@
/*
igraph library.
Copyright (C) 2025 The igraph development team
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "igraph_sampling.h"
/**
* \function igraph_rng_sample_sphere_surface
* \brief Sample points uniformly from the surface of a sphere.
*
* The center of the sphere is at the origin.
*
* \param rng The random number generator to use.
* \param dim The dimension of the random vectors.
* \param n The number of vectors to sample.
* \param radius Radius of the sphere, it must be positive.
* \param positive Whether to restrict sampling to the positive
* orthant.
* \param res Pointer to an initialized matrix, the result is
* stored here, each column will be a sampled vector. The matrix is
* resized, as needed.
* \return Error code.
*
* Time complexity: O(n*dim*g), where g is the time complexity of
* generating a standard normal random number.
*
* \sa \ref igraph_rng_sample_sphere_volume(), \ref
* igraph_rng_sample_dirichlet() for other similar samplers.
*/
igraph_error_t igraph_rng_sample_sphere_surface(
igraph_rng_t* rng, igraph_int_t dim, igraph_int_t n, igraph_real_t radius,
igraph_bool_t positive, igraph_matrix_t *res
) {
igraph_int_t i, j;
if (dim < 2) {
IGRAPH_ERROR("Sphere must be at least two dimensional to sample from "
"surface.", IGRAPH_EINVAL);
}
if (n < 0) {
IGRAPH_ERROR("Number of samples must be non-negative.", IGRAPH_EINVAL);
}
if (radius <= 0) {
IGRAPH_ERROR("Sphere radius must be positive.", IGRAPH_EINVAL);
}
IGRAPH_CHECK(igraph_matrix_resize(res, dim, n));
for (i = 0; i < n; i++) {
igraph_real_t *col = &MATRIX(*res, 0, i);
igraph_real_t sum = 0.0;
for (j = 0; j < dim; j++) {
col[j] = igraph_rng_get_normal(rng, 0, 1);
sum += col[j] * col[j];
}
sum = sqrt(sum);
for (j = 0; j < dim; j++) {
col[j] = radius * col[j] / sum;
}
if (positive) {
for (j = 0; j < dim; j++) {
col[j] = fabs(col[j]);
}
}
}
return IGRAPH_SUCCESS;
}
/**
* \function igraph_rng_sample_sphere_volume
* \brief Sample points uniformly from the volume of a sphere.
*
* The center of the sphere is at the origin.
*
* \param rng The random number generator to use.
* \param dim The dimension of the random vectors.
* \param n The number of vectors to sample.
* \param radius Radius of the sphere, it must be positive.
* \param positive Whether to restrict sampling to the positive
* orthant.
* \param res Pointer to an initialized matrix, the result is
* stored here, each column will be a sampled vector. The matrix is
* resized, as needed.
* \return Error code.
*
* Time complexity: O(n*dim*g), where g is the time complexity of
* generating a standard normal random number.
*
* \sa \ref igraph_rng_sample_sphere_surface(), \ref
* igraph_rng_sample_dirichlet() for other similar samplers.
*/
igraph_error_t igraph_rng_sample_sphere_volume(
igraph_rng_t* rng, igraph_int_t dim, igraph_int_t n, igraph_real_t radius,
igraph_bool_t positive, igraph_matrix_t *res
) {
igraph_int_t i, j;
/* Arguments are checked by the following call */
IGRAPH_CHECK(igraph_rng_sample_sphere_surface(rng, dim, n, radius, positive, res));
for (i = 0; i < n; i++) {
igraph_real_t *col = &MATRIX(*res, 0, i);
igraph_real_t U = pow(igraph_rng_get_unif01(rng), 1.0 / dim);
for (j = 0; j < dim; j++) {
col[j] *= U;
}
}
return IGRAPH_SUCCESS;
}
/**
* \function igraph_rng_sample_dirichlet
* \brief Sample points from a Dirichlet distribution.
*
* \param rng The random number generator to use.
* \param n The number of vectors to sample.
* \param alpha The parameters of the Dirichlet distribution. They
* must be positive. The length of this vector gives the dimension
* of the generated samples.
* \param res Pointer to an initialized matrix, the result is stored
* here, one sample in each column. It will be resized, as needed.
* \return Error code.
*
* Time complexity: O(n * dim * g), where dim is the dimension of the
* sample vectors, set by the length of alpha, and g is the time
* complexity of sampling from a Gamma distribution.
*
* \sa \ref igraph_rng_sample_sphere_surface() and
* \ref igraph_rng_sample_sphere_volume() for other methods to sample
* latent vectors.
*/
igraph_error_t igraph_rng_sample_dirichlet(
igraph_rng_t* rng, igraph_int_t n, const igraph_vector_t *alpha,
igraph_matrix_t *res
) {
igraph_int_t len = igraph_vector_size(alpha);
igraph_int_t i, j;
igraph_real_t sum, num;
if (n < 0) {
IGRAPH_ERRORF("Number of samples should be non-negative, got %" IGRAPH_PRId ".",
IGRAPH_EINVAL, n);
}
if (len < 2) {
IGRAPH_ERRORF("Dirichlet parameter vector too short, must "
"have at least two entries, got %" IGRAPH_PRId
".", IGRAPH_EINVAL, len);
}
if (igraph_vector_min(alpha) <= 0) {
IGRAPH_ERRORF("Dirichlet concentration parameters must be positive, got %g.",
IGRAPH_EINVAL, igraph_vector_min(alpha));
}
IGRAPH_CHECK(igraph_matrix_resize(res, len, n));
for (i = 0; i < n; i++) {
for (j = 0, sum = 0.0; j < len; j++) {
num = igraph_rng_get_gamma(rng, VECTOR(*alpha)[j], 1.0);
sum += num;
MATRIX(*res, j, i) = num;
}
for (j = 0; j < len; j++) {
MATRIX(*res, j, i) /= sum;
}
}
return IGRAPH_SUCCESS;
}