/* -*- mode: C -*- */ /* IGraph library. Copyright (C) 2003, 2004, 2005 Gabor Csardi MTA RMKI, Konkoly-Thege Miklos st. 29-33, Budapest 1121, Hungary 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.h" #include "memory.h" #include #include int igraph_clusters_weak(const igraph_t *graph, igraph_vector_t *membership, igraph_vector_t *csize, igraph_integer_t *no); int igraph_clusters_strong(const igraph_t *graph, igraph_vector_t *membership, igraph_vector_t *csize, igraph_integer_t *no); /** * \ingroup structural * \function igraph_clusters * \brief Calculates the (weakly or strongly) connected components in * a graph. * * \param graph The graph object to analyze. * \param membership First half of the result will be stored here. For * every vertex the id of its component is given. The vector * has to be preinitialized and will be resized. Alternatively * this argument can be \c NULL, in which case it is ignored. * \param csize The second half of the result. For every component it * gives its size, the order is defined by the component ids. * The vector has to be preinitialized and will be resized. * Alternatively this argument can be \c NULL, in which * case it is ignored. * \param no Pointer to an integer, if not \c NULL then the number of * clusters will be stored here. * \param mode For directed graph this specifies whether to calculate * weakly or strongly connected components. Possible values: * \c IGRAPH_WEAK, * \c IGRAPH_STRONG. This argument is * ignored for undirected graphs. * \return Error code: * \c IGRAPH_EINVAL: invalid mode argument. * * Time complexity: O(|V|+|E|), * |V| and * |E| are the number of vertices and * edges in the graph. */ int igraph_clusters(const igraph_t *graph, igraph_vector_t *membership, igraph_vector_t *csize, igraph_integer_t *no, igraph_connectedness_t mode) { if (mode==IGRAPH_WEAK || !igraph_is_directed(graph)) { return igraph_clusters_weak(graph, membership, csize, no); } else if (mode==IGRAPH_STRONG) { return igraph_clusters_strong(graph, membership, csize, no); } else { IGRAPH_ERROR("Cannot calculate clusters", IGRAPH_EINVAL); } return 1; } int igraph_clusters_weak(const igraph_t *graph, igraph_vector_t *membership, igraph_vector_t *csize, igraph_integer_t *no) { long int no_of_nodes=igraph_vcount(graph); char *already_added; long int first_node, act_cluster_size=0, no_of_clusters=1; igraph_dqueue_t q=IGRAPH_DQUEUE_NULL; long int i; igraph_vector_t neis=IGRAPH_VECTOR_NULL; already_added=Calloc(no_of_nodes,char); if (already_added==0) { IGRAPH_ERROR("Cannot calculate clusters", IGRAPH_ENOMEM); } IGRAPH_FINALLY(igraph_free, already_added); IGRAPH_DQUEUE_INIT_FINALLY(&q, no_of_nodes > 100000 ? 10000 : no_of_nodes/10); IGRAPH_VECTOR_INIT_FINALLY(&neis, 0); /* Memory for result, csize is dynamically allocated */ if (membership) { IGRAPH_CHECK(igraph_vector_resize(membership, no_of_nodes)); } if (csize) { igraph_vector_clear(csize); } /* The algorithm */ for (first_node=0; first_node < no_of_nodes; ++first_node) { if (already_added[first_node]==1) continue; IGRAPH_ALLOW_INTERRUPTION(); already_added[first_node]=1; act_cluster_size=1; if (membership) { VECTOR(*membership)[first_node]=no_of_clusters-1; } IGRAPH_CHECK(igraph_dqueue_push(&q, first_node)); while ( !igraph_dqueue_empty(&q) ) { long int act_node=igraph_dqueue_pop(&q); IGRAPH_CHECK(igraph_neighbors(graph, &neis, act_node, IGRAPH_ALL)); for (i=0; i igraph_vector_size(&tmp)) { continue; } IGRAPH_CHECK(igraph_dqueue_push(&q, i)); while (!igraph_dqueue_empty(&q)) { long int act_node=igraph_dqueue_back(&q); IGRAPH_CHECK(igraph_neighbors(graph, &tmp, act_node, IGRAPH_OUT)); if (VECTOR(next_nei)[act_node]==0) { /* this is the first time we've met this vertex */ VECTOR(next_nei)[act_node]++; } else if (VECTOR(next_nei)[act_node] <= igraph_vector_size(&tmp)) { /* we've already met this vertex but it has more children */ long int neighbor=VECTOR(tmp)[(long int)VECTOR(next_nei)[act_node]-1]; if (VECTOR(next_nei)[neighbor] == 0) { IGRAPH_CHECK(igraph_dqueue_push(&q, neighbor)); } VECTOR(next_nei)[act_node]++; } else { /* we've met this vertex and it has no more children */ IGRAPH_CHECK(igraph_vector_push_back(&out, act_node)); igraph_dqueue_pop_back(&q); } } /* while q */ } /* for */ /* OK, we've the 'out' values for the nodes, let's use them in descreasing order with the help of a heap */ igraph_vector_null(&next_nei); /* mark already added vertices */ while (!igraph_vector_empty(&out)) { long int grandfather=igraph_vector_pop_back(&out); IGRAPH_ALLOW_INTERRUPTION(); if (VECTOR(next_nei)[grandfather] != 0) { continue; } VECTOR(next_nei)[grandfather]=1; act_cluster_size=1; if (membership) { VECTOR(*membership)[grandfather]=no_of_clusters-1; } IGRAPH_CHECK(igraph_dqueue_push(&q, grandfather)); while (!igraph_dqueue_empty(&q)) { long int act_node=igraph_dqueue_pop_back(&q); IGRAPH_CHECK(igraph_neighbors(graph, &tmp, act_node, IGRAPH_IN)); for (i=0; i * * Time complexity: O(|V|+|E|), the number of vertices plus the number * of edges. */ int igraph_decompose(const igraph_t *graph, igraph_vector_ptr_t *components, igraph_connectedness_t mode, long int maxcompno, long int minelements) { long int actstart; long int no_of_nodes=igraph_vcount(graph); long int resco=0; /* number of graphs created so far */ char *already_added; igraph_dqueue_t q; igraph_vector_t verts; igraph_vector_t neis; long int i; igraph_t *newg; if (!igraph_is_directed(graph)) { mode=IGRAPH_WEAK; } if (mode != IGRAPH_WEAK) { IGRAPH_ERROR("only 'IGRAPH_WEAK' is implemented", IGRAPH_EINVAL); } if (maxcompno<0) { maxcompno=LONG_MAX; } already_added=Calloc(no_of_nodes, char); if (already_added==0) { IGRAPH_ERROR("Cannot decompose graph", IGRAPH_ENOMEM); } IGRAPH_FINALLY(igraph_free, already_added); IGRAPH_CHECK(igraph_dqueue_init(&q, 100)); IGRAPH_VECTOR_INIT_FINALLY(&verts, 0); IGRAPH_VECTOR_INIT_FINALLY(&neis, 0); igraph_vector_ptr_clear(components); IGRAPH_FINALLY(igraph_i_decompose_free, components); for(actstart=0; resco