/* -*- mode: C -*- */ /* IGraph library. Copyright (C) 2006-2012 Gabor Csardi 334 Harvard street, Cambridge, MA 02139 USA 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_community.h" #include "igraph_memory.h" #include "igraph_interface.h" #include "igraph_iterators.h" #include "config.h" /** * \function igraph_coreness * \brief Finding the coreness of the vertices in a network. * * The k-core of a graph is a maximal subgraph in which each vertex * has at least degree k. (Degree here means the degree in the * subgraph of course.). The coreness of a vertex is the highest order * of a k-core containing the vertex. * * * This function implements the algorithm presented in Vladimir * Batagelj, Matjaz Zaversnik: An O(m) Algorithm for Cores * Decomposition of Networks. * \param graph The input graph. * \param cores Pointer to an initialized vector, the result of the * computation will be stored here. It will be resized as * needed. For each vertex it contains the highest order of a * core containing the vertex. * \param mode For directed graph it specifies whether to calculate * in-cores, out-cores or the undirected version. It is ignored * for undirected graphs. Possible values: \c IGRAPH_ALL * undirected version, \c IGRAPH_IN in-cores, \c IGRAPH_OUT * out-cores. * \return Error code. * * Time complexity: O(|E|), the number of edges. */ int igraph_coreness(const igraph_t *graph, igraph_vector_t *cores, igraph_neimode_t mode) { long int no_of_nodes = igraph_vcount(graph); long int *bin, *vert, *pos; long int maxdeg; long int i, j = 0; igraph_vector_t neis; igraph_neimode_t omode; if (mode != IGRAPH_ALL && mode != IGRAPH_OUT && mode != IGRAPH_IN) { IGRAPH_ERROR("Invalid mode in k-cores", IGRAPH_EINVAL); } if (!igraph_is_directed(graph) || mode == IGRAPH_ALL) { mode = omode = IGRAPH_ALL; } else if (mode == IGRAPH_IN) { omode = IGRAPH_OUT; } else { omode = IGRAPH_IN; } vert = igraph_Calloc(no_of_nodes, long int); if (vert == 0) { IGRAPH_ERROR("Cannot calculate k-cores", IGRAPH_ENOMEM); } IGRAPH_FINALLY(igraph_free, vert); pos = igraph_Calloc(no_of_nodes, long int); if (pos == 0) { IGRAPH_ERROR("Cannot calculate k-cores", IGRAPH_ENOMEM); } IGRAPH_FINALLY(igraph_free, pos); /* maximum degree + degree of vertices */ IGRAPH_CHECK(igraph_degree(graph, cores, igraph_vss_all(), mode, IGRAPH_LOOPS)); maxdeg = (long int) igraph_vector_max(cores); bin = igraph_Calloc(maxdeg + 1, long int); if (bin == 0) { IGRAPH_ERROR("Cannot calculate k-cores", IGRAPH_ENOMEM); } IGRAPH_FINALLY(igraph_free, bin); /* degree histogram */ for (i = 0; i < no_of_nodes; i++) { bin[ (long int)VECTOR(*cores)[i] ] += 1; } /* start pointers */ j = 0; for (i = 0; i <= maxdeg; i++) { long int k = bin[i]; bin[i] = j; j += k; } /* sort in vert (and corrupt bin) */ for (i = 0; i < no_of_nodes; i++) { pos[i] = bin[(long int)VECTOR(*cores)[i]]; vert[pos[i]] = i; bin[(long int)VECTOR(*cores)[i]] += 1; } /* correct bin */ for (i = maxdeg; i > 0; i--) { bin[i] = bin[i - 1]; } bin[0] = 0; /* this is the main algorithm */ IGRAPH_VECTOR_INIT_FINALLY(&neis, maxdeg); for (i = 0; i < no_of_nodes; i++) { long int v = vert[i]; IGRAPH_CHECK(igraph_neighbors(graph, &neis, (igraph_integer_t) v, omode)); for (j = 0; j < igraph_vector_size(&neis); j++) { long int u = (long int) VECTOR(neis)[j]; if (VECTOR(*cores)[u] > VECTOR(*cores)[v]) { long int du = (long int) VECTOR(*cores)[u]; long int pu = pos[u]; long int pw = bin[du]; long int w = vert[pw]; if (u != w) { pos[u] = pw; pos[w] = pu; vert[pu] = w; vert[pw] = u; } bin[du] += 1; VECTOR(*cores)[u] -= 1; } } } igraph_vector_destroy(&neis); IGRAPH_FINALLY_CLEAN(1); igraph_free(bin); igraph_free(pos); igraph_free(vert); IGRAPH_FINALLY_CLEAN(3); return 0; }