/* call-seq: * graph.maxdegree(vs,mode,loops) -> Vertex * * Returns the vertex Object in the vs Array with the largest degree. * mode defines the type * of the degree. IGRAPH_OUT, out-degree, IGRAPH_IN, in-degree, IGRAPH_ALL, * total degree (sum of the in- and out-degree). This parameter is ignored * for undirected graphs. loops is a boolean gives whether the self-loops * should be counted. */ VALUE cIGraph_maxdegree(VALUE self, VALUE vs, VALUE mode, VALUE loops){ igraph_t *graph; igraph_bool_t loop = 0; igraph_integer_t res; igraph_neimode_t pmode = NUM2INT(mode); igraph_vs_t vids; igraph_vector_t vidv; if(loops == Qtrue) loop = 1; Data_Get_Struct(self, igraph_t, graph); //Convert an array of vertices to a vector of vertex ids igraph_vector_init_int(&vidv,0); cIGraph_vertex_arr_to_id_vec(self,vs,&vidv); //create vertex selector from the vecotr of ids igraph_vs_vector(&vids,&vidv); igraph_maxdegree(graph,&res,vids,pmode,loop); igraph_vector_destroy(&vidv); igraph_vs_destroy(&vids); return INT2NUM(res); }
int igraph_cohesive_blocks(const igraph_t *graph, igraph_vector_ptr_t *blocks, igraph_vector_t *cohesion, igraph_vector_t *parent, igraph_t *block_tree) { /* Some implementation comments. Everything is relatively straightforward, except, that we need to follow the vertex ids of the various subgraphs, without having to store two-way mappings at each level. The subgraphs can overlap, this complicates things a bit. The 'Q' vector is used as a double ended queue and it contains the subgraphs to work on in the future. Some other vectors are associated with it. 'Qparent' gives the parent graph of a graph in Q. Qmapping gives the mapping of the vertices from the graph to the parent graph. Qcohesion is the vertex connectivity of the graph. Qptr is an integer and points to the next graph to work on. */ igraph_vector_ptr_t Q; igraph_vector_ptr_t Qmapping; igraph_vector_long_t Qparent; igraph_vector_long_t Qcohesion; igraph_vector_bool_t Qcheck; long int Qptr=0; igraph_integer_t conn; igraph_bool_t is_simple; igraph_t *graph_copy; igraph_vector_ptr_t separators; igraph_vector_t compvertices; igraph_vector_long_t components; igraph_vector_bool_t marked; igraph_vector_long_t compid; igraph_dqueue_t bfsQ; igraph_vector_t neis; if (igraph_is_directed(graph)) { IGRAPH_ERROR("Cohesive blocking only works on undirected graphs", IGRAPH_EINVAL); } IGRAPH_CHECK(igraph_is_simple(graph, &is_simple)); if (!is_simple) { IGRAPH_ERROR("Cohesive blocking only works on simple graphs", IGRAPH_EINVAL); } IGRAPH_STATUS("Starting cohesive block calculation.\n", 0); if (blocks) { igraph_vector_ptr_clear(blocks); } if (cohesion) { igraph_vector_clear(cohesion); } if (parent) { igraph_vector_clear(parent); } IGRAPH_CHECK(igraph_vector_ptr_init(&Q, 1)); IGRAPH_FINALLY(igraph_vector_ptr_destroy, &Q); IGRAPH_FINALLY(igraph_i_cohesive_blocks_free, &Q); IGRAPH_CHECK(igraph_vector_ptr_init(&Qmapping, 1)); IGRAPH_FINALLY(igraph_vector_ptr_destroy, &Qmapping); IGRAPH_FINALLY(igraph_i_cohesive_blocks_free2, &Qmapping); IGRAPH_CHECK(igraph_vector_long_init(&Qparent, 1)); IGRAPH_FINALLY(igraph_vector_long_destroy, &Qparent); IGRAPH_CHECK(igraph_vector_long_init(&Qcohesion, 1)); IGRAPH_FINALLY(igraph_vector_long_destroy, &Qcohesion); IGRAPH_CHECK(igraph_vector_bool_init(&Qcheck, 1)); IGRAPH_FINALLY(igraph_vector_bool_destroy, &Qcheck); IGRAPH_CHECK(igraph_vector_ptr_init(&separators, 0)); IGRAPH_FINALLY(igraph_vector_ptr_destroy, &separators); IGRAPH_VECTOR_INIT_FINALLY(&compvertices, 0); IGRAPH_CHECK(igraph_vector_bool_init(&marked, 0)); IGRAPH_FINALLY(igraph_vector_bool_destroy, &marked); IGRAPH_VECTOR_INIT_FINALLY(&neis, 0); IGRAPH_CHECK(igraph_dqueue_init(&bfsQ, 100)); IGRAPH_FINALLY(igraph_dqueue_destroy, &bfsQ); IGRAPH_CHECK(igraph_vector_long_init(&compid, 0)); IGRAPH_FINALLY(igraph_vector_long_destroy, &compid); IGRAPH_CHECK(igraph_vector_long_init(&components, 0)); IGRAPH_FINALLY(igraph_vector_long_destroy, &components); /* Put the input graph in the queue */ graph_copy=igraph_Calloc(1, igraph_t); if (!graph_copy) { IGRAPH_ERROR("Cannot do cohesive blocking", IGRAPH_ENOMEM); } IGRAPH_CHECK(igraph_copy(graph_copy, graph)); VECTOR(Q)[0] = graph_copy; VECTOR(Qmapping)[0] = 0; /* Identity mapping */ VECTOR(Qparent)[0] = -1; /* Has no parent */ IGRAPH_CHECK(igraph_vertex_connectivity(graph, &conn, /*checks=*/ 1)); VECTOR(Qcohesion)[0] = conn; VECTOR(Qcheck)[0] = 0; /* Then work until the queue is empty */ while (Qptr < igraph_vector_ptr_size(&Q)) { igraph_t *mygraph=VECTOR(Q)[Qptr]; igraph_bool_t mycheck=VECTOR(Qcheck)[Qptr]; long int mynodes=igraph_vcount(mygraph); long int i, nsep; long int no, kept=0; long int cptr=0; long int nsepv=0; igraph_bool_t addedsep=0; IGRAPH_STATUSF(("Candidate %li: %li vertices,", 0, Qptr, mynodes)); IGRAPH_ALLOW_INTERRUPTION(); /* Get the separators */ IGRAPH_CHECK(igraph_minimum_size_separators(mygraph, &separators)); IGRAPH_FINALLY(igraph_i_cohesive_blocks_free3, &separators); nsep=igraph_vector_ptr_size(&separators); IGRAPH_STATUSF((" %li separators,", 0, nsep)); /* Remove them from the graph, also mark them */ IGRAPH_CHECK(igraph_vector_bool_resize(&marked, mynodes)); igraph_vector_bool_null(&marked); for (i=0; i<nsep; i++) { igraph_vector_t *v=VECTOR(separators)[i]; long int j, n=igraph_vector_size(v); for (j=0; j<n; j++) { long int vv=(long int) VECTOR(*v)[j]; if (!VECTOR(marked)[vv]) { nsepv++; VECTOR(marked)[vv] = 1; } } } /* Find the connected components, omitting the separator vertices, but including the neighboring separator vertices */ IGRAPH_CHECK(igraph_i_cb_components(mygraph, &marked, &components, &no, &compid, &bfsQ, &neis)); /* Add the separator vertices themselves, as another component, but only if there is at least one vertex not included in any separator. */ if (nsepv != mynodes) { addedsep=1; for (i=0; i<mynodes; i++) { if (VECTOR(marked)[i]) { IGRAPH_CHECK(igraph_vector_long_push_back(&components, i)); } } IGRAPH_CHECK(igraph_vector_long_push_back(&components, -1)); no++; } IGRAPH_STATUSF((" %li new candidates,", 0, no)); for (i=0; i<no; i++) { igraph_vector_t *newmapping; igraph_t *newgraph; igraph_integer_t maxdeg; igraph_vector_clear(&compvertices); while (1) { long int v=VECTOR(components)[cptr++]; if (v < 0) { break; } IGRAPH_CHECK(igraph_vector_push_back(&compvertices, v)); } newmapping=igraph_Calloc(1, igraph_vector_t); if (!newmapping) { IGRAPH_ERROR("Cannot do cohesive blocking", IGRAPH_ENOMEM); } IGRAPH_FINALLY(igraph_free, newmapping); IGRAPH_VECTOR_INIT_FINALLY(newmapping, 0); newgraph=igraph_Calloc(1, igraph_t); if (!newgraph) { IGRAPH_ERROR("Cannot do cohesive blocking", IGRAPH_ENOMEM); } IGRAPH_FINALLY(igraph_free, newgraph); IGRAPH_CHECK(igraph_induced_subgraph_map(mygraph, newgraph, igraph_vss_vector(&compvertices), IGRAPH_SUBGRAPH_AUTO, /*map=*/ 0, /*invmap=*/ newmapping)); IGRAPH_FINALLY(igraph_destroy, newgraph); IGRAPH_CHECK(igraph_maxdegree(newgraph, &maxdeg, igraph_vss_all(), IGRAPH_ALL, IGRAPH_LOOPS)); if (maxdeg > VECTOR(Qcohesion)[Qptr]) { igraph_integer_t newconn; kept++; IGRAPH_CHECK(igraph_vector_ptr_push_back(&Q, newgraph)); IGRAPH_FINALLY_CLEAN(2); IGRAPH_CHECK(igraph_vector_ptr_push_back(&Qmapping, newmapping)); IGRAPH_FINALLY_CLEAN(2); IGRAPH_CHECK(igraph_vertex_connectivity(newgraph, &newconn, /*checks=*/ 1)); IGRAPH_CHECK(igraph_vector_long_push_back(&Qcohesion, newconn)); IGRAPH_CHECK(igraph_vector_long_push_back(&Qparent, Qptr)); IGRAPH_CHECK(igraph_vector_bool_push_back(&Qcheck, mycheck || addedsep)); } else { igraph_destroy(newgraph); igraph_free(newgraph); igraph_vector_destroy(newmapping); igraph_free(newmapping); IGRAPH_FINALLY_CLEAN(4); } } IGRAPH_STATUSF((" keeping %li.\n", 0, kept)); igraph_destroy(mygraph); igraph_free(mygraph); VECTOR(Q)[Qptr] = 0; igraph_i_cohesive_blocks_free3(&separators); IGRAPH_FINALLY_CLEAN(1); Qptr++; } igraph_vector_long_destroy(&components); igraph_vector_long_destroy(&compid); igraph_dqueue_destroy(&bfsQ); igraph_vector_destroy(&neis); igraph_vector_bool_destroy(&marked); igraph_vector_destroy(&compvertices); igraph_vector_ptr_destroy(&separators); IGRAPH_FINALLY_CLEAN(7); if (blocks || cohesion || parent || block_tree) { igraph_integer_t noblocks=(igraph_integer_t) Qptr, badblocks=0; igraph_vector_bool_t removed; long int i, resptr=0; igraph_vector_long_t rewritemap; IGRAPH_CHECK(igraph_vector_bool_init(&removed, noblocks)); IGRAPH_FINALLY(igraph_vector_bool_destroy, &removed); IGRAPH_CHECK(igraph_vector_long_init(&rewritemap, noblocks)); IGRAPH_FINALLY(igraph_vector_long_destroy, &rewritemap); for (i=1; i<noblocks; i++) { long int p=VECTOR(Qparent)[i]; while (VECTOR(removed)[p]) { p=VECTOR(Qparent)[p]; } if (VECTOR(Qcohesion)[p] >= VECTOR(Qcohesion)[i]) { VECTOR(removed)[i]=1; badblocks++; } } /* Rewrite the mappings */ for (i=1; i<Qptr; i++) { long int p=VECTOR(Qparent)[i]; igraph_vector_t *mapping=VECTOR(Qmapping)[i]; igraph_vector_t *pmapping=VECTOR(Qmapping)[p]; long int j, n=igraph_vector_size(mapping); if (!pmapping) { continue; } for (j=0; j<n; j++) { long int v=(long int) VECTOR(*mapping)[j]; VECTOR(*mapping)[j] = VECTOR(*pmapping)[v]; } } /* Because we also put the separator vertices in the queue, it is not ensured that the found blocks are not subsets of each other. We check this now. */ for (i=1; i<noblocks; i++) { long int j, ic; igraph_vector_t *ivec; if (!VECTOR(Qcheck)[i] || VECTOR(removed)[i]) { continue; } ivec=VECTOR(Qmapping)[i]; ic=VECTOR(Qcohesion)[i]; for (j=1; j<noblocks; j++) { igraph_vector_t *jvec; long int jc; if (j==i || !VECTOR(Qcheck)[j] || VECTOR(removed)[j]) { continue; } jvec=VECTOR(Qmapping)[j]; jc=VECTOR(Qcohesion)[j]; if (igraph_i_cb_isin(ivec, jvec) && jc >= ic) { badblocks++; VECTOR(removed)[i]=1; break; } } } noblocks -= badblocks; if (blocks) { IGRAPH_CHECK(igraph_vector_ptr_resize(blocks, noblocks)); } if (cohesion) { IGRAPH_CHECK(igraph_vector_resize(cohesion, noblocks)); } if (parent) { IGRAPH_CHECK(igraph_vector_resize(parent, noblocks)); } for (i=0; i<Qptr; i++) { if (VECTOR(removed)[i]) { IGRAPH_STATUSF(("Candidate %li ignored.\n", 0, i)); continue; } else { IGRAPH_STATUSF(("Candidate %li is a cohesive (sub)block\n", 0, i)); } VECTOR(rewritemap)[i] = resptr; if (cohesion) { VECTOR(*cohesion)[resptr]=VECTOR(Qcohesion)[i]; } if (parent || block_tree) { long int p=VECTOR(Qparent)[i]; while (p>=0 && VECTOR(removed)[p]) { p=VECTOR(Qparent)[p]; } if (p>=0) { p=VECTOR(rewritemap)[p]; } VECTOR(Qparent)[i]=p; if (parent) { VECTOR(*parent)[resptr]=p; } } if (blocks) { VECTOR(*blocks)[resptr]=VECTOR(Qmapping)[i]; VECTOR(Qmapping)[i]=0; } resptr++; } /* Plus the original graph */ if (blocks) { igraph_vector_t *orig=igraph_Calloc(1, igraph_vector_t); if (!orig) { IGRAPH_ERROR("Cannot do cohesive blocking", IGRAPH_ENOMEM); } IGRAPH_FINALLY(igraph_free, orig); IGRAPH_CHECK(igraph_vector_init_seq(orig, 0, igraph_vcount(graph)-1)); VECTOR(*blocks)[0]=orig; IGRAPH_FINALLY_CLEAN(1); } if (block_tree) { igraph_vector_t edges; long int eptr=0; IGRAPH_VECTOR_INIT_FINALLY(&edges, noblocks*2-2); for (i=1; i<Qptr; i++) { if (VECTOR(removed)[i]) { continue; } VECTOR(edges)[eptr++] = VECTOR(Qparent)[i]; VECTOR(edges)[eptr++] = VECTOR(rewritemap)[i]; } IGRAPH_CHECK(igraph_create(block_tree, &edges, noblocks, IGRAPH_DIRECTED)); igraph_vector_destroy(&edges); IGRAPH_FINALLY_CLEAN(1); } igraph_vector_long_destroy(&rewritemap); igraph_vector_bool_destroy(&removed); IGRAPH_FINALLY_CLEAN(2); } igraph_vector_bool_destroy(&Qcheck); igraph_vector_long_destroy(&Qcohesion); igraph_vector_long_destroy(&Qparent); igraph_i_cohesive_blocks_free2(&Qmapping); IGRAPH_FINALLY_CLEAN(4); igraph_vector_ptr_destroy(&Qmapping); igraph_vector_ptr_destroy(&Q); IGRAPH_FINALLY_CLEAN(3); /* + the elements of Q, they were already destroyed */ IGRAPH_STATUS("Cohesive blocking done.\n", 0); return 0; }
int igraph_revolver_d_d(const igraph_t *graph, igraph_integer_t niter, const igraph_vector_t *vtime, const igraph_vector_t *etime, igraph_matrix_t *kernel, igraph_matrix_t *sd, igraph_matrix_t *norm, igraph_matrix_t *cites, igraph_matrix_t *expected, igraph_real_t *logprob, igraph_real_t *lognull, const igraph_matrix_t *debug, igraph_vector_ptr_t *debugres) { igraph_integer_t no_of_events, vnoev, enoev; igraph_vector_t st; long int i; igraph_integer_t maxdegree; igraph_vector_t vtimeidx, etimeidx; igraph_lazy_inclist_t inclist; if (igraph_vector_size(vtime) != igraph_vcount(graph)) { IGRAPH_ERROR("Invalid vtime length", IGRAPH_EINVAL); } if (igraph_vector_size(etime) != igraph_ecount(graph)) { IGRAPH_ERROR("Invalid etime length", IGRAPH_EINVAL); } vnoev=(igraph_integer_t) igraph_vector_max(vtime)+1; enoev=(igraph_integer_t) igraph_vector_max(etime)+1; no_of_events= vnoev > enoev ? vnoev : enoev; IGRAPH_VECTOR_INIT_FINALLY(&st, no_of_events); for (i=0; i<no_of_events; i++) { VECTOR(st)[i]=1; } IGRAPH_CHECK(igraph_maxdegree(graph, &maxdegree, igraph_vss_all(), IGRAPH_ALL, IGRAPH_LOOPS)); IGRAPH_VECTOR_INIT_FINALLY(&vtimeidx, 0); IGRAPH_VECTOR_INIT_FINALLY(&etimeidx, 0); IGRAPH_CHECK(igraph_vector_order1(vtime, &vtimeidx, no_of_events)); IGRAPH_CHECK(igraph_vector_order1(etime, &etimeidx, no_of_events)); IGRAPH_CHECK(igraph_lazy_inclist_init(graph, &inclist, IGRAPH_ALL)); IGRAPH_FINALLY(igraph_lazy_inclist_destroy, &inclist); IGRAPH_PROGRESS("Revolver d-d", 0, NULL); for (i=0; i<niter; i++) { IGRAPH_ALLOW_INTERRUPTION(); if (i+1 != niter) { /* not the last iteration */ /* measure */ IGRAPH_CHECK(igraph_revolver_mes_d_d(graph, &inclist, kernel, 0 /*sd*/, 0 /*norm*/, 0/*cites*/, 0/*debug*/, 0 /*debugres*/, &st, vtime, &vtimeidx, etime, &etimeidx, no_of_events, maxdegree)); /* normalize */ igraph_matrix_scale(kernel, 1/igraph_matrix_sum(kernel)); /* update st */ IGRAPH_CHECK(igraph_revolver_st_d_d(graph, &inclist, &st, kernel, vtime, &vtimeidx, etime, &etimeidx, no_of_events)); } else { /* measure */ IGRAPH_CHECK(igraph_revolver_mes_d_d(graph, &inclist, kernel, sd, norm, cites, debug, debugres, &st, vtime, &vtimeidx, etime, &etimeidx, no_of_events, maxdegree)); /* normalize */ igraph_matrix_scale(kernel, 1/igraph_matrix_sum(kernel)); /* update st */ IGRAPH_CHECK(igraph_revolver_st_d_d(graph, &inclist, &st, kernel, vtime, &vtimeidx, etime, &etimeidx, no_of_events)); /* expected number of citations */ if (expected) { IGRAPH_CHECK(igraph_revolver_exp_d_d(graph, &inclist, expected, kernel, &st, vtime, &vtimeidx, etime, &etimeidx, no_of_events, maxdegree)); } /* error calculation */ if (logprob || lognull) { IGRAPH_CHECK(igraph_revolver_error_d_d(graph, &inclist, kernel, &st, vtime, &vtimeidx, etime, &etimeidx, no_of_events, maxdegree, logprob, lognull)); } } IGRAPH_PROGRESS("Revolver d-d", 100.0*(i+1)/niter, NULL); } igraph_lazy_inclist_destroy(&inclist); igraph_vector_destroy(&etimeidx); igraph_vector_destroy(&vtimeidx); igraph_vector_destroy(&st); IGRAPH_FINALLY_CLEAN(4); return 0; }