From 6086f746095569853dba4a2fcb143cc40ae78ac6 Mon Sep 17 00:00:00 2001 From: krlmlr Date: Wed, 19 Feb 2025 12:22:28 +0000 Subject: [PATCH] vendor: Update vendored sources to igraph/igraph@10ef19bc2a61de6c6cfe76e5a068f82b1d29fff1 Merge pull request igraph/igraph#2716 from igraph/feat/triangle-count --- R/aaa-auto.R | 27 +- src/cpp11.cpp | 8 +- src/rinterface.c | 50 +++- src/vendor/cigraph/CHANGELOG.md | 7 + src/vendor/cigraph/include/igraph_motifs.h | 8 +- src/vendor/cigraph/interfaces/functions.yaml | 5 +- src/vendor/cigraph/src/properties/triangles.c | 241 +++++++++++------- src/vendor/igraph_version.h | 4 +- 8 files changed, 246 insertions(+), 104 deletions(-) diff --git a/R/aaa-auto.R b/R/aaa-auto.R index a0a4c5c571..f63ef7918d 100644 --- a/R/aaa-auto.R +++ b/R/aaa-auto.R @@ -2712,14 +2712,25 @@ triad_census_impl <- function(graph) { res } -adjacent_triangles_impl <- function(graph, vids=V(graph)) { +count_adjacent_triangles_impl <- function(graph, vids=V(graph)) { # Argument checks ensure_igraph(graph) vids <- as_igraph_vs(graph, vids) on.exit( .Call(R_igraph_finalizer) ) # Function call - res <- .Call(R_igraph_adjacent_triangles, graph, vids-1) + res <- .Call(R_igraph_count_adjacent_triangles, graph, vids-1) + + res +} + +count_triangles_impl <- function(graph) { + # Argument checks + ensure_igraph(graph) + + on.exit( .Call(R_igraph_finalizer) ) + # Function call + res <- .Call(R_igraph_count_triangles, graph) res } @@ -3916,3 +3927,15 @@ vertex_path_from_edge_path_impl <- function(graph, start, edge.path, mode=c("out res } +adjacent_triangles_impl <- function() { + # Argument checks + + + on.exit( .Call(R_igraph_finalizer) ) + # Function call + res <- .Call(R_igraph_adjacent_triangles) + + + res +} + diff --git a/src/cpp11.cpp b/src/cpp11.cpp index f5181f421d..50cb2ae556 100644 --- a/src/cpp11.cpp +++ b/src/cpp11.cpp @@ -32,7 +32,7 @@ extern SEXP R_igraph_address(SEXP); extern SEXP R_igraph_adhesion(SEXP, SEXP); extern SEXP R_igraph_adjacency(SEXP, SEXP, SEXP); extern SEXP R_igraph_adjacency_spectral_embedding(SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP); -extern SEXP R_igraph_adjacent_triangles(SEXP, SEXP); +extern SEXP R_igraph_adjacent_triangles(void); extern SEXP R_igraph_adjacent_vertices(SEXP, SEXP, SEXP); extern SEXP R_igraph_adjlist(SEXP, SEXP, SEXP); extern SEXP R_igraph_all_minimal_st_separators(SEXP); @@ -112,12 +112,14 @@ extern SEXP R_igraph_copy_to(SEXP); extern SEXP R_igraph_coreness(SEXP, SEXP); extern SEXP R_igraph_correlated_game(SEXP, SEXP, SEXP, SEXP); extern SEXP R_igraph_correlated_pair_game(SEXP, SEXP, SEXP, SEXP, SEXP); +extern SEXP R_igraph_count_adjacent_triangles(SEXP, SEXP); extern SEXP R_igraph_count_automorphisms(SEXP, SEXP, SEXP); extern SEXP R_igraph_count_isomorphisms_vf2(SEXP, SEXP, SEXP, SEXP, SEXP, SEXP); extern SEXP R_igraph_count_loops(SEXP); extern SEXP R_igraph_count_multiple(SEXP, SEXP); extern SEXP R_igraph_count_reachable(SEXP, SEXP); extern SEXP R_igraph_count_subisomorphisms_vf2(SEXP, SEXP, SEXP, SEXP, SEXP, SEXP); +extern SEXP R_igraph_count_triangles(SEXP); extern SEXP R_igraph_create(SEXP, SEXP, SEXP); extern SEXP R_igraph_create_bipartite(SEXP, SEXP, SEXP); extern SEXP R_igraph_de_bruijn(SEXP, SEXP); @@ -487,7 +489,7 @@ static const R_CallMethodDef CallEntries[] = { {"R_igraph_adhesion", (DL_FUNC) &R_igraph_adhesion, 2}, {"R_igraph_adjacency", (DL_FUNC) &R_igraph_adjacency, 3}, {"R_igraph_adjacency_spectral_embedding", (DL_FUNC) &R_igraph_adjacency_spectral_embedding, 7}, - {"R_igraph_adjacent_triangles", (DL_FUNC) &R_igraph_adjacent_triangles, 2}, + {"R_igraph_adjacent_triangles", (DL_FUNC) &R_igraph_adjacent_triangles, 0}, {"R_igraph_adjacent_vertices", (DL_FUNC) &R_igraph_adjacent_vertices, 3}, {"R_igraph_adjlist", (DL_FUNC) &R_igraph_adjlist, 3}, {"R_igraph_all_minimal_st_separators", (DL_FUNC) &R_igraph_all_minimal_st_separators, 1}, @@ -567,12 +569,14 @@ static const R_CallMethodDef CallEntries[] = { {"R_igraph_coreness", (DL_FUNC) &R_igraph_coreness, 2}, {"R_igraph_correlated_game", (DL_FUNC) &R_igraph_correlated_game, 4}, {"R_igraph_correlated_pair_game", (DL_FUNC) &R_igraph_correlated_pair_game, 5}, + {"R_igraph_count_adjacent_triangles", (DL_FUNC) &R_igraph_count_adjacent_triangles, 2}, {"R_igraph_count_automorphisms", (DL_FUNC) &R_igraph_count_automorphisms, 3}, {"R_igraph_count_isomorphisms_vf2", (DL_FUNC) &R_igraph_count_isomorphisms_vf2, 6}, {"R_igraph_count_loops", (DL_FUNC) &R_igraph_count_loops, 1}, {"R_igraph_count_multiple", (DL_FUNC) &R_igraph_count_multiple, 2}, {"R_igraph_count_reachable", (DL_FUNC) &R_igraph_count_reachable, 2}, {"R_igraph_count_subisomorphisms_vf2", (DL_FUNC) &R_igraph_count_subisomorphisms_vf2, 6}, + {"R_igraph_count_triangles", (DL_FUNC) &R_igraph_count_triangles, 1}, {"R_igraph_create", (DL_FUNC) &R_igraph_create, 3}, {"R_igraph_create_bipartite", (DL_FUNC) &R_igraph_create_bipartite, 3}, {"R_igraph_de_bruijn", (DL_FUNC) &R_igraph_de_bruijn, 2}, diff --git a/src/rinterface.c b/src/rinterface.c index 0374a61fee..fa184494a6 100644 --- a/src/rinterface.c +++ b/src/rinterface.c @@ -8589,9 +8589,9 @@ SEXP R_igraph_triad_census(SEXP graph) { } /*-------------------------------------------/ -/ igraph_adjacent_triangles / +/ igraph_count_adjacent_triangles / /-------------------------------------------*/ -SEXP R_igraph_adjacent_triangles(SEXP graph, SEXP vids) { +SEXP R_igraph_count_adjacent_triangles(SEXP graph, SEXP vids) { /* Declarations */ igraph_t c_graph; igraph_vector_t c_res; @@ -8606,7 +8606,7 @@ SEXP R_igraph_adjacent_triangles(SEXP graph, SEXP vids) { igraph_vector_int_t c_vids_data; R_SEXP_to_igraph_vs(vids, &c_graph, &c_vids, &c_vids_data); /* Call igraph */ - IGRAPH_R_CHECK(igraph_adjacent_triangles(&c_graph, &c_res, c_vids)); + IGRAPH_R_CHECK(igraph_count_adjacent_triangles(&c_graph, &c_res, c_vids)); /* Convert output */ PROTECT(res=R_igraph_vector_to_SEXP(&c_res)); @@ -8620,6 +8620,30 @@ SEXP R_igraph_adjacent_triangles(SEXP graph, SEXP vids) { return(r_result); } +/*-------------------------------------------/ +/ igraph_count_triangles / +/-------------------------------------------*/ +SEXP R_igraph_count_triangles(SEXP graph) { + /* Declarations */ + igraph_t c_graph; + igraph_real_t c_res; + SEXP res; + + SEXP r_result; + /* Convert input */ + R_SEXP_to_igraph(graph, &c_graph); + /* Call igraph */ + IGRAPH_R_CHECK(igraph_count_triangles(&c_graph, &c_res)); + + /* Convert output */ + PROTECT(res=NEW_NUMERIC(1)); + REAL(res)[0]=c_res; + r_result = res; + + UNPROTECT(1); + return(r_result); +} + /*-------------------------------------------/ / igraph_local_scan_0 / /-------------------------------------------*/ @@ -11718,6 +11742,26 @@ SEXP R_igraph_vertex_path_from_edge_path(SEXP graph, SEXP start, SEXP edge_path, IGRAPH_FINALLY_CLEAN(1); r_result = vertex_path; + UNPROTECT(1); + return(r_result); +} + +/*-------------------------------------------/ +/ igraph_adjacent_triangles / +/-------------------------------------------*/ +SEXP R_igraph_adjacent_triangles(void) { + /* Declarations */ + igraph_error_t c_result; + SEXP r_result; + /* Convert input */ + + /* Call igraph */ + IGRAPH_R_CHECK(igraph_adjacent_triangles()); + + /* Convert output */ + + + UNPROTECT(1); return(r_result); } diff --git a/src/vendor/cigraph/CHANGELOG.md b/src/vendor/cigraph/CHANGELOG.md index 4056caa3e6..aeb62766db 100644 --- a/src/vendor/cigraph/CHANGELOG.md +++ b/src/vendor/cigraph/CHANGELOG.md @@ -2,9 +2,15 @@ ## [master] +### Added + + - `igraph_count_triangles()` counts undirected triangles in a graph. + - `igraph_count_adjacent_triangles()` (rename of `igraph_adjacent_triangles()`) + ### Deprecated - The undocumented function `igraph_vector_sumsq()` is deprecated. Use `igraph_blas_dnrm2()` to compute the Euclidean norm of real vectors. + - `igraph_adjacent_triangles()` is deprecated and scheduled for removal in 1.0. ### Other @@ -12,6 +18,7 @@ - Updated the vendored `plfit` library to version 1.0.0. This works around a bug in some MSVC / Windows SDK versions that define a `NAN` macro that is not a compile-time constant. - Updated vendored BLAS to 3.12.0 and vendored ARPACK to ARPACK-NG 3.7.0. - Re-translated vendored BLAS/LAPACK/ARPACK sources with f2c version 20240504. + - The performance of `igraph_transitivity_undirected()` is improved by a factor of about 2.5. - Documentation improvements. ## [0.10.15] diff --git a/src/vendor/cigraph/include/igraph_motifs.h b/src/vendor/cigraph/include/igraph_motifs.h index 6394b86266..74de61a9c2 100644 --- a/src/vendor/cigraph/include/igraph_motifs.h +++ b/src/vendor/cigraph/include/igraph_motifs.h @@ -89,13 +89,19 @@ IGRAPH_EXPORT igraph_error_t igraph_dyad_census(const igraph_t *graph, igraph_re igraph_real_t *asym, igraph_real_t *null); IGRAPH_EXPORT igraph_error_t igraph_triad_census(const igraph_t *igraph, igraph_vector_t *res); -IGRAPH_EXPORT igraph_error_t igraph_adjacent_triangles(const igraph_t *graph, +IGRAPH_EXPORT igraph_error_t igraph_count_adjacent_triangles(const igraph_t *graph, igraph_vector_t *res, const igraph_vs_t vids); +IGRAPH_EXPORT IGRAPH_DEPRECATED igraph_error_t igraph_adjacent_triangles(const igraph_t *graph, + igraph_vector_t *res, + const igraph_vs_t vids); + IGRAPH_EXPORT igraph_error_t igraph_list_triangles(const igraph_t *graph, igraph_vector_int_t *res); +IGRAPH_EXPORT igraph_error_t igraph_count_triangles(const igraph_t *graph, igraph_real_t *res); + __END_DECLS #endif diff --git a/src/vendor/cigraph/interfaces/functions.yaml b/src/vendor/cigraph/interfaces/functions.yaml index e6e923e805..2d95da0930 100644 --- a/src/vendor/cigraph/interfaces/functions.yaml +++ b/src/vendor/cigraph/interfaces/functions.yaml @@ -1972,10 +1972,13 @@ igraph_triad_census: PARAMS: GRAPH graph, OUT VECTOR res RETURN: ERROR -igraph_adjacent_triangles: +igraph_count_adjacent_triangles: PARAMS: GRAPH graph, OUT VECTOR res, VERTEX_SELECTOR vids=ALL DEPS: vids ON graph +igraph_count_triangles: + PARAMS: GRAPH graph, OUT REAL res + igraph_local_scan_0: PARAMS: |- GRAPH graph, OUT VECTOR res, OPTIONAL EDGEWEIGHTS weights, diff --git a/src/vendor/cigraph/src/properties/triangles.c b/src/vendor/cigraph/src/properties/triangles.c index 3d9091c2ab..ea21c355f2 100644 --- a/src/vendor/cigraph/src/properties/triangles.c +++ b/src/vendor/cigraph/src/properties/triangles.c @@ -113,7 +113,7 @@ igraph_error_t igraph_transitivity_avglocal_undirected(const igraph_t *graph, return IGRAPH_SUCCESS; } -static igraph_error_t igraph_transitivity_local_undirected1(const igraph_t *graph, +static igraph_error_t transitivity_local_undirected1(const igraph_t *graph, igraph_vector_t *res, const igraph_vs_t vids, igraph_transitivity_mode_t mode) { @@ -125,7 +125,7 @@ static igraph_error_t igraph_transitivity_local_undirected1(const igraph_t *grap return IGRAPH_SUCCESS; } -static igraph_error_t igraph_transitivity_local_undirected2(const igraph_t *graph, +static igraph_error_t transitivity_local_undirected2(const igraph_t *graph, igraph_vector_t *res, const igraph_vs_t vids, igraph_transitivity_mode_t mode) { @@ -321,7 +321,7 @@ igraph_error_t igraph_i_trans4_al_simplify(igraph_adjlist_t *al, return IGRAPH_SUCCESS; } -static igraph_error_t igraph_transitivity_local_undirected4(const igraph_t *graph, +static igraph_error_t transitivity_local_undirected4(const igraph_t *graph, igraph_vector_t *res, igraph_transitivity_mode_t mode) { @@ -378,7 +378,7 @@ igraph_error_t igraph_transitivity_local_undirected(const igraph_t *graph, igraph_transitivity_mode_t mode) { if (igraph_vs_is_all(&vids)) { - return igraph_transitivity_local_undirected4(graph, res, mode); + return transitivity_local_undirected4(graph, res, mode); } else { igraph_vit_t vit; igraph_integer_t size; @@ -388,28 +388,128 @@ igraph_error_t igraph_transitivity_local_undirected(const igraph_t *graph, igraph_vit_destroy(&vit); IGRAPH_FINALLY_CLEAN(1); if (size < 100) { - return igraph_transitivity_local_undirected1(graph, res, vids, mode); + return transitivity_local_undirected1(graph, res, vids, mode); } else { - return igraph_transitivity_local_undirected2(graph, res, vids, mode); + return transitivity_local_undirected2(graph, res, vids, mode); } } } -static igraph_error_t igraph_adjacent_triangles1(const igraph_t *graph, +static igraph_error_t adjacent_triangles1(const igraph_t *graph, igraph_vector_t *res, const igraph_vs_t vids) { # include "properties/triangles_template1.h" return IGRAPH_SUCCESS; } -static igraph_error_t igraph_adjacent_triangles4(const igraph_t *graph, +static igraph_error_t adjacent_triangles4(const igraph_t *graph, igraph_vector_t *res) { # include "properties/triangles_template.h" return IGRAPH_SUCCESS; } +static igraph_error_t count_triangles_and_triples( + const igraph_t *graph, igraph_real_t *triangles, igraph_real_t *connected_triples) +{ + const igraph_integer_t vcount = igraph_vcount(graph); + igraph_vector_int_t mark; + igraph_adjlist_t al; + + IGRAPH_CHECK(igraph_adjlist_init(graph, &al, IGRAPH_ALL, IGRAPH_NO_LOOPS, IGRAPH_NO_MULTIPLE)); + IGRAPH_FINALLY(igraph_adjlist_destroy, &al); + + IGRAPH_VECTOR_INT_INIT_FINALLY(&mark, vcount); + + *triangles = 0; + if (connected_triples) *connected_triples = 0; + + /* In a simple graph we could loop through all edges and count how many common + * neighbours their endpoints have. However, we only need to consider each + * connected vertex pair once, even if there are multiple edges between them. + * The nested for loop below uses an adjlist that already has multi-edges and + * self-loops filtered, and solves this problem. + * + * Performance trick: + * + * We only consider connected u-v pairs when v < u to avoid triple-counting + * and speed up the procedure. This effectively orients an undirected graph + * as directed acyclic. In an arbitrary orientation, an originally undirected + * triangle may appear as one of these two directed patterns: + * - A -> B -> C -> A. This is NOT acyclic, so we don't encounter it. + * - A -> B -> C, A -> C. This is the only one we need to count. + * This is implemented through the `if (v >= u) break;` lines below. + * + * Some other functions achieve the same via igraph_i_trans4_al_simplify(). + */ + for (igraph_integer_t v1 = 0; v1 < vcount; v1++) { + const igraph_vector_int_t *nei1 = igraph_adjlist_get(&al, v1); + const igraph_integer_t d1 = igraph_vector_int_size(nei1); + if (d1 > 1) { + if (connected_triples) { + *connected_triples += (igraph_real_t) d1 * (d1 - 1.0) / 2.0; + } + + for (igraph_integer_t i=0; i < d1; i++) { + const igraph_integer_t v2 = VECTOR(*nei1)[i]; + if (v2 >= v1) break; + + VECTOR(mark)[v2] = v1+1; + } + for (igraph_integer_t i=0; i < d1; i++) { + const igraph_integer_t v2 = VECTOR(*nei1)[i]; + if (v2 >= v1) break; + + const igraph_vector_int_t *nei2 = igraph_adjlist_get(&al, v2); + const igraph_integer_t d2 = igraph_vector_int_size(nei2); + for (igraph_integer_t j=0; j < d2; j++) { + const igraph_integer_t v3 = VECTOR(*nei2)[j]; + if (v3 >= v2) break; + + if (VECTOR(mark)[v3] == v1+1) { + *triangles += 1; + } + } + } + } + } + + igraph_vector_int_destroy(&mark); + igraph_adjlist_destroy(&al); + IGRAPH_FINALLY_CLEAN(2); + + return IGRAPH_SUCCESS; +} + + /** - * \function igraph_adjacent_triangles + * \ingroup structural + * \function igraph_count_triangles + * \brief Counts triangles in a graph. + * + * This function computes the total number of triangles, i.e. fully connected + * vertex triples, in a graph. Edge directions, edge multiplicities, and self-loops + * are ignored. + * + * \param graph The graph object. Edge directions and multiplicites are ignored. + * \param res Pointer to a real variable, the result will be stored here. + * \return Error code: + * \c IGRAPH_ENOMEM: not enough memory for + * temporary data. + * + * \sa \ref igraph_list_triangles(), \ref igraph_count_adjacent_triangles(), + * \ref igraph_transitivity_undirected(). + * + * Time complexity: O(|V|*d^2), |V| is the number of vertices in + * the graph, d is the average node degree. + */ + +igraph_error_t igraph_count_triangles(const igraph_t *graph, igraph_real_t *res) { + return count_triangles_and_triples(graph, res, NULL); +} + + +/** + * \function igraph_count_adjacent_triangles * \brief Count the number of triangles a vertex is part of. * * \param graph The input graph. Edge directions and multiplicities are ignored. @@ -417,22 +517,46 @@ static igraph_error_t igraph_adjacent_triangles4(const igraph_t *graph, * \param vids The vertices to perform the calculation for. * \return Error mode. * - * \sa \ref igraph_list_triangles() to list them. + * \sa \ref igraph_list_triangles() to list triangles, + * \ref igraph_count_triangles() to count all triangles at once. * * Time complexity: O(d^2 n), d is the average vertex degree of the * queried vertices, n is their number. */ -igraph_error_t igraph_adjacent_triangles(const igraph_t *graph, +igraph_error_t igraph_count_adjacent_triangles(const igraph_t *graph, igraph_vector_t *res, const igraph_vs_t vids) { if (igraph_vs_is_all(&vids)) { - return igraph_adjacent_triangles4(graph, res); + return adjacent_triangles4(graph, res); } else { - return igraph_adjacent_triangles1(graph, res, vids); + return adjacent_triangles1(graph, res, vids); } } +/** + * \function igraph_adjacent_triangles + * \brief Count the number of triangles a vertex is part of (deprecated alias). + * + * \deprecated-by igraph_count_adjacent_triangles 0.10.15 + * + * \param graph The input graph. Edge directions and multiplicities are ignored. + * \param res Initiliazed vector, the results are stored here. + * \param vids The vertices to perform the calculation for. + * \return Error mode. + * + * \sa \ref igraph_list_triangles() to list them. + * + * Time complexity: O(d^2 n), d is the average vertex degree of the + * queried vertices, n is their number. + */ + +igraph_error_t igraph_adjacent_triangles(const igraph_t *graph, + igraph_vector_t *res, + const igraph_vs_t vids) { + return igraph_count_adjacent_triangles(graph, res, vids); +} + /** * \function igraph_list_triangles * \brief Find all triangles in a graph. @@ -451,9 +575,10 @@ igraph_error_t igraph_adjacent_triangles(const igraph_t *graph, * listed exactly once. * \return Error code. * - * \sa \ref igraph_transitivity_undirected() to count the triangles, + * \sa \ref igraph_count_triangles() to count the triangles, * \ref igraph_adjacent_triangles() to count the triangles a vertex - * participates in. + * participates in, \ref igraph_transitivity_undirected() to compute + * the global clustering coefficient. * * Time complexity: O(d^2 n), d is the average degree, n is the number * of vertices. @@ -518,90 +643,20 @@ igraph_error_t igraph_transitivity_undirected(const igraph_t *graph, igraph_real_t *res, igraph_transitivity_mode_t mode) { - const igraph_integer_t no_of_nodes = igraph_vcount(graph); - igraph_real_t triples = 0, triangles = 0; - igraph_integer_t maxdegree; - igraph_integer_t *neis; - igraph_vector_int_t order; - igraph_vector_t rank; - igraph_vector_int_t degree; - - igraph_adjlist_t allneis; - igraph_vector_int_t *neis1, *neis2; - igraph_integer_t neilen1, neilen2; - - if (no_of_nodes == 0) { - *res = mode == IGRAPH_TRANSITIVITY_ZERO ? 0.0 : IGRAPH_NAN; - return IGRAPH_SUCCESS; - } - - IGRAPH_VECTOR_INT_INIT_FINALLY(&order, no_of_nodes); - IGRAPH_VECTOR_INT_INIT_FINALLY(°ree, no_of_nodes); - - IGRAPH_CHECK(igraph_degree(graph, °ree, igraph_vss_all(), IGRAPH_ALL, IGRAPH_LOOPS)); - maxdegree = igraph_vector_int_max(°ree) + 1; - IGRAPH_CHECK(igraph_vector_int_order1(°ree, &order, maxdegree)); - - igraph_vector_int_destroy(°ree); - IGRAPH_FINALLY_CLEAN(1); - - IGRAPH_VECTOR_INIT_FINALLY(&rank, no_of_nodes); - for (igraph_integer_t i = 0; i < no_of_nodes; i++) { - VECTOR(rank)[ VECTOR(order)[i] ] = no_of_nodes - i - 1; - } - - IGRAPH_CHECK(igraph_adjlist_init(graph, &allneis, IGRAPH_ALL, IGRAPH_NO_LOOPS, IGRAPH_NO_MULTIPLE)); - IGRAPH_FINALLY(igraph_adjlist_destroy, &allneis); - - neis = IGRAPH_CALLOC(no_of_nodes, igraph_integer_t); - IGRAPH_CHECK_OOM(neis, "Insufficient memory for undirected global transitivity."); - IGRAPH_FINALLY(igraph_free, neis); - - for (igraph_integer_t nn = no_of_nodes - 1; nn >= 0; nn--) { - const igraph_integer_t node = VECTOR(order)[nn]; - - IGRAPH_ALLOW_INTERRUPTION(); - - neis1 = igraph_adjlist_get(&allneis, node); - neilen1 = igraph_vector_int_size(neis1); - triples += (igraph_real_t) neilen1 * (neilen1 - 1); - /* Mark the neighbors of 'node' */ - for (igraph_integer_t i = 0; i < neilen1; i++) { - igraph_integer_t nei = VECTOR(*neis1)[i]; - neis[nei] = node + 1; - } - for (igraph_integer_t i = 0; i < neilen1; i++) { - igraph_integer_t nei = VECTOR(*neis1)[i]; - /* If 'nei' is not ready yet */ - if (VECTOR(rank)[nei] > VECTOR(rank)[node]) { - neis2 = igraph_adjlist_get(&allneis, nei); - neilen2 = igraph_vector_int_size(neis2); - for (igraph_integer_t j = 0; j < neilen2; j++) { - igraph_integer_t nei2 = VECTOR(*neis2)[j]; - if (neis[nei2] == node + 1) { - triangles += 1.0; - } - } - } - } - } + igraph_real_t triangles, connected_triples; - IGRAPH_FREE(neis); - igraph_adjlist_destroy(&allneis); - igraph_vector_destroy(&rank); - igraph_vector_int_destroy(&order); - IGRAPH_FINALLY_CLEAN(4); + IGRAPH_CHECK(count_triangles_and_triples(graph, &triangles, &connected_triples)); - if (triples == 0 && mode == IGRAPH_TRANSITIVITY_ZERO) { + if (connected_triples == 0 && mode == IGRAPH_TRANSITIVITY_ZERO) { *res = 0; } else { - *res = triangles / triples * 2.0; + *res = triangles / connected_triples * 3.0; } return IGRAPH_SUCCESS; } -static igraph_error_t igraph_i_transitivity_barrat1( +static igraph_error_t transitivity_barrat1( const igraph_t *graph, igraph_vector_t *res, const igraph_vs_t vids, @@ -693,7 +748,7 @@ static igraph_error_t igraph_i_transitivity_barrat1( return IGRAPH_SUCCESS; } -static igraph_error_t igraph_i_transitivity_barrat4( +static igraph_error_t transitivity_barrat4( const igraph_t *graph, igraph_vector_t *res, const igraph_vector_t *weights, @@ -885,8 +940,8 @@ igraph_error_t igraph_transitivity_barrat(const igraph_t *graph, /* Preconditions validated, now we can call the real implementation */ if (igraph_vs_is_all(&vids)) { - return igraph_i_transitivity_barrat4(graph, res, weights, mode); + return transitivity_barrat4(graph, res, weights, mode); } else { - return igraph_i_transitivity_barrat1(graph, res, vids, weights, mode); + return transitivity_barrat1(graph, res, vids, weights, mode); } } diff --git a/src/vendor/igraph_version.h b/src/vendor/igraph_version.h index 2cc971dcd2..ff8368978d 100644 --- a/src/vendor/igraph_version.h +++ b/src/vendor/igraph_version.h @@ -28,11 +28,11 @@ __BEGIN_DECLS -#define IGRAPH_VERSION "0.10.15-53-g6981deb37" +#define IGRAPH_VERSION "0.10.15-65-g10ef19bc2" #define IGRAPH_VERSION_MAJOR 0 #define IGRAPH_VERSION_MINOR 10 #define IGRAPH_VERSION_PATCH 15 -#define IGRAPH_VERSION_PRERELEASE "53-g6981deb37" +#define IGRAPH_VERSION_PRERELEASE "65-g10ef19bc2" IGRAPH_EXPORT void igraph_version(const char **version_string, int *major,