void igraph_i_union_many_free2(igraph_vector_ptr_t *v) { long int i, n=igraph_vector_ptr_size(v); for (i=0; i<n; i++) { if (VECTOR(*v)[i] != 0) { igraph_vector_long_destroy(VECTOR(*v)[i]); igraph_Free(VECTOR(*v)[i]); } } igraph_vector_ptr_destroy(v); }
void igraph_i_cohesive_blocks_free2(igraph_vector_ptr_t *ptr) { long int i, n=igraph_vector_ptr_size(ptr); for (i=0; i<n; i++) { igraph_vector_long_t *v=VECTOR(*ptr)[i]; if (v) { igraph_vector_long_destroy(v); igraph_free(v); } } }
int test_graph_from_leda_tutorial() { /* Test graph from the LEDA tutorial: * http://www.leda-tutorial.org/en/unofficial/ch05s03s05.html */ igraph_t graph; igraph_vector_bool_t types; igraph_vector_long_t matching; igraph_integer_t matching_size; igraph_bool_t is_matching; int i; igraph_small(&graph, 0, 0, 0, 8, 0, 12, 0, 14, 1, 9, 1, 10, 1, 13, 2, 8, 2, 9, 3, 10, 3, 11, 3, 13, 4, 9, 4, 14, 5, 14, 6, 9, 6, 14, 7, 8, 7, 12, 7, 14 , -1); igraph_vector_bool_init(&types, 15); for (i = 0; i < 15; i++) VECTOR(types)[i] = (i >= 8); igraph_vector_long_init(&matching, 0); igraph_i_maximum_bipartite_matching_unweighted(&graph, &types, &matching_size, &matching); if (matching_size != 6) { printf("matching_size is %ld, expected: 6\n", (long)matching_size); return 1; } igraph_is_maximal_matching(&graph, &types, &matching, &is_matching); if (!is_matching) { printf("not a matching: "); igraph_vector_long_print(&matching); return 3; } else igraph_vector_long_print(&matching); igraph_vector_long_destroy(&matching); igraph_vector_bool_destroy(&types); igraph_destroy(&graph); return 0; }
int igraph_revolver_mes_p_p(const igraph_t *graph, igraph_lazy_inclist_t *inclist, igraph_matrix_t *kernel, igraph_matrix_t *sd, igraph_matrix_t *norm, igraph_matrix_t *cites, const igraph_matrix_t *debug, igraph_vector_ptr_t *debugres, const igraph_vector_t *st, const igraph_vector_t *vtime, const igraph_vector_t *vtimeidx, const igraph_vector_t *etime, const igraph_vector_t *etimeidx, igraph_integer_t pno_of_events, const igraph_vector_t *authors, const igraph_vector_t *eventsizes, igraph_integer_t pmaxpapers) { long int no_of_nodes=igraph_vcount(graph); long int no_of_edges=igraph_ecount(graph); long int no_of_events=pno_of_events; long int maxpapers=pmaxpapers; igraph_vector_long_t papers; igraph_vector_char_t added; igraph_matrix_t v_normfact, *normfact, v_notnull, *notnull; igraph_matrix_t ch; igraph_vector_long_t ntk; igraph_matrix_t ntkk; igraph_vector_t *adjedges; long int timestep, i; long int nptr=0, eptr=0, aptr=0; long int nptr_save, eptr_save, eptr_new; IGRAPH_CHECK(igraph_vector_long_init(&papers, no_of_nodes)); IGRAPH_FINALLY(&igraph_vector_long_destroy, &papers); IGRAPH_CHECK(igraph_vector_char_init(&added, no_of_edges)); IGRAPH_FINALLY(igraph_vector_char_destroy, &added); IGRAPH_CHECK(igraph_vector_long_init(&ntk, maxpapers+1)); IGRAPH_FINALLY(igraph_vector_long_destroy, &ntk); IGRAPH_MATRIX_INIT_FINALLY(&ntkk, maxpapers+1, maxpapers+1); IGRAPH_MATRIX_INIT_FINALLY(&ch, maxpapers+1, maxpapers+1); if (norm) { normfact=norm; IGRAPH_CHECK(igraph_matrix_resize(normfact, maxpapers+1, maxpapers+1)); igraph_matrix_null(normfact); } else { normfact=&v_normfact; IGRAPH_MATRIX_INIT_FINALLY(normfact, maxpapers+1, maxpapers+1); } if (cites) { notnull=cites; IGRAPH_CHECK(igraph_matrix_resize(notnull, maxpapers+1, maxpapers+1)); igraph_matrix_null(notnull); } else { notnull=&v_notnull; IGRAPH_MATRIX_INIT_FINALLY(notnull, maxpapers+1, maxpapers+1); } IGRAPH_CHECK(igraph_matrix_resize(kernel, maxpapers+1, maxpapers+1)); igraph_matrix_null(kernel); if (sd) { IGRAPH_CHECK(igraph_matrix_resize(sd, maxpapers+1, maxpapers+1)); igraph_matrix_null(sd); } for (timestep=0; timestep<no_of_events; timestep++) { IGRAPH_ALLOW_INTERRUPTION(); nptr_save=nptr; while (nptr < no_of_nodes && VECTOR(*vtime)[(long int)VECTOR(*vtimeidx)[nptr]]==timestep) { nptr++; } /* If it is a new author then she has no papers yet */ VECTOR(ntk)[0] += (nptr-nptr_save); /* Update ch accordingly, could be done later as well */ if (VECTOR(ntk)[0] == nptr-nptr_save && nptr!=nptr_save) { if (nptr-nptr_save >= 2) { MATRIX(ch, 0, 0) = eptr; } for (i=1; i<maxpapers+1; i++) { if (NTKK(0,i) == (nptr-nptr_save)*VECTOR(ntk)[i]) { MATRIX(ch, 0, i) = MATRIX(ch, i, 0) = eptr; } } } /* print_ntkk(&ntkk, &ntk); */ /* Estimate Akk */ eptr_save=eptr; while (eptr < no_of_edges && VECTOR(*etime)[(long int)VECTOR(*etimeidx)[eptr] ] == timestep) { long int edge=(long int) VECTOR(*etimeidx)[eptr]; long int from=IGRAPH_FROM(graph, edge), to=IGRAPH_TO(graph, edge); long int xidx=VECTOR(papers)[from]; long int yidx=VECTOR(papers)[to]; double xk, oldakk; MATRIX(*notnull, xidx, yidx) += 1; MATRIX(*notnull, yidx, xidx) = MATRIX(*notnull, xidx, yidx); xk=VECTOR(*st)[timestep]/NTKK(xidx, yidx); oldakk=MATRIX(*kernel, xidx, yidx); MATRIX(*kernel, xidx, yidx) += (xk-oldakk)/MATRIX(*notnull, xidx, yidx); MATRIX(*kernel, yidx, xidx) = MATRIX(*kernel, xidx, yidx); if (sd) { MATRIX(*sd, xidx, yidx) += (xk-oldakk)*(xk-MATRIX(*kernel, xidx, yidx)); MATRIX(*sd, yidx, xidx) = MATRIX(*sd, xidx, yidx); } /* TODO: debug */ eptr++; } /* update ntkk, the new papers change the type of their authors */ eptr_new=eptr; for (i=aptr; i<aptr+VECTOR(*eventsizes)[timestep]; i++) { long int aut=(long int) VECTOR(*authors)[i]; long int pap=VECTOR(papers)[aut]; long int j, n; adjedges=igraph_lazy_inclist_get(inclist, (igraph_integer_t) aut); n=igraph_vector_size(adjedges); for (j=0; j<n; j++) { long int edge=(long int) VECTOR(*adjedges)[j]; if (VECTOR(added)[edge]) { long int otherv=IGRAPH_OTHER(graph, edge, aut); long int otherpap=VECTOR(papers)[otherv]; MATRIX(ntkk, pap, otherpap) -= 1; MATRIX(ntkk, otherpap, pap) = MATRIX(ntkk, pap, otherpap); if (NTKK(pap, otherpap)==1) { MATRIX(ch, pap, otherpap) = eptr_new; MATRIX(ch, otherpap, pap) = MATRIX(ch, pap, otherpap); } MATRIX(ntkk, pap+1, otherpap) += 1; MATRIX(ntkk, otherpap, pap+1) = MATRIX(ntkk, pap+1, otherpap); if (NTKK(pap+1, otherpap)==0) { MATRIX(*normfact, pap+1, otherpap) += eptr_new-MATRIX(ch, pap+1, otherpap); MATRIX(*normfact, otherpap, pap+1) = MATRIX(*normfact, pap+1, otherpap); } } } /* update ntk too */ for (j=0; j<maxpapers+1; j++) { long int before, after; before=(long int) NTKK(pap, j); VECTOR(ntk)[pap]-=1; after=(long int) NTKK(pap, j); VECTOR(ntk)[pap]+=1; if (before > 0 && after==0) { MATRIX(*normfact, pap, j) += eptr_new-MATRIX(ch, pap, j); MATRIX(*normfact, j, pap) = MATRIX(*normfact, pap, j); } } VECTOR(ntk)[pap]-=1; for (j=0; j<maxpapers+1; j++) { long int before, after; before=(long int) NTKK(pap+1, j); VECTOR(ntk)[pap+1] += 1; after=(long int) NTKK(pap+1, j); VECTOR(ntk)[pap+1] -= 1; if (before == 0 && after > 0) { MATRIX(ch, pap+1, j) = eptr_new; MATRIX(ch, j, pap+1) = MATRIX(ch, pap+1, j); } } VECTOR(ntk)[pap+1]+=1; VECTOR(papers)[aut] += 1; } aptr += VECTOR(*eventsizes)[timestep]; /* For every new edge, we lose one connection possibility, also add the edges*/ eptr=eptr_save; while (eptr < no_of_edges && VECTOR(*etime)[(long int) VECTOR(*etimeidx)[eptr] ] == timestep) { long int edge=(long int) VECTOR(*etimeidx)[eptr]; long int from=IGRAPH_FROM(graph, edge), to=IGRAPH_TO(graph, edge); long int xidx=VECTOR(papers)[from]; long int yidx=VECTOR(papers)[to]; MATRIX(ntkk, xidx, yidx) += 1; MATRIX(ntkk, yidx, xidx) = MATRIX(ntkk, xidx, yidx); if (NTKK(xidx, yidx)==0) { MATRIX(*normfact, xidx, yidx) += eptr_new-MATRIX(ch, xidx, yidx); MATRIX(*normfact, yidx, xidx) = MATRIX(*normfact, xidx, yidx); } VECTOR(added)[edge]=1; eptr++; } } for (i=0; i<maxpapers+1; i++) { igraph_real_t oldakk; long int j; for (j=0; j<=i; j++) { if (NTKK(i, j) != 0) { MATRIX(*normfact, i, j) += (eptr-MATRIX(ch, i, j)); MATRIX(*normfact, j, i) = MATRIX(*normfact, i, j); } if (MATRIX(*normfact, i, j)==0) { MATRIX(*kernel, i, j)=MATRIX(*kernel, j, i)=0; MATRIX(*normfact, i, j)=MATRIX(*normfact, j, i)=1; } oldakk=MATRIX(*kernel, i, j); MATRIX(*kernel, i, j) *= MATRIX(*notnull, i, j)/MATRIX(*normfact, i, j); MATRIX(*kernel, j, i) = MATRIX(*kernel, i, j); if (sd) { MATRIX(*sd, i, j) += oldakk * oldakk * MATRIX(*notnull, i, j) * (1-MATRIX(*notnull, i, j)/MATRIX(*normfact, i, j)); MATRIX(*sd, i, j) = sqrt(MATRIX(*sd, i, j)/(MATRIX(*normfact, i, j)-1)); MATRIX(*sd, j, i) = MATRIX(*sd, i, j); } } } if (!cites) { igraph_matrix_destroy(notnull); IGRAPH_FINALLY_CLEAN(1); } if (!norm) { igraph_matrix_destroy(normfact); IGRAPH_FINALLY_CLEAN(1); } igraph_matrix_destroy(&ch); igraph_matrix_destroy(&ntkk); igraph_vector_long_destroy(&ntk); igraph_vector_char_destroy(&added); igraph_vector_long_destroy(&papers); IGRAPH_FINALLY_CLEAN(5); return 0; }
int igraph_revolver_p_p(const igraph_t *graph, igraph_integer_t niter, const igraph_vector_t *vtime, const igraph_vector_t *etime, const igraph_vector_t *authors, const igraph_vector_t *eventsizes, 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; igraph_vector_t st; long int i; igraph_integer_t maxpapers=0; igraph_vector_t vtimeidx, etimeidx; igraph_lazy_inclist_t inclist; igraph_vector_long_t papers; 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); } no_of_events=(igraph_integer_t) igraph_vector_size(eventsizes); IGRAPH_VECTOR_INIT_FINALLY(&st, no_of_events); for (i=0; i<no_of_events; i++) { VECTOR(st)[i]=1; } IGRAPH_CHECK(igraph_vector_long_init(&papers, igraph_vcount(graph))); IGRAPH_FINALLY(igraph_vector_long_destroy, &papers); for (i=0; i<igraph_vector_size(authors); i++) { long int author=(long int) VECTOR(*authors)[i]; VECTOR(papers)[author] += 1; if (VECTOR(papers)[author] > maxpapers) { maxpapers=(igraph_integer_t) VECTOR(papers)[author]; } } igraph_vector_long_destroy(&papers); IGRAPH_FINALLY_CLEAN(1); 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 p-p", 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_p_p(graph, &inclist, kernel, 0 /*sd*/, 0 /*norm*/, 0/*cites*/, 0/*debug*/, 0 /*debugres*/, &st, vtime, &vtimeidx, etime, &etimeidx, no_of_events, authors, eventsizes, maxpapers)); /* normalize */ igraph_matrix_scale(kernel, 1/igraph_matrix_sum(kernel)); /* update st */ IGRAPH_CHECK(igraph_revolver_st_p_p(graph, &inclist, &st, kernel, vtime, &vtimeidx, etime, &etimeidx, no_of_events, authors, eventsizes, maxpapers)); } else { /* measure */ IGRAPH_CHECK(igraph_revolver_mes_p_p(graph, &inclist, kernel, sd, norm, cites, debug, debugres, &st, vtime, &vtimeidx, etime, &etimeidx, no_of_events, authors, eventsizes, maxpapers)); /* normalize */ igraph_matrix_scale(kernel, 1/igraph_matrix_sum(kernel)); /* update st */ IGRAPH_CHECK(igraph_revolver_st_p_p(graph, &inclist, &st, kernel, vtime, &vtimeidx, etime, &etimeidx, no_of_events, authors, eventsizes, maxpapers)); /* expected number of citations */ if (expected) { IGRAPH_CHECK(igraph_revolver_exp_p_p(graph, &inclist, expected, kernel, &st, vtime, &vtimeidx, etime, &etimeidx, no_of_events, authors, eventsizes, maxpapers)); } /* error calculation */ if (logprob || lognull) { IGRAPH_CHECK(igraph_revolver_error_p_p(graph, &inclist, kernel, &st, vtime, &vtimeidx, etime, &etimeidx, no_of_events, authors, eventsizes, maxpapers, logprob, lognull)); } } IGRAPH_PROGRESS("Revolver p-p", 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; }
int igraph_revolver_error_d_d(const igraph_t *graph, igraph_lazy_inclist_t *inclist, const igraph_matrix_t *kernel, const igraph_vector_t *st, const igraph_vector_t *vtime, const igraph_vector_t *vtimeidx, const igraph_vector_t *etime, const igraph_vector_t *etimeidx, igraph_integer_t pno_of_events, igraph_integer_t pmaxdegree, igraph_real_t *logprob, igraph_real_t *lognull) { long int no_of_events=pno_of_events; long int no_of_nodes=igraph_vcount(graph); long int no_of_edges=igraph_ecount(graph); igraph_vector_long_t degree; long int timestep, nptr=0, eptr=0, eptr_save; long int edges=0, vertices=0; igraph_real_t rlogprob, rlognull, *mylogprob=logprob, *mylognull=lognull; IGRAPH_CHECK(igraph_vector_long_init(°ree, no_of_nodes)); IGRAPH_FINALLY(igraph_vector_long_destroy, °ree); if (!logprob) { mylogprob=&rlogprob; } if (!lognull) { mylognull=&rlognull; } *mylogprob=0; *mylognull=0; for (timestep=0; timestep<no_of_events; timestep++) { IGRAPH_ALLOW_INTERRUPTION(); while (nptr < no_of_nodes && VECTOR(*vtime)[ (long int) VECTOR(*vtimeidx)[nptr] ] == timestep) { vertices++; nptr++; } eptr_save=eptr; while (eptr < no_of_edges && VECTOR(*etime)[ (long int) VECTOR(*etimeidx)[eptr] ] == timestep) { long int edge=(long int) VECTOR(*etimeidx)[eptr]; long int from=IGRAPH_FROM(graph, edge); long int to=IGRAPH_TO(graph, edge); long int xidx=VECTOR(degree)[from]; long int yidx=VECTOR(degree)[to]; igraph_real_t prob=MATRIX(*kernel, xidx, yidx)/VECTOR(*st)[timestep]; igraph_real_t nullprob=1.0/(vertices*(vertices-1)/2-eptr_save); *mylogprob += log(prob); *mylognull += log(nullprob); edges++; eptr++; } eptr=eptr_save; while (eptr < no_of_edges && VECTOR(*etime)[ (long int) VECTOR(*etimeidx)[eptr] ] == timestep) { long int edge=(long int) VECTOR(*etimeidx)[eptr]; long int from=IGRAPH_FROM(graph, edge); long int to=IGRAPH_TO(graph, edge); VECTOR(degree)[from] += 1; VECTOR(degree)[to] += 1; eptr++; } } igraph_vector_long_destroy(°ree); IGRAPH_FINALLY_CLEAN(1); return 0; }
int igraph_revolver_st_d_d(const igraph_t *graph, igraph_lazy_inclist_t *inclist, igraph_vector_t *st, const igraph_matrix_t *kernel, const igraph_vector_t *vtime, const igraph_vector_t *vtimeidx, const igraph_vector_t *etime, const igraph_vector_t *etimeidx, igraph_integer_t pno_of_events) { long int no_of_events=pno_of_events; long int maxdegree=igraph_matrix_nrow(kernel)-1; long int no_of_nodes=igraph_vcount(graph); long int no_of_edges=igraph_ecount(graph); long int timestep=0; igraph_vector_long_t degree; igraph_vector_long_t ntk; igraph_vector_char_t added; igraph_vector_t *adjedges; long int i; long int nptr=0, eptr=0; IGRAPH_CHECK(igraph_vector_long_init(&ntk, maxdegree+1)); IGRAPH_FINALLY(igraph_vector_long_destroy, &ntk); IGRAPH_CHECK(igraph_vector_long_init(°ree, no_of_nodes)); IGRAPH_FINALLY(igraph_vector_long_destroy, °ree); IGRAPH_CHECK(igraph_vector_char_init(&added, no_of_edges)); IGRAPH_FINALLY(igraph_vector_char_destroy, &added); IGRAPH_CHECK(igraph_vector_resize(st, no_of_events)); VECTOR(*st)[0]=0; for (timestep=0; timestep<no_of_events-1; timestep++) { IGRAPH_ALLOW_INTERRUPTION(); /* add the new nodes */ while (nptr < no_of_nodes && VECTOR(*vtime)[ (long int) VECTOR(*vtimeidx)[nptr] ] == timestep) { for (i=0; i<maxdegree+1; i++) { VECTOR(*st)[timestep] += VECTOR(ntk)[i]*MATRIX(*kernel, i, 0); } VECTOR(ntk)[0]++; nptr++; } /* add the new edges as well, but this is for the next timestep already */ VECTOR(*st)[timestep+1] = VECTOR(*st)[timestep]; while (eptr < no_of_edges && VECTOR(*etime)[ (long int) VECTOR(*etimeidx)[eptr] ] == timestep) { long int edge=(long int) VECTOR(*etimeidx)[eptr]; long int from=IGRAPH_FROM(graph, edge); long int to=IGRAPH_TO(graph, edge); long int xidx=VECTOR(degree)[from]; long int yidx=VECTOR(degree)[to]; igraph_real_t inc=0; long int n; inc -= MATRIX(*kernel, xidx, yidx); for (i=0; i<maxdegree+1; i++) { inc += VECTOR(ntk)[i] * (MATRIX(*kernel, i, xidx+1) - MATRIX(*kernel, i, xidx) + MATRIX(*kernel, i, yidx+1) - MATRIX(*kernel, i, yidx)); } inc -= MATRIX(*kernel, xidx+1, xidx+1); inc -= MATRIX(*kernel, yidx+1, yidx+1); inc += MATRIX(*kernel, xidx, xidx); inc += MATRIX(*kernel, yidx, yidx); VECTOR(ntk)[xidx]--; VECTOR(ntk)[yidx]--; VECTOR(ntk)[xidx+1]++; VECTOR(ntk)[yidx+1]++; adjedges=igraph_lazy_inclist_get(inclist, (igraph_integer_t) from); n=igraph_vector_size(adjedges); for (i=0; i<n; i++) { long int edge=(long int) VECTOR(*adjedges)[i]; if (VECTOR(added)[edge]) { long int otherv=IGRAPH_OTHER(graph, edge, from); long int deg=VECTOR(degree)[otherv]; inc += MATRIX(*kernel, xidx, deg); inc -= MATRIX(*kernel, xidx+1, deg); } } adjedges=igraph_lazy_inclist_get(inclist, (igraph_integer_t) to); n=igraph_vector_size(adjedges); for (i=0; i<n; i++) { long int edge=(long int) VECTOR(*adjedges)[i]; if (VECTOR(added)[edge]) { long int otherv=IGRAPH_OTHER(graph, edge, to); long int deg=VECTOR(degree)[otherv]; inc += MATRIX(*kernel, yidx, deg); inc -= MATRIX(*kernel, yidx+1, deg); } } VECTOR(degree)[from] += 1; VECTOR(degree)[to] += 1; VECTOR(added)[edge]=1; VECTOR(*st)[timestep+1] += inc; eptr++; } } igraph_vector_char_destroy(&added); igraph_vector_long_destroy(°ree); igraph_vector_long_destroy(&ntk); IGRAPH_FINALLY_CLEAN(3); return 0; }
QList<int> MWBM::run(QList<int> input_weights, int numberOfLeft, int numberOfRight, bool &isMatched) { igraph_t graph; igraph_vector_bool_t types; igraph_vector_long_t matching; igraph_vector_t weights; igraph_integer_t matching_size; igraph_real_t matching_weight; igraph_bool_t is_matching; igraph_vector_t v; int i; QList<int> out; igraph_real_t weight_array[input_weights.size()]; for(int j=0;j<input_weights.size();j++) { weight_array[j] = input_weights.at(j); }; QList<int> edges_list; for(int j=0;j<numberOfLeft;j++) { for(int k=numberOfLeft;k<numberOfRight+numberOfLeft;k++) { edges_list.append(j); edges_list.append(k); } } igraph_real_t edges[edges_list.size()]; for(int j=0;j<edges_list.size();j++) { edges[j] = edges_list.at(j); } igraph_vector_view(&v, edges, sizeof(edges)/sizeof(double)); igraph_create(&graph, &v, 0, IGRAPH_DIRECTED); igraph_vector_bool_init(&types, numberOfLeft+numberOfRight); for (i = 0; i < numberOfLeft+numberOfRight; i++) VECTOR(types)[i] = (i >= numberOfLeft); igraph_vector_long_init(&matching, 0); igraph_vector_init_copy(&weights, weight_array, sizeof(weight_array) / sizeof(weight_array[0])); igraph_maximum_bipartite_matching(&graph, &types, &matching_size, &matching_weight, &matching, &weights,DBL_EPSILON); igraph_is_maximal_matching(&graph, &types, &matching, &is_matching); if (!is_matching) { isMatched = false; } else { isMatched=true; } for(int j=0;j<numberOfLeft*2;j++) out.append(VECTOR(matching)[j]); igraph_vector_destroy(&weights); igraph_vector_long_destroy(&matching); igraph_vector_bool_destroy(&types); igraph_destroy(&graph); return out; }
int igraph_biconnected_components(const igraph_t *graph, igraph_integer_t *no, igraph_vector_ptr_t *tree_edges, igraph_vector_ptr_t *component_edges, igraph_vector_ptr_t *components, igraph_vector_t *articulation_points) { long int no_of_nodes=igraph_vcount(graph); igraph_vector_long_t nextptr; igraph_vector_long_t num, low; igraph_vector_bool_t found; igraph_vector_int_t *adjedges; igraph_stack_t path; igraph_vector_t edgestack; igraph_inclist_t inclist; long int i, counter, rootdfs=0; igraph_vector_long_t vertex_added; long int comps=0; igraph_vector_ptr_t *mycomponents=components, vcomponents; IGRAPH_CHECK(igraph_vector_long_init(&nextptr, no_of_nodes)); IGRAPH_FINALLY(igraph_vector_long_destroy, &nextptr); IGRAPH_CHECK(igraph_vector_long_init(&num, no_of_nodes)); IGRAPH_FINALLY(igraph_vector_long_destroy, &num); IGRAPH_CHECK(igraph_vector_long_init(&low, no_of_nodes)); IGRAPH_FINALLY(igraph_vector_long_destroy, &low); IGRAPH_CHECK(igraph_vector_bool_init(&found, no_of_nodes)); IGRAPH_FINALLY(igraph_vector_bool_destroy, &found); IGRAPH_CHECK(igraph_stack_init(&path, 100)); IGRAPH_FINALLY(igraph_stack_destroy, &path); IGRAPH_VECTOR_INIT_FINALLY(&edgestack, 0); IGRAPH_CHECK(igraph_vector_reserve(&edgestack, 100)); IGRAPH_CHECK(igraph_inclist_init(graph, &inclist, IGRAPH_ALL)); IGRAPH_FINALLY(igraph_inclist_destroy, &inclist); IGRAPH_CHECK(igraph_vector_long_init(&vertex_added, no_of_nodes)); IGRAPH_FINALLY(igraph_vector_long_destroy, &vertex_added); if (no) { *no=0; } if (tree_edges) { igraph_vector_ptr_clear(tree_edges); } if (components) { igraph_vector_ptr_clear(components); } if (component_edges) { igraph_vector_ptr_clear(component_edges); } if (articulation_points) { igraph_vector_clear(articulation_points); } if (component_edges && !components) { mycomponents=&vcomponents; IGRAPH_CHECK(igraph_vector_ptr_init(mycomponents, 0)); IGRAPH_FINALLY(igraph_i_free_vectorlist, mycomponents); } for (i=0; i<no_of_nodes; i++) { if (VECTOR(low)[i] != 0) { continue; } /* already visited */ IGRAPH_ALLOW_INTERRUPTION(); IGRAPH_CHECK(igraph_stack_push(&path, i)); counter=1; rootdfs=0; VECTOR(low)[i]=VECTOR(num)[i]=counter++; while (!igraph_stack_empty(&path)) { long int n; long int act=(long int) igraph_stack_top(&path); long int actnext=VECTOR(nextptr)[act]; adjedges=igraph_inclist_get(&inclist, act); n=igraph_vector_int_size(adjedges); if (actnext < n) { /* Step down (maybe) */ long int edge=(long int) VECTOR(*adjedges)[actnext]; long int nei=IGRAPH_OTHER(graph, edge, act); if (VECTOR(low)[nei] == 0) { if (act==i) { rootdfs++; } IGRAPH_CHECK(igraph_vector_push_back(&edgestack, edge)); IGRAPH_CHECK(igraph_stack_push(&path, nei)); VECTOR(low)[nei] = VECTOR(num)[nei]=counter++; } else { /* Update low value if needed */ if (VECTOR(num)[nei] < VECTOR(low)[act]) { VECTOR(low)[act]=VECTOR(num)[nei]; } } VECTOR(nextptr)[act] += 1; } else { /* Step up */ igraph_stack_pop(&path); if (!igraph_stack_empty(&path)) { long int prev=(long int) igraph_stack_top(&path); /* Update LOW value if needed */ if (VECTOR(low)[act] < VECTOR(low)[prev]) { VECTOR(low)[prev] = VECTOR(low)[act]; } /* Check for articulation point */ if (VECTOR(low)[act] >= VECTOR(num)[prev]) { if (articulation_points && !VECTOR(found)[prev] && prev != i /* the root */) { IGRAPH_CHECK(igraph_vector_push_back(articulation_points, prev)); VECTOR(found)[prev] = 1; } if (no) { *no += 1; } /*------------------------------------*/ /* Record the biconnected component just found */ if (tree_edges || mycomponents) { igraph_vector_t *v = 0, *v2 = 0; comps++; if (tree_edges) { v=igraph_Calloc(1, igraph_vector_t); if (!v) { IGRAPH_ERROR("Out of memory", IGRAPH_ENOMEM); } IGRAPH_CHECK(igraph_vector_init(v, 0)); IGRAPH_FINALLY(igraph_vector_destroy, v); } if (mycomponents) { v2=igraph_Calloc(1, igraph_vector_t); if (!v2) { IGRAPH_ERROR("Out of memory", IGRAPH_ENOMEM); } IGRAPH_CHECK(igraph_vector_init(v2, 0)); IGRAPH_FINALLY(igraph_vector_destroy, v2); } while (!igraph_vector_empty(&edgestack)) { long int e=(long int) igraph_vector_pop_back(&edgestack); long int from=IGRAPH_FROM(graph,e); long int to=IGRAPH_TO(graph,e); if (tree_edges) { IGRAPH_CHECK(igraph_vector_push_back(v, e)); } if (mycomponents) { if (VECTOR(vertex_added)[from] != comps) { VECTOR(vertex_added)[from] = comps; IGRAPH_CHECK(igraph_vector_push_back(v2, from)); } if (VECTOR(vertex_added)[to] != comps) { VECTOR(vertex_added)[to] = comps; IGRAPH_CHECK(igraph_vector_push_back(v2, to)); } } if (from==prev || to==prev) { break; } } if (mycomponents) { IGRAPH_CHECK(igraph_vector_ptr_push_back(mycomponents, v2)); IGRAPH_FINALLY_CLEAN(1); } if (tree_edges) { IGRAPH_CHECK(igraph_vector_ptr_push_back(tree_edges, v)); IGRAPH_FINALLY_CLEAN(1); } if (component_edges) { igraph_vector_t *nodes=VECTOR(*mycomponents)[comps-1]; igraph_vector_t *vv=igraph_Calloc(1, igraph_vector_t); long int ii, no_vert=igraph_vector_size(nodes); if (!vv) { IGRAPH_ERROR("Out of memory", IGRAPH_ENOMEM); } IGRAPH_CHECK(igraph_vector_init(vv, 0)); IGRAPH_FINALLY(igraph_vector_destroy, vv); for (ii=0; ii<no_vert; ii++) { long int vert=(long int) VECTOR(*nodes)[ii]; igraph_vector_int_t *edges=igraph_inclist_get(&inclist, vert); long int j, nn=igraph_vector_int_size(edges); for (j=0; j<nn; j++) { long int e=(long int) VECTOR(*edges)[j]; long int nei=IGRAPH_OTHER(graph, e, vert); if (VECTOR(vertex_added)[nei] == comps && nei<vert) { IGRAPH_CHECK(igraph_vector_push_back(vv, e)); } } } IGRAPH_CHECK(igraph_vector_ptr_push_back(component_edges, vv)); IGRAPH_FINALLY_CLEAN(1); } } /* record component if requested */ /*------------------------------------*/ } } /* !igraph_stack_empty(&path) */ } } /* !igraph_stack_empty(&path) */ if (articulation_points && rootdfs >= 2) { IGRAPH_CHECK(igraph_vector_push_back(articulation_points, i)); } } /* i < no_of_nodes */ if (mycomponents != components) { igraph_i_free_vectorlist(mycomponents); IGRAPH_FINALLY_CLEAN(1); } igraph_vector_long_destroy(&vertex_added); igraph_inclist_destroy(&inclist); igraph_vector_destroy(&edgestack); igraph_stack_destroy(&path); igraph_vector_bool_destroy(&found); igraph_vector_long_destroy(&low); igraph_vector_long_destroy(&num); igraph_vector_long_destroy(&nextptr); IGRAPH_FINALLY_CLEAN(8); return 0; }
int igraph_intersection_many(igraph_t *res, const igraph_vector_ptr_t *graphs, igraph_vector_ptr_t *edgemaps) { long int no_of_graphs=igraph_vector_ptr_size(graphs); long int no_of_nodes=0; igraph_bool_t directed=1; igraph_vector_t edges; igraph_vector_ptr_t edge_vects, order_vects; long int i, j, tailfrom = no_of_graphs > 0 ? 0 : -1, tailto=-1; igraph_vector_long_t no_edges; igraph_bool_t allne= no_of_graphs == 0 ? 0 : 1, allsame=0; long int idx=0; /* Check directedness */ if (no_of_graphs != 0) { directed=igraph_is_directed(VECTOR(*graphs)[0]); } for (i=1; i<no_of_graphs; i++) { if (directed != igraph_is_directed(VECTOR(*graphs)[i])) { IGRAPH_ERROR("Cannot intersect directed and undirected graphs", IGRAPH_EINVAL); } } if (edgemaps) { IGRAPH_CHECK(igraph_vector_ptr_resize(edgemaps, no_of_graphs)); igraph_vector_ptr_null(edgemaps); IGRAPH_FINALLY(igraph_i_union_many_free3, edgemaps); } IGRAPH_VECTOR_INIT_FINALLY(&edges, 0); IGRAPH_CHECK(igraph_vector_long_init(&no_edges, no_of_graphs)); IGRAPH_FINALLY(igraph_vector_long_destroy, &no_edges); /* Calculate number of nodes, query number of edges */ for (i=0; i<no_of_graphs; i++) { long int n=igraph_vcount(VECTOR(*graphs)[i]); if (n > no_of_nodes) { no_of_nodes=n; } VECTOR(no_edges)[i] = igraph_ecount(VECTOR(*graphs)[i]); allne = allne && VECTOR(no_edges)[i] > 0; } if (edgemaps) { for (i=0; i<no_of_graphs; i++) { VECTOR(*edgemaps)[i]=igraph_Calloc(1, igraph_vector_t); if (!VECTOR(*edgemaps)[i]) { IGRAPH_ERROR("Cannot intersect graphs", IGRAPH_ENOMEM); } IGRAPH_CHECK(igraph_vector_init(VECTOR(*edgemaps)[i], VECTOR(no_edges)[i])); igraph_vector_fill(VECTOR(*edgemaps)[i], -1); } } /* Allocate memory for the edge lists and their index vectors */ if (no_of_graphs != 0) { IGRAPH_CHECK(igraph_vector_ptr_init(&edge_vects, no_of_graphs)); IGRAPH_FINALLY(igraph_i_union_many_free, &edge_vects); IGRAPH_CHECK(igraph_vector_ptr_init(&order_vects, no_of_graphs)); IGRAPH_FINALLY(igraph_i_union_many_free2, &order_vects); } for (i=0; i<no_of_graphs; i++) { VECTOR(edge_vects)[i]=igraph_Calloc(1, igraph_vector_t); VECTOR(order_vects)[i]=igraph_Calloc(1, igraph_vector_long_t); if (! VECTOR(edge_vects)[i] || ! VECTOR(order_vects)[i]) { IGRAPH_ERROR("Cannot intersect graphs", IGRAPH_ENOMEM); } IGRAPH_CHECK(igraph_vector_init(VECTOR(edge_vects)[i], 2 * VECTOR(no_edges)[i])); IGRAPH_CHECK(igraph_vector_long_init(VECTOR(order_vects)[i], VECTOR(no_edges)[i])); } /* Query and sort the edge lists */ for (i=0; i<no_of_graphs; i++) { long int k, j, n=VECTOR(no_edges)[i]; igraph_vector_t *edges=VECTOR(edge_vects)[i]; igraph_vector_long_t *order=VECTOR(order_vects)[i]; IGRAPH_CHECK(igraph_get_edgelist(VECTOR(*graphs)[i], edges, /*bycol=*/0)); if (!directed) { for (k=0, j=0; k<n; k++, j+=2) { if (VECTOR(*edges)[j] > VECTOR(*edges)[j+1]) { long int tmp=VECTOR(*edges)[j]; VECTOR(*edges)[j]=VECTOR(*edges)[j+1]; VECTOR(*edges)[j+1]=tmp; } } } for (k=0; k<n; k++) { VECTOR(*order)[k]=k; } igraph_qsort_r(VECTOR(*order), n, sizeof(VECTOR(*order)[0]), edges, igraph_i_order_edgelist_cmp); } /* Do the merge. We work from the end of the edge lists, because then we don't have to keep track of where we are right now in the edge and order lists. We find the "largest" edge, and if it is present in all graphs, then we copy it to the result. We remove all instances of this edge. */ while (allne) { /* Look for the smallest tail element */ for (j=0, tailfrom=LONG_MAX, tailto=LONG_MAX; j<no_of_graphs; j++) { long int edge=igraph_vector_long_tail(VECTOR(order_vects)[j]); igraph_vector_t *ev=VECTOR(edge_vects)[j]; long int from=VECTOR(*ev)[2*edge]; long int to=VECTOR(*ev)[2*edge+1]; if (from < tailfrom || (from == tailfrom && to < tailto)) { tailfrom = from; tailto = to; } } /* OK, now remove all elements from the tail(s) that are bigger than the smallest tail element. */ for (j=0, allsame=1; j<no_of_graphs; j++) { long int from=-1, to=-1; while (1) { long int edge=igraph_vector_long_tail(VECTOR(order_vects)[j]); igraph_vector_t *ev=VECTOR(edge_vects)[j]; from=VECTOR(*ev)[2*edge]; to=VECTOR(*ev)[2*edge+1]; if (from > tailfrom || (from==tailfrom && to > tailto)) { igraph_vector_long_pop_back(VECTOR(order_vects)[j]); if (igraph_vector_long_empty(VECTOR(order_vects)[j])) { allne=0; break; } } else { break; } } if (from != tailfrom || to != tailto) { allsame=0; } } /* Add the edge, if the smallest tail element was present in all graphs. */ if (allsame) { IGRAPH_CHECK(igraph_vector_push_back(&edges, tailfrom)); IGRAPH_CHECK(igraph_vector_push_back(&edges, tailto)); } /* Drop edges matching the smalles tail elements from the order vectors, build edge maps */ if (allne) { for (j=0; j<no_of_graphs; j++) { long int edge=igraph_vector_long_tail(VECTOR(order_vects)[j]); igraph_vector_t *ev=VECTOR(edge_vects)[j]; long int from=VECTOR(*ev)[2*edge]; long int to=VECTOR(*ev)[2*edge+1]; if (from == tailfrom && to == tailto) { igraph_vector_long_pop_back(VECTOR(order_vects)[j]); if (igraph_vector_long_empty(VECTOR(order_vects)[j])) { allne=0; } if (edgemaps && allsame) { igraph_vector_t *map=VECTOR(*edgemaps)[j]; VECTOR(*map)[edge]=idx; } } } if (allsame) { idx++; } } } /* while allne */ if (no_of_graphs > 0) { igraph_i_union_many_free2(&order_vects); igraph_i_union_many_free(&edge_vects); IGRAPH_FINALLY_CLEAN(2); } igraph_vector_long_destroy(&no_edges); IGRAPH_FINALLY_CLEAN(1); IGRAPH_CHECK(igraph_create(res, &edges, (igraph_integer_t) no_of_nodes, directed)); igraph_vector_destroy(&edges); IGRAPH_FINALLY_CLEAN(1); if (edgemaps) { IGRAPH_FINALLY_CLEAN(1); } return 0; }
int igraph_i_merge(igraph_t *res, int mode, const igraph_t *left, const igraph_t *right, igraph_vector_t *edge_map1, igraph_vector_t *edge_map2) { long int no_of_nodes_left=igraph_vcount(left); long int no_of_nodes_right=igraph_vcount(right); long int no_of_nodes; long int no_edges_left=igraph_ecount(left); long int no_edges_right=igraph_ecount(right); igraph_bool_t directed=igraph_is_directed(left); igraph_vector_t edges; igraph_vector_t edges1, edges2; igraph_vector_long_t order1, order2; long int i, j, eptr=0; long int idx1, idx2, edge1=-1, edge2=-1, from1=-1, from2=-1, to1=-1, to2=-1; igraph_bool_t l; if (directed != igraph_is_directed(right)) { IGRAPH_ERROR("Cannot make union or intersection of directed " "and undirected graph", IGRAPH_EINVAL); } IGRAPH_VECTOR_INIT_FINALLY(&edges, 0); IGRAPH_VECTOR_INIT_FINALLY(&edges1, no_edges_left*2); IGRAPH_VECTOR_INIT_FINALLY(&edges2, no_edges_right*2); IGRAPH_CHECK(igraph_vector_long_init(&order1, no_edges_left)); IGRAPH_FINALLY(igraph_vector_long_destroy, &order1); IGRAPH_CHECK(igraph_vector_long_init(&order2, no_edges_right)); IGRAPH_FINALLY(igraph_vector_long_destroy, &order2); if (edge_map1) { switch (mode) { case IGRAPH_MODE_UNION: IGRAPH_CHECK(igraph_vector_resize(edge_map1, no_edges_left)); break; case IGRAPH_MODE_INTERSECTION: igraph_vector_clear(edge_map1); break; } } if (edge_map2) { switch (mode) { case IGRAPH_MODE_UNION: IGRAPH_CHECK(igraph_vector_resize(edge_map2, no_edges_right)); break; case IGRAPH_MODE_INTERSECTION: igraph_vector_clear(edge_map2); break; } } no_of_nodes=no_of_nodes_left > no_of_nodes_right ? no_of_nodes_left : no_of_nodes_right; /* We merge the two edge lists. We need to sort them first. For undirected graphs, we also need to make sure that for every edge, that larger (non-smaller) vertex id is in the second column. */ IGRAPH_CHECK(igraph_get_edgelist(left, &edges1, /*bycol=*/ 0)); IGRAPH_CHECK(igraph_get_edgelist(right, &edges2, /*bycol=*/ 0)); if (!directed) { for (i=0, j=0; i<no_edges_left; i++, j+=2) { if (VECTOR(edges1)[j] > VECTOR(edges1)[j+1]) { long int tmp=VECTOR(edges1)[j]; VECTOR(edges1)[j]=VECTOR(edges1)[j+1]; VECTOR(edges1)[j+1]=tmp; } } for (i=0, j=0; i<no_edges_right; i++, j+=2) { if (VECTOR(edges2)[j] > VECTOR(edges2)[j+1]) { long int tmp=VECTOR(edges2)[j]; VECTOR(edges2)[j]=VECTOR(edges2)[j+1]; VECTOR(edges2)[j+1]=tmp; } } } for (i=0; i<no_edges_left; i++) { VECTOR(order1)[i]=i; } for (i=0; i<no_edges_right; i++) { VECTOR(order2)[i]=i; } igraph_qsort_r(VECTOR(order1), no_edges_left, sizeof(VECTOR(order1)[0]), &edges1, igraph_i_order_edgelist_cmp); igraph_qsort_r(VECTOR(order2), no_edges_right, sizeof(VECTOR(order2)[0]), &edges2, igraph_i_order_edgelist_cmp); #define INC1() if ( (++idx1) < no_edges_left) { \ edge1 = VECTOR(order1)[idx1]; \ from1 = VECTOR(edges1)[2*edge1]; \ to1 = VECTOR(edges1)[2*edge1+1]; \ } #define INC2() if ( (++idx2) < no_edges_right) { \ edge2 = VECTOR(order2)[idx2]; \ from2 = VECTOR(edges2)[2*edge2]; \ to2 = VECTOR(edges2)[2*edge2+1]; \ } idx1 = idx2 = -1; INC1(); INC2(); #define CONT() switch (mode) { \ case IGRAPH_MODE_UNION: \ l = idx1 < no_edges_left || idx2 < no_edges_right; \ break; \ case IGRAPH_MODE_INTERSECTION: \ l = idx1 < no_edges_left && idx2 < no_edges_right; \ break; \ } CONT(); while (l) { if (idx2 >= no_edges_right || (idx1 < no_edges_left && from1 < from2) || (idx1 < no_edges_left && from1 == from2 && to1 < to2)) { /* Edge from first graph */ if (mode==IGRAPH_MODE_UNION) { IGRAPH_CHECK(igraph_vector_push_back(&edges, from1)); IGRAPH_CHECK(igraph_vector_push_back(&edges, to1)); if (edge_map1) { VECTOR(*edge_map1)[edge1]=eptr; } eptr++; } INC1(); } else if (idx1 >= no_edges_left || (idx2 < no_edges_right && from2 < from1) || (idx2 < no_edges_right && from1 == from2 && to2 < to1)) { /* Edge from second graph */ if (mode==IGRAPH_MODE_UNION) { IGRAPH_CHECK(igraph_vector_push_back(&edges, from2)); IGRAPH_CHECK(igraph_vector_push_back(&edges, to2)); if (edge_map2) { VECTOR(*edge_map2)[edge2]=eptr; } eptr++; } INC2(); } else { /* Edge from both */ IGRAPH_CHECK(igraph_vector_push_back(&edges, from1)); IGRAPH_CHECK(igraph_vector_push_back(&edges, to1)); if (mode==IGRAPH_MODE_UNION) { if (edge_map1) { VECTOR(*edge_map1)[edge1]=eptr; } if (edge_map2) { VECTOR(*edge_map2)[edge2]=eptr; } } else if (mode==IGRAPH_MODE_INTERSECTION) { if (edge_map1) { IGRAPH_CHECK(igraph_vector_push_back(edge_map1, edge1)); } if (edge_map2) { IGRAPH_CHECK(igraph_vector_push_back(edge_map2, edge2)); } } eptr++; INC1(); INC2(); } CONT(); } #undef INC1 #undef INC2 igraph_vector_long_destroy(&order2); igraph_vector_long_destroy(&order1); igraph_vector_destroy(&edges2); igraph_vector_destroy(&edges1); IGRAPH_FINALLY_CLEAN(4); IGRAPH_CHECK(igraph_create(res, &edges, no_of_nodes, directed)); igraph_vector_destroy(&edges); IGRAPH_FINALLY_CLEAN(1); return 0; }
int igraph_bipartite_projection_size(const igraph_t *graph, const igraph_vector_bool_t *types, igraph_integer_t *vcount1, igraph_integer_t *ecount1, igraph_integer_t *vcount2, igraph_integer_t *ecount2) { long int no_of_nodes=igraph_vcount(graph); long int vc1=0, ec1=0, vc2=0, ec2=0; igraph_adjlist_t adjlist; igraph_vector_long_t added; long int i; IGRAPH_CHECK(igraph_vector_long_init(&added, no_of_nodes)); IGRAPH_FINALLY(igraph_vector_long_destroy, &added); IGRAPH_CHECK(igraph_adjlist_init(graph, &adjlist, IGRAPH_ALL)); IGRAPH_FINALLY(igraph_adjlist_destroy, &adjlist); for (i=0; i<no_of_nodes; i++) { igraph_vector_int_t *neis1; long int neilen1, j; long int *ecptr; if (VECTOR(*types)[i]) { vc2++; ecptr=&ec2; } else { vc1++; ecptr=&ec1; } neis1=igraph_adjlist_get(&adjlist, i); neilen1=igraph_vector_int_size(neis1); for (j=0; j<neilen1; j++) { long int k, neilen2, nei=(long int) VECTOR(*neis1)[j]; igraph_vector_int_t *neis2=igraph_adjlist_get(&adjlist, nei); if (IGRAPH_UNLIKELY(VECTOR(*types)[i] == VECTOR(*types)[nei])) { IGRAPH_ERROR("Non-bipartite edge found in bipartite projection", IGRAPH_EINVAL); } neilen2=igraph_vector_int_size(neis2); for (k=0; k<neilen2; k++) { long int nei2=(long int) VECTOR(*neis2)[k]; if (nei2 <= i) { continue; } if (VECTOR(added)[nei2] == i+1) { continue; } VECTOR(added)[nei2] = i+1; (*ecptr)++; } } } *vcount1=(igraph_integer_t) vc1; *ecount1=(igraph_integer_t) ec1; *vcount2=(igraph_integer_t) vc2; *ecount2=(igraph_integer_t) ec2; igraph_adjlist_destroy(&adjlist); igraph_vector_long_destroy(&added); IGRAPH_FINALLY_CLEAN(2); return 0; }
int igraph_i_bipartite_projection(const igraph_t *graph, const igraph_vector_bool_t *types, igraph_t *proj, int which, igraph_vector_t *multiplicity) { long int no_of_nodes=igraph_vcount(graph); long int i, j, k; igraph_integer_t remaining_nodes=0; igraph_vector_t vertex_perm, vertex_index; igraph_vector_t edges; igraph_adjlist_t adjlist; igraph_vector_int_t *neis1, *neis2; long int neilen1, neilen2; igraph_vector_long_t added; igraph_vector_t mult; if (which < 0) { return 0; } IGRAPH_VECTOR_INIT_FINALLY(&vertex_perm, 0); IGRAPH_CHECK(igraph_vector_reserve(&vertex_perm, no_of_nodes)); IGRAPH_VECTOR_INIT_FINALLY(&edges, 0); IGRAPH_VECTOR_INIT_FINALLY(&vertex_index, no_of_nodes); IGRAPH_CHECK(igraph_vector_long_init(&added, no_of_nodes)); IGRAPH_FINALLY(igraph_vector_long_destroy, &added); IGRAPH_CHECK(igraph_adjlist_init(graph, &adjlist, IGRAPH_ALL)); IGRAPH_FINALLY(igraph_adjlist_destroy, &adjlist); if (multiplicity) { IGRAPH_VECTOR_INIT_FINALLY(&mult, no_of_nodes); igraph_vector_clear(multiplicity); } for (i=0; i<no_of_nodes; i++) { if (VECTOR(*types)[i] == which) { VECTOR(vertex_index)[i] = ++remaining_nodes; igraph_vector_push_back(&vertex_perm, i); } } for (i=0; i<no_of_nodes; i++) { if (VECTOR(*types)[i] == which) { long int new_i=(long int) VECTOR(vertex_index)[i]-1; long int iedges=0; neis1=igraph_adjlist_get(&adjlist, i); neilen1=igraph_vector_int_size(neis1); for (j=0; j<neilen1; j++) { long int nei=(long int) VECTOR(*neis1)[j]; if (IGRAPH_UNLIKELY(VECTOR(*types)[i] == VECTOR(*types)[nei])) { IGRAPH_ERROR("Non-bipartite edge found in bipartite projection", IGRAPH_EINVAL); } neis2=igraph_adjlist_get(&adjlist, nei); neilen2=igraph_vector_int_size(neis2); for (k=0; k<neilen2; k++) { long int nei2=(long int) VECTOR(*neis2)[k], new_nei2; if (nei2 <= i) { continue; } if (VECTOR(added)[nei2] == i+1) { if (multiplicity) { VECTOR(mult)[nei2]+=1; } continue; } VECTOR(added)[nei2] = i+1; if (multiplicity) { VECTOR(mult)[nei2]=1; } iedges++; IGRAPH_CHECK(igraph_vector_push_back(&edges, new_i)); if (multiplicity) { /* If we need the multiplicity as well, then we put in the old vertex ids here and rewrite it later */ IGRAPH_CHECK(igraph_vector_push_back(&edges, nei2)); } else { new_nei2=(long int) VECTOR(vertex_index)[nei2]-1; IGRAPH_CHECK(igraph_vector_push_back(&edges, new_nei2)); } } } if (multiplicity) { /* OK, we need to go through all the edges added for vertex new_i and check their multiplicity */ long int now=igraph_vector_size(&edges); long int from=now-iedges*2; for (j=from; j<now; j+=2) { long int nei2=(long int) VECTOR(edges)[j+1]; long int new_nei2=(long int) VECTOR(vertex_index)[nei2]-1; long int m=(long int) VECTOR(mult)[nei2]; VECTOR(edges)[j+1]=new_nei2; IGRAPH_CHECK(igraph_vector_push_back(multiplicity, m)); } } } /* if VECTOR(*type)[i] == which */ } if (multiplicity) { igraph_vector_destroy(&mult); IGRAPH_FINALLY_CLEAN(1); } igraph_adjlist_destroy(&adjlist); igraph_vector_long_destroy(&added); igraph_vector_destroy(&vertex_index); IGRAPH_FINALLY_CLEAN(3); IGRAPH_CHECK(igraph_create(proj, &edges, remaining_nodes, /*directed=*/ 0)); igraph_vector_destroy(&edges); IGRAPH_FINALLY_CLEAN(1); IGRAPH_FINALLY(igraph_destroy, proj); IGRAPH_I_ATTRIBUTE_DESTROY(proj); IGRAPH_I_ATTRIBUTE_COPY(proj, graph, 1, 0, 0); IGRAPH_CHECK(igraph_i_attribute_permute_vertices(graph, proj, &vertex_perm)); igraph_vector_destroy(&vertex_perm); IGRAPH_FINALLY_CLEAN(2); return 0; }
int igraph_biconnected_components(const igraph_t *graph, igraph_integer_t *no, igraph_vector_ptr_t *components, igraph_vector_t *articulation_points) { long int no_of_nodes=igraph_vcount(graph); igraph_vector_long_t nextptr; igraph_vector_long_t num, low; igraph_vector_bool_t found; igraph_vector_t *adjedges; igraph_stack_t path; igraph_vector_t edgestack; igraph_adjedgelist_t adjedgelist; long int i, counter, rootdfs=0; IGRAPH_CHECK(igraph_vector_long_init(&nextptr, no_of_nodes)); IGRAPH_FINALLY(igraph_vector_long_destroy, &nextptr); IGRAPH_CHECK(igraph_vector_long_init(&num, no_of_nodes)); IGRAPH_FINALLY(igraph_vector_long_destroy, &num); IGRAPH_CHECK(igraph_vector_long_init(&low, no_of_nodes)); IGRAPH_FINALLY(igraph_vector_long_destroy, &low); IGRAPH_CHECK(igraph_vector_bool_init(&found, no_of_nodes)); IGRAPH_FINALLY(igraph_vector_bool_destroy, &found); IGRAPH_CHECK(igraph_stack_init(&path, 100)); IGRAPH_FINALLY(igraph_stack_destroy, &path); IGRAPH_VECTOR_INIT_FINALLY(&edgestack, 0); IGRAPH_CHECK(igraph_vector_reserve(&edgestack, 100)); IGRAPH_CHECK(igraph_adjedgelist_init(graph, &adjedgelist, IGRAPH_ALL)); IGRAPH_FINALLY(igraph_adjedgelist_destroy, &adjedgelist); if (no) { *no=0; } if (components) { igraph_vector_ptr_clear(components); } if (articulation_points) { igraph_vector_clear(articulation_points); } for (i=0; i<no_of_nodes; i++) { if (VECTOR(low)[i] != 0) { continue; /* already visited */ } IGRAPH_ALLOW_INTERRUPTION(); IGRAPH_CHECK(igraph_stack_push(&path, i)); counter=1; rootdfs=0; VECTOR(low)[i]=VECTOR(num)[i]=counter++; while (!igraph_stack_empty(&path)) { long int n; long int act=igraph_stack_top(&path); long int actnext=VECTOR(nextptr)[act]; adjedges=igraph_adjedgelist_get(&adjedgelist, act); n=igraph_vector_size(adjedges); if (actnext < n) { /* Step down (maybe) */ long int edge=VECTOR(*adjedges)[actnext]; long int nei=IGRAPH_OTHER(graph, edge, act); if (VECTOR(low)[nei] == 0) { if (act==i) { rootdfs++; } IGRAPH_CHECK(igraph_vector_push_back(&edgestack, edge)); IGRAPH_CHECK(igraph_stack_push(&path, nei)); VECTOR(low)[nei] = VECTOR(num)[nei]=counter++; } else { /* Update low value if needed */ if (VECTOR(num)[nei] < VECTOR(low)[act]) { VECTOR(low)[act]=VECTOR(num)[nei]; } } VECTOR(nextptr)[act] += 1; } else { /* Step up */ igraph_stack_pop(&path); if (!igraph_stack_empty(&path)) { long int prev=igraph_stack_top(&path); /* Update LOW value if needed */ if (VECTOR(low)[act] < VECTOR(low)[prev]) { VECTOR(low)[prev] = VECTOR(low)[act]; } /* Check for articulation point */ if (VECTOR(low)[act] >= VECTOR(num)[prev]) { if (articulation_points && !VECTOR(found)[prev] && prev != i /* the root */) { IGRAPH_CHECK(igraph_vector_push_back(articulation_points, prev)); VECTOR(found)[prev] = 1; } if (no) { *no += 1; } if (components) { igraph_vector_t *v=igraph_Calloc(1, igraph_vector_t); IGRAPH_CHECK(igraph_vector_init(v, 0)); while (!igraph_vector_empty(&edgestack)) { long int e=igraph_vector_pop_back(&edgestack); IGRAPH_CHECK(igraph_vector_push_back(v, e)); if (IGRAPH_FROM(graph,e)==prev || IGRAPH_TO(graph,e)==prev) { break; } } IGRAPH_CHECK(igraph_vector_ptr_push_back(components, v)); } } } /* !igraph_stack_empty(&path) */ } } /* !igraph_stack_empty(&path) */ if (articulation_points && rootdfs >= 2) { IGRAPH_CHECK(igraph_vector_push_back(articulation_points, i)); } } /* i < no_of_nodes */ igraph_adjedgelist_destroy(&adjedgelist); igraph_vector_destroy(&edgestack); igraph_stack_destroy(&path); igraph_vector_bool_destroy(&found); igraph_vector_long_destroy(&low); igraph_vector_long_destroy(&num); igraph_vector_long_destroy(&nextptr); IGRAPH_FINALLY_CLEAN(7); return 0; }
int igraph_union_many(igraph_t *res, const igraph_vector_ptr_t *graphs, igraph_vector_ptr_t *edgemaps) { long int no_of_graphs=igraph_vector_ptr_size(graphs); long int no_of_nodes=0; igraph_bool_t directed=1; igraph_vector_t edges; igraph_vector_ptr_t edge_vects, order_vects; igraph_vector_long_t no_edges; long int i, j, tailfrom= no_of_graphs > 0 ? 0 : -1, tailto=-1; long int idx=0; /* Check directedness */ if (no_of_graphs != 0) { directed=igraph_is_directed(VECTOR(*graphs)[0]); no_of_nodes=igraph_vcount(VECTOR(*graphs)[0]); } for (i=1; i<no_of_graphs; i++) { if (directed != igraph_is_directed(VECTOR(*graphs)[i])) { IGRAPH_ERROR("Cannot union directed and undirected graphs", IGRAPH_EINVAL); } } if (edgemaps) { IGRAPH_CHECK(igraph_vector_ptr_resize(edgemaps, no_of_graphs)); igraph_vector_ptr_null(edgemaps); IGRAPH_FINALLY(igraph_i_union_many_free3, edgemaps); } IGRAPH_VECTOR_INIT_FINALLY(&edges, 0); IGRAPH_CHECK(igraph_vector_long_init(&no_edges, no_of_graphs)); IGRAPH_FINALLY(igraph_vector_long_destroy, &no_edges); /* Calculate number of nodes, query number of edges */ for (i=0; i<no_of_graphs; i++) { long int n=igraph_vcount(VECTOR(*graphs)[i]); if (n > no_of_nodes) { no_of_nodes=n; } VECTOR(no_edges)[i] = igraph_ecount(VECTOR(*graphs)[i]); } if (edgemaps) { for (i=0; i<no_of_graphs; i++) { VECTOR(*edgemaps)[i]=igraph_Calloc(1, igraph_vector_t); if (!VECTOR(*edgemaps)[i]) { IGRAPH_ERROR("Cannot union graphs", IGRAPH_ENOMEM); } IGRAPH_CHECK(igraph_vector_init(VECTOR(*edgemaps)[i], VECTOR(no_edges)[i])); } } /* Allocate memory for the edge lists and their index vectors */ if (no_of_graphs != 0) { IGRAPH_CHECK(igraph_vector_ptr_init(&edge_vects, no_of_graphs)); IGRAPH_FINALLY(igraph_i_union_many_free, &edge_vects); IGRAPH_CHECK(igraph_vector_ptr_init(&order_vects, no_of_graphs)); IGRAPH_FINALLY(igraph_i_union_many_free2, &order_vects); } for (i=0; i<no_of_graphs; i++) { VECTOR(edge_vects)[i]=igraph_Calloc(1, igraph_vector_t); VECTOR(order_vects)[i]=igraph_Calloc(1, igraph_vector_long_t); if (! VECTOR(edge_vects)[i] || ! VECTOR(order_vects)[i]) { IGRAPH_ERROR("Cannot union graphs", IGRAPH_ENOMEM); } IGRAPH_CHECK(igraph_vector_init(VECTOR(edge_vects)[i], 2 * VECTOR(no_edges)[i])); IGRAPH_CHECK(igraph_vector_long_init(VECTOR(order_vects)[i], VECTOR(no_edges)[i])); } /* Query and sort the edge lists */ for (i=0; i<no_of_graphs; i++) { long int k, j, n=VECTOR(no_edges)[i]; igraph_vector_t *edges=VECTOR(edge_vects)[i]; igraph_vector_long_t *order=VECTOR(order_vects)[i]; IGRAPH_CHECK(igraph_get_edgelist(VECTOR(*graphs)[i], edges, /*bycol=*/0)); if (!directed) { for (k=0, j=0; k<n; k++, j+=2) { if (VECTOR(*edges)[j] > VECTOR(*edges)[j+1]) { long int tmp=VECTOR(*edges)[j]; VECTOR(*edges)[j]=VECTOR(*edges)[j+1]; VECTOR(*edges)[j+1]=tmp; } } } for (k=0; k<n; k++) { VECTOR(*order)[k]=k; } igraph_qsort_r(VECTOR(*order), n, sizeof(VECTOR(*order)[0]), edges, igraph_i_order_edgelist_cmp); } while (tailfrom >= 0) { /* Get the largest tail element */ tailfrom = tailto = -1; for (j=0; j<no_of_graphs; j++) { if (!igraph_vector_long_empty(VECTOR(order_vects)[j])) { long int edge=igraph_vector_long_tail(VECTOR(order_vects)[j]); igraph_vector_t *ev=VECTOR(edge_vects)[j]; long int from=VECTOR(*ev)[2*edge]; long int to=VECTOR(*ev)[2*edge+1]; if (from > tailfrom || (from == tailfrom && to > tailto)) { tailfrom = from; tailto = to; } } } if (tailfrom < 0) { continue; } /* add the edge */ IGRAPH_CHECK(igraph_vector_push_back(&edges, tailfrom)); IGRAPH_CHECK(igraph_vector_push_back(&edges, tailto)); /* update edge lists, we just modify the 'order' vectors */ for (j=0; j<no_of_graphs; j++) { if (!igraph_vector_long_empty(VECTOR(order_vects)[j])) { long int edge=igraph_vector_long_tail(VECTOR(order_vects)[j]); igraph_vector_t *ev=VECTOR(edge_vects)[j]; long int from=VECTOR(*ev)[2*edge]; long int to=VECTOR(*ev)[2*edge+1]; if (from == tailfrom && to == tailto) { igraph_vector_long_pop_back(VECTOR(order_vects)[j]); if (edgemaps) { igraph_vector_t *map=VECTOR(*edgemaps)[j]; VECTOR(*map)[edge]=idx; } } } } idx++; } if (no_of_graphs > 0) { igraph_i_union_many_free2(&order_vects); igraph_i_union_many_free(&edge_vects); IGRAPH_FINALLY_CLEAN(2); } igraph_vector_long_destroy(&no_edges); IGRAPH_FINALLY_CLEAN(1); IGRAPH_CHECK(igraph_create(res, &edges, (igraph_integer_t) no_of_nodes, directed)); igraph_vector_destroy(&edges); IGRAPH_FINALLY_CLEAN(1); if (edgemaps) { IGRAPH_FINALLY_CLEAN(1); } return 0; }
int igraph_forest_fire_game(igraph_t *graph, igraph_integer_t nodes, igraph_real_t fw_prob, igraph_real_t bw_factor, igraph_integer_t pambs, igraph_bool_t directed) { igraph_vector_long_t visited; long int no_of_nodes=nodes, actnode, i; igraph_vector_t edges; igraph_vector_t *inneis, *outneis; igraph_i_forest_fire_data_t data; igraph_dqueue_t neiq; long int ambs=pambs; igraph_real_t param_geom_out=1-fw_prob; igraph_real_t param_geom_in=1-fw_prob*bw_factor; if (fw_prob < 0) { IGRAPH_ERROR("Forest fire model: 'fw_prob' should be between non-negative", IGRAPH_EINVAL); } if (bw_factor < 0) { IGRAPH_ERROR("Forest fire model: 'bw_factor' should be non-negative", IGRAPH_EINVAL); } if (ambs < 0) { IGRAPH_ERROR("Number of ambassadors ('ambs') should be non-negative", IGRAPH_EINVAL); } if (fw_prob == 0 || ambs == 0) { IGRAPH_WARNING("'fw_prob or ambs is zero, creating empty graph"); IGRAPH_CHECK(igraph_empty(graph, nodes, directed)); return 0; } IGRAPH_VECTOR_INIT_FINALLY(&edges, 0); inneis=igraph_Calloc(no_of_nodes, igraph_vector_t); if (!inneis) { IGRAPH_ERROR("Cannot run forest fire model", IGRAPH_ENOMEM); } IGRAPH_FINALLY(igraph_free, inneis); outneis=igraph_Calloc(no_of_nodes, igraph_vector_t); if (!outneis) { IGRAPH_ERROR("Cannot run forest fire model", IGRAPH_ENOMEM); } IGRAPH_FINALLY(igraph_free, outneis); data.inneis=inneis; data.outneis=outneis; data.no_of_nodes=no_of_nodes; IGRAPH_FINALLY(igraph_i_forest_fire_free, &data); for (i=0; i<no_of_nodes; i++) { IGRAPH_CHECK(igraph_vector_init(inneis+i, 0)); IGRAPH_CHECK(igraph_vector_init(outneis+i, 0)); } IGRAPH_CHECK(igraph_vector_long_init(&visited, no_of_nodes)); IGRAPH_FINALLY(igraph_vector_long_destroy, &visited); IGRAPH_DQUEUE_INIT_FINALLY(&neiq, 10); RNG_BEGIN(); #define ADD_EDGE_TO(nei) \ if (VECTOR(visited)[(nei)] != actnode+1) { \ VECTOR(visited)[(nei)] = actnode+1; \ IGRAPH_CHECK(igraph_dqueue_push(&neiq, nei)); \ IGRAPH_CHECK(igraph_vector_push_back(&edges, actnode)); \ IGRAPH_CHECK(igraph_vector_push_back(&edges, nei)); \ IGRAPH_CHECK(igraph_vector_push_back(outneis+actnode, nei)); \ IGRAPH_CHECK(igraph_vector_push_back(inneis+nei, actnode)); \ } IGRAPH_PROGRESS("Forest fire: ", 0.0, NULL); for (actnode=1; actnode < no_of_nodes; actnode++) { IGRAPH_PROGRESS("Forest fire: ", 100.0*actnode/no_of_nodes, NULL); IGRAPH_ALLOW_INTERRUPTION(); /* We don't want to visit the current vertex */ VECTOR(visited)[actnode] = actnode+1; /* Choose ambassador(s) */ for (i=0; i<ambs; i++) { long int a=RNG_INTEGER(0, actnode-1); ADD_EDGE_TO(a); } while (!igraph_dqueue_empty(&neiq)) { long int actamb=(long int) igraph_dqueue_pop(&neiq); igraph_vector_t *outv=outneis+actamb; igraph_vector_t *inv=inneis+actamb; long int no_in=igraph_vector_size(inv); long int no_out=igraph_vector_size(outv); long int neis_out=(long int) RNG_GEOM(param_geom_out); long int neis_in=(long int) RNG_GEOM(param_geom_in); /* outgoing neighbors */ if (neis_out >= no_out) { for (i=0; i<no_out; i++) { long int nei=(long int) VECTOR(*outv)[i]; ADD_EDGE_TO(nei); } } else { long int oleft=no_out; for (i=0; i<neis_out && oleft > 0; ) { long int which=RNG_INTEGER(0, oleft-1); long int nei=(long int) VECTOR(*outv)[which]; VECTOR(*outv)[which] = VECTOR(*outv)[oleft-1]; VECTOR(*outv)[oleft-1] = nei; if (VECTOR(visited)[nei] != actnode+1) { ADD_EDGE_TO(nei); i++; } oleft--; } } /* incoming neighbors */ if (neis_in >= no_in) { for (i=0; i<no_in; i++) { long int nei=(long int) VECTOR(*inv)[i]; ADD_EDGE_TO(nei); } } else { long int ileft=no_in; for (i=0; i<neis_in && ileft > 0; ) { long int which=RNG_INTEGER(0, ileft-1); long int nei=(long int) VECTOR(*inv)[which]; VECTOR(*inv)[which] = VECTOR(*inv)[ileft-1]; VECTOR(*inv)[ileft-1] = nei; if (VECTOR(visited)[nei] != actnode+1) { ADD_EDGE_TO(nei); i++; } ileft--; } } } /* while neiq not empty */ } /* actnode < no_of_nodes */ #undef ADD_EDGE_TO RNG_END(); IGRAPH_PROGRESS("Forest fire: ", 100.0, NULL); igraph_dqueue_destroy(&neiq); igraph_vector_long_destroy(&visited); igraph_i_forest_fire_free(&data); igraph_free(outneis); igraph_free(inneis); IGRAPH_FINALLY_CLEAN(5); IGRAPH_CHECK(igraph_create(graph, &edges, nodes, directed)); igraph_vector_destroy(&edges); IGRAPH_FINALLY_CLEAN(1); return 0; }
int igraph_revolver_st_p_p(const igraph_t *graph, igraph_lazy_inclist_t *inclist, igraph_vector_t *st, const igraph_matrix_t *kernel, const igraph_vector_t *vtime, const igraph_vector_t *vtimeidx, const igraph_vector_t *etime, const igraph_vector_t *etimeidx, igraph_integer_t pno_of_events, const igraph_vector_t *authors, const igraph_vector_t *eventsizes, igraph_integer_t pmaxpapers) { long int no_of_events=pno_of_events; long int maxpapers=igraph_matrix_nrow(kernel)-1; long int no_of_nodes=igraph_vcount(graph); long int no_of_edges=igraph_ecount(graph); long int timestep=0; igraph_vector_long_t papers; igraph_vector_long_t ntk; igraph_vector_char_t added; igraph_vector_t *adjedges; long int i; long int nptr=0, eptr=0, aptr=0, nptr_save; IGRAPH_CHECK(igraph_vector_long_init(&ntk, maxpapers+1)); IGRAPH_FINALLY(igraph_vector_long_destroy, &ntk); IGRAPH_CHECK(igraph_vector_long_init(&papers, no_of_nodes)); IGRAPH_FINALLY(igraph_vector_long_destroy, &papers); IGRAPH_CHECK(igraph_vector_char_init(&added, no_of_edges)); IGRAPH_FINALLY(igraph_vector_char_destroy, &added); IGRAPH_CHECK(igraph_vector_resize(st, no_of_events)); VECTOR(*st)[0]=0; for (timestep=0; timestep<no_of_events-1; timestep++) { IGRAPH_ALLOW_INTERRUPTION(); /* add the new nodes */ nptr_save=nptr; while (nptr < no_of_nodes && VECTOR(*vtime)[ (long int) VECTOR(*vtimeidx)[nptr] ] == timestep) { nptr++; } nptr_save=nptr-nptr_save; if (nptr_save != 0) { for (i=0; i<maxpapers+1; i++) { VECTOR(*st)[timestep] += VECTOR(ntk)[i]*MATRIX(*kernel, i, 0)*nptr_save; } VECTOR(*st)[timestep] += nptr_save*(nptr_save-1)/2 * MATRIX(*kernel, 0, 0); VECTOR(ntk)[0]+=nptr_save; } VECTOR(*st)[timestep+1] = VECTOR(*st)[timestep]; for (i=aptr; i<aptr+VECTOR(*eventsizes)[timestep]; i++) { long int aut=(long int) VECTOR(*authors)[i]; long int pap=VECTOR(papers)[aut]; long int j, n; for (j=0; j<maxpapers+1; j++) { VECTOR(*st)[timestep+1] += VECTOR(ntk)[j] * (MATRIX(*kernel, j, pap+1)- MATRIX(*kernel, j, pap)); } VECTOR(*st)[timestep+1] += MATRIX(*kernel, pap, pap); VECTOR(*st)[timestep+1] -= MATRIX(*kernel, pap+1, pap+1); VECTOR(ntk)[pap]--; VECTOR(ntk)[pap+1]++; adjedges=igraph_lazy_inclist_get(inclist, (igraph_integer_t) aut); n=igraph_vector_size(adjedges); for (j=0; j<n; j++) { long int edge=(long int) VECTOR(*adjedges)[j]; if (VECTOR(added)[edge]) { long int otherv=IGRAPH_OTHER(graph, edge, aut); long int otherpap=VECTOR(papers)[otherv]; VECTOR(*st)[timestep+1] += MATRIX(*kernel, pap, otherpap); VECTOR(*st)[timestep+1] -= MATRIX(*kernel, pap+1, otherpap); } } VECTOR(papers)[aut] += 1; } aptr += VECTOR(*eventsizes)[timestep]; while (eptr < no_of_edges && VECTOR(*etime)[ (long int) VECTOR(*etimeidx)[eptr] ] == timestep) { long int edge=(long int) VECTOR(*etimeidx)[eptr]; long int from=IGRAPH_FROM(graph, edge); long int to=IGRAPH_TO(graph, edge); long int xidx=VECTOR(papers)[from]; long int yidx=VECTOR(papers)[to]; VECTOR(*st)[timestep+1] -= MATRIX(*kernel, xidx, yidx); VECTOR(added)[edge]=1; eptr++; } } igraph_vector_char_destroy(&added); igraph_vector_long_destroy(&papers); igraph_vector_long_destroy(&ntk); IGRAPH_FINALLY_CLEAN(3); return 0; }
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_mes_d_d(const igraph_t *graph, igraph_lazy_inclist_t *inclist, igraph_matrix_t *kernel, igraph_matrix_t *sd, igraph_matrix_t *norm, igraph_matrix_t *cites, const igraph_matrix_t *debug, igraph_vector_ptr_t *debugres, const igraph_vector_t *st, const igraph_vector_t *vtime, const igraph_vector_t *vtimeidx, const igraph_vector_t *etime, const igraph_vector_t *etimeidx, igraph_integer_t pno_of_events, igraph_integer_t pmaxdegree) { long int no_of_nodes=igraph_vcount(graph); long int no_of_edges=igraph_ecount(graph); long int no_of_events=pno_of_events; long int maxdegree=pmaxdegree; igraph_vector_long_t degree; igraph_vector_char_t added; /* is this edge already in the network? */ igraph_matrix_t v_normfact, *normfact, v_notnull, *notnull; igraph_matrix_t ch; igraph_vector_long_t ntk; /* # of type x vertices */ igraph_matrix_t ntkk; /* # of connections between type x1, x2 vert. */ igraph_vector_t *adjedges; long int timestep, i; long int nptr=0, eptr=0; long int nptr_save, eptr_save, eptr_new; IGRAPH_CHECK(igraph_vector_long_init(°ree, no_of_nodes)); IGRAPH_FINALLY(&igraph_vector_long_destroy, °ree); IGRAPH_CHECK(igraph_vector_char_init(&added, no_of_edges)); IGRAPH_FINALLY(igraph_vector_char_destroy, &added); IGRAPH_CHECK(igraph_vector_long_init(&ntk, maxdegree+1)); IGRAPH_FINALLY(igraph_vector_long_destroy, &ntk); IGRAPH_MATRIX_INIT_FINALLY(&ntkk, maxdegree+1, maxdegree+1); IGRAPH_MATRIX_INIT_FINALLY(&ch, maxdegree+1, maxdegree+1); if (norm) { normfact=norm; IGRAPH_CHECK(igraph_matrix_resize(normfact, maxdegree+1, maxdegree+1)); igraph_matrix_null(normfact); } else { normfact=&v_normfact; IGRAPH_MATRIX_INIT_FINALLY(normfact, maxdegree+1, maxdegree+1); } if (cites) { notnull=cites; IGRAPH_CHECK(igraph_matrix_resize(notnull, maxdegree+1, maxdegree+1)); igraph_matrix_null(notnull); } else { notnull=&v_notnull; IGRAPH_MATRIX_INIT_FINALLY(notnull, maxdegree+1, maxdegree+1); } IGRAPH_CHECK(igraph_matrix_resize(kernel, maxdegree+1, maxdegree+1)); igraph_matrix_null(kernel); if (sd) { IGRAPH_CHECK(igraph_matrix_resize(sd, maxdegree+1, maxdegree+1)); igraph_matrix_null(sd); } for (timestep=0; timestep<no_of_events; timestep++) { IGRAPH_ALLOW_INTERRUPTION(); /* Add the vertices in the first */ nptr_save=nptr; while (nptr < no_of_nodes && VECTOR(*vtime)[(long int)VECTOR(*vtimeidx)[nptr]]==timestep) { nptr++; } VECTOR(ntk)[0] += (nptr-nptr_save); /* Update ch accordingly, could be done later as well */ if (VECTOR(ntk)[0] == nptr-nptr_save && nptr!=nptr_save) { if (nptr-nptr_save >= 2) { MATRIX(ch, 0, 0) = eptr; } for (i=1; i<maxdegree+1; i++) { if (NTKK(0,i) == (nptr-nptr_save)*VECTOR(ntk)[i]) { MATRIX(ch, 0, i) = MATRIX(ch, i, 0) = eptr; } } } /* Estimate Akk */ eptr_save=eptr; while (eptr < no_of_edges && VECTOR(*etime)[(long int)VECTOR(*etimeidx)[eptr] ] == timestep) { long int edge=(long int) VECTOR(*etimeidx)[eptr]; long int from=IGRAPH_FROM(graph, edge), to=IGRAPH_TO(graph, edge); long int xidx=VECTOR(degree)[from]; long int yidx=VECTOR(degree)[to]; double xk, oldakk; MATRIX(*notnull, xidx, yidx) += 1; MATRIX(*notnull, yidx, xidx) = MATRIX(*notnull, xidx, yidx); xk=VECTOR(*st)[timestep]/NTKK(xidx, yidx); oldakk=MATRIX(*kernel, xidx, yidx); MATRIX(*kernel, xidx, yidx) += (xk-oldakk)/MATRIX(*notnull, xidx, yidx); MATRIX(*kernel, yidx, xidx) = MATRIX(*kernel, xidx, yidx); if (sd) { MATRIX(*sd, xidx, yidx) += (xk-oldakk)*(xk-MATRIX(*kernel, xidx, yidx)); MATRIX(*sd, yidx, xidx) = MATRIX(*sd, xidx, yidx); } /* TODO: debug */ eptr++; } /* Update ntkk, ntk, ch, normfact, add the edges */ eptr_new=eptr; eptr=eptr_save; while (eptr < no_of_edges && VECTOR(*etime)[(long int) VECTOR(*etimeidx)[eptr] ] == timestep) { long int edge=(long int) VECTOR(*etimeidx)[eptr]; long int from=IGRAPH_FROM(graph, edge); long int to=IGRAPH_TO(graph, edge); long int xidx=VECTOR(degree)[from]; long int yidx=VECTOR(degree)[to]; long int n; adjedges=igraph_lazy_inclist_get(inclist, (igraph_integer_t) from); n=igraph_vector_size(adjedges); for (i=0; i<n; i++) { long int edge=(long int) VECTOR(*adjedges)[i]; if (VECTOR(added)[edge]) { long int otherv=IGRAPH_OTHER(graph, edge, from); /* other than from */ long int deg=VECTOR(degree)[otherv]; MATRIX(ntkk, xidx, deg) -= 1; MATRIX(ntkk, deg, xidx) = MATRIX(ntkk, xidx, deg); if (NTKK(xidx, deg)==1) { MATRIX(ch, deg, xidx) = eptr_new; MATRIX(ch, xidx, deg) = MATRIX(ch, deg, xidx); } MATRIX(ntkk, xidx+1, deg) += 1; MATRIX(ntkk, deg, xidx+1) = MATRIX(ntkk, xidx+1, deg); if (NTKK(xidx+1, deg)==0) { MATRIX(*normfact, xidx+1, deg) += eptr_new-MATRIX(ch, xidx+1, deg); MATRIX(*normfact, deg, xidx+1) = MATRIX(*normfact, xidx+1, deg); } } } adjedges=igraph_lazy_inclist_get(inclist, (igraph_integer_t) to); n=igraph_vector_size(adjedges); for (i=0; i<n; i++) { long int edge=(long int) VECTOR(*adjedges)[i]; if (VECTOR(added)[edge]) { long int otherv=IGRAPH_OTHER(graph, edge, to); /* other than to */ long int deg=VECTOR(degree)[otherv]; MATRIX(ntkk, yidx, deg) -= 1; MATRIX(ntkk, deg, yidx) = MATRIX(ntkk, yidx, deg); if (NTKK(yidx, deg)==1) { MATRIX(ch, deg, yidx) = eptr_new; MATRIX(ch, yidx, deg) = MATRIX(ch, deg, yidx); } MATRIX(ntkk, yidx+1, deg) += 1; MATRIX(ntkk, deg, yidx+1) = MATRIX(ntkk, yidx+1, deg); if (NTKK(yidx+1, deg)==0) { MATRIX(*normfact, yidx+1, deg) += eptr_new-MATRIX(ch, yidx+1, deg); MATRIX(*normfact, deg, yidx+1) = MATRIX(*normfact, yidx+1, deg); } } } VECTOR(added)[edge]=1; MATRIX(ntkk, xidx+1, yidx+1) += 1; MATRIX(ntkk, yidx+1, xidx+1) = MATRIX(ntkk, xidx+1, yidx+1); if (NTKK(xidx+1, yidx+1)==0) { MATRIX(*normfact, xidx+1, yidx+1) = eptr_new-MATRIX(ch, xidx+1, yidx+1); MATRIX(*normfact, yidx+1, xidx+1) = MATRIX(*normfact, xidx+1, yidx+1); } for (i=0; i<maxdegree+1; i++) { long int before, after; before=(long int) NTKK(xidx,i); VECTOR(ntk)[xidx] -= 1; after=(long int) NTKK(xidx,i); VECTOR(ntk)[xidx] += 1; if (before > 0 && after==0) { MATRIX(*normfact, xidx, i) += eptr_new-MATRIX(ch, xidx, i); MATRIX(*normfact, i, xidx) = MATRIX(*normfact, xidx, i); } } VECTOR(ntk)[xidx]--; for (i=0; i<maxdegree+1; i++) { long int before, after; before=(long int) NTKK(yidx, i); VECTOR(ntk)[yidx] -= 1; after=(long int) NTKK(yidx, i); VECTOR(ntk)[yidx] += 1; if (before > 0 && after==0) { MATRIX(*normfact, yidx, i) += eptr_new-MATRIX(ch, yidx, i); MATRIX(*normfact, i, yidx) = MATRIX(*normfact, yidx, i); } } VECTOR(ntk)[yidx]--; for (i=0; i<maxdegree+1; i++) { long int before, after; before=(long int) NTKK(xidx+1, i); VECTOR(ntk)[xidx+1] += 1; after=(long int) NTKK(xidx+1, i); VECTOR(ntk)[xidx+1] -= 1; if (before==0 && after > 0) { MATRIX(ch, xidx+1, i) = eptr_new; MATRIX(ch, i, xidx+1) = MATRIX(ch, xidx+1, i); } } VECTOR(ntk)[xidx+1]++; for (i=0; i<maxdegree+1; i++) { long int before, after; before=(long int) NTKK(yidx+1, i); VECTOR(ntk)[yidx+1] += 1; after=(long int) NTKK(yidx+1, i); VECTOR(ntk)[yidx+1] -= 1; if (before == 0 && after == 0) { MATRIX(ch, yidx+1, i) = eptr_new; MATRIX(ch, i, yidx+1) = MATRIX(ch, yidx+1, i); } } VECTOR(ntk)[yidx+1]++; VECTOR(degree)[from]++; VECTOR(degree)[to]++; eptr++; } } for (i=0; i<maxdegree+1; i++) { igraph_real_t oldakk; long int j; for (j=0; j<=i; j++) { if (NTKK(i, j) != 0) { MATRIX(*normfact, i, j) += (eptr-MATRIX(ch, i, j)); MATRIX(*normfact, j, i) = MATRIX(*normfact, i, j); } if (MATRIX(*normfact, i, j)==0) { MATRIX(*kernel, i, j)=MATRIX(*kernel, j, i)=0; MATRIX(*normfact, i, j)=MATRIX(*normfact, j, i)=1; } oldakk=MATRIX(*kernel, i, j); MATRIX(*kernel, i, j) *= MATRIX(*notnull, i, j)/MATRIX(*normfact, i, j); MATRIX(*kernel, j, i) = MATRIX(*kernel, i, j); if (sd) { MATRIX(*sd, i, j) += oldakk * oldakk * MATRIX(*notnull, i, j) * (1-MATRIX(*notnull, i, j)/MATRIX(*normfact, i, j)); MATRIX(*sd, i, j) = sqrt(MATRIX(*sd, i, j)/(MATRIX(*normfact, i, j)-1)); MATRIX(*sd, j, i) = MATRIX(*sd, i, j); } } } if (!cites) { igraph_matrix_destroy(notnull); IGRAPH_FINALLY_CLEAN(1); } if (!norm) { igraph_matrix_destroy(normfact); IGRAPH_FINALLY_CLEAN(1); } igraph_matrix_destroy(&ch); igraph_matrix_destroy(&ntkk); igraph_vector_long_destroy(&ntk); igraph_vector_char_destroy(&added); igraph_vector_long_destroy(°ree); IGRAPH_FINALLY_CLEAN(5); return 0; }
int igraph_i_maximum_bipartite_matching_unweighted(const igraph_t* graph, const igraph_vector_bool_t* types, igraph_integer_t* matching_size, igraph_vector_long_t* matching) { long int i, j, k, n, no_of_nodes = igraph_vcount(graph); long int num_matched; /* number of matched vertex pairs */ igraph_vector_long_t match; /* will store the matching */ igraph_vector_t labels; /* will store the labels */ igraph_vector_t neis; /* used to retrieve the neighbors of a node */ igraph_dqueue_long_t q; /* a FIFO for push ordering */ igraph_bool_t smaller_set; /* denotes which part of the bipartite graph is smaller */ long int label_changed = 0; /* Counter to decide when to run a global relabeling */ long int relabeling_freq = no_of_nodes / 2; /* We will use: * - FIFO push ordering * - global relabeling frequency: n/2 steps where n is the number of nodes * - simple greedy matching for initialization */ /* (1) Initialize data structures */ IGRAPH_CHECK(igraph_vector_long_init(&match, no_of_nodes)); IGRAPH_FINALLY(igraph_vector_long_destroy, &match); IGRAPH_VECTOR_INIT_FINALLY(&labels, no_of_nodes); IGRAPH_VECTOR_INIT_FINALLY(&neis, 0); IGRAPH_CHECK(igraph_dqueue_long_init(&q, 0)); IGRAPH_FINALLY(igraph_dqueue_long_destroy, &q); /* (2) Initially, every node is unmatched */ igraph_vector_long_fill(&match, -1); /* (3) Find an initial matching in a greedy manner. * At the same time, find which side of the graph is smaller. */ num_matched = 0; j = 0; for (i = 0; i < no_of_nodes; i++) { if (VECTOR(*types)[i]) j++; if (MATCHED(i)) continue; IGRAPH_CHECK(igraph_neighbors(graph, &neis, (igraph_integer_t) i, IGRAPH_ALL)); n = igraph_vector_size(&neis); for (j = 0; j < n; j++) { k = (long int) VECTOR(neis)[j]; if (UNMATCHED(k)) { /* We match vertex i to vertex VECTOR(neis)[j] */ VECTOR(match)[k] = i; VECTOR(match)[i] = k; num_matched++; break; } } } smaller_set = (j <= no_of_nodes/2); /* (4) Set the initial labeling -- lines 1 and 2 in the tech report */ IGRAPH_CHECK(igraph_i_maximum_bipartite_matching_unweighted_relabel( graph, types, &labels, &match, smaller_set)); /* (5) Fill the push queue with the unmatched nodes from the smaller set. */ for (i = 0; i < no_of_nodes; i++) { if (UNMATCHED(i) && VECTOR(*types)[i] == smaller_set) IGRAPH_CHECK(igraph_dqueue_long_push(&q, i)); } /* (6) Main loop from the referenced tech report -- lines 4--13 */ label_changed = 0; while (!igraph_dqueue_long_empty(&q)) { long int v = igraph_dqueue_long_pop(&q); /* Line 13 */ long int u = -1, label_u = 2 * no_of_nodes; long int w; if (label_changed >= relabeling_freq) { /* Run global relabeling */ IGRAPH_CHECK(igraph_i_maximum_bipartite_matching_unweighted_relabel( graph, types, &labels, &match, smaller_set)); label_changed = 0; } debug("Considering vertex %ld\n", v); /* Line 5: find row u among the neighbors of v s.t. label(u) is minimal */ IGRAPH_CHECK(igraph_neighbors(graph, &neis, (igraph_integer_t) v, IGRAPH_ALL)); n = igraph_vector_size(&neis); for (i = 0; i < n; i++) { if (VECTOR(labels)[(long int)VECTOR(neis)[i]] < label_u) { u = (long int) VECTOR(neis)[i]; label_u = (long int) VECTOR(labels)[u]; label_changed++; } } debug(" Neighbor with smallest label: %ld (label=%ld)\n", u, label_u); if (label_u < no_of_nodes) { /* Line 6 */ VECTOR(labels)[v] = VECTOR(labels)[u] + 1; /* Line 7 */ if (MATCHED(u)) { /* Line 8 */ w = VECTOR(match)[u]; debug(" Vertex %ld is matched to %ld, performing a double push\n", u, w); if (w != v) { VECTOR(match)[u] = -1; VECTOR(match)[w] = -1; /* Line 9 */ IGRAPH_CHECK(igraph_dqueue_long_push(&q, w)); /* Line 10 */ debug(" Unmatching & activating vertex %ld\n", w); num_matched--; } } VECTOR(match)[u] = v; VECTOR(match)[v] = u; /* Line 11 */ num_matched++; VECTOR(labels)[u] += 2; /* Line 12 */ label_changed++; } printf("MATCH: "); igraph_vector_long_print(&match); printf("LABELS "); igraph_vector_print(&labels); } /* Fill the output parameters */ if (matching != 0) { IGRAPH_CHECK(igraph_vector_long_update(matching, &match)); } if (matching_size != 0) { *matching_size = (igraph_integer_t) num_matched; } /* Release everything */ igraph_dqueue_long_destroy(&q); igraph_vector_destroy(&neis); igraph_vector_destroy(&labels); igraph_vector_long_destroy(&match); IGRAPH_FINALLY_CLEAN(4); return IGRAPH_SUCCESS; }
/** * Finding maximum bipartite matchings on bipartite graphs using the * Hungarian algorithm (a.k.a. Kuhn-Munkres algorithm). * * The algorithm uses a maximum cardinality matching on a subset of * tight edges as a starting point. This is achieved by * \c igraph_i_maximum_bipartite_matching_unweighted on the restricted * graph. * * The algorithm works reliably only if the weights are integers. The * \c eps parameter should specity a very small number; if the slack on * an edge falls below \c eps, it will be considered tight. If all your * weights are integers, you can safely set \c eps to zero. */ int igraph_i_maximum_bipartite_matching_weighted(const igraph_t* graph, const igraph_vector_bool_t* types, igraph_integer_t* matching_size, igraph_real_t* matching_weight, igraph_vector_long_t* matching, const igraph_vector_t* weights, igraph_real_t eps) { long int i, j, k, n, no_of_nodes, no_of_edges; igraph_integer_t u, v, w, msize; igraph_t newgraph; igraph_vector_long_t match; /* will store the matching */ igraph_vector_t slack; /* will store the slack on each edge */ igraph_vector_t parent; /* parent vertices during a BFS */ igraph_vector_t vec1, vec2; /* general temporary vectors */ igraph_vector_t labels; /* will store the labels */ igraph_dqueue_long_t q; /* a FIFO for BST */ igraph_bool_t smaller_set; /* denotes which part of the bipartite graph is smaller */ long int smaller_set_size; /* size of the smaller set */ igraph_real_t dual; /* solution of the dual problem */ igraph_adjlist_t tight_phantom_edges; /* adjacency list to manage tight phantom edges */ igraph_integer_t alternating_path_endpoint; igraph_vector_t* neis; igraph_vector_int_t *neis2; igraph_inclist_t inclist; /* incidence list of the original graph */ /* The Hungarian algorithm is originally for complete bipartite graphs. * For non-complete bipartite graphs, a phantom edge of weight zero must be * added between every pair of non-connected vertices. We don't do this * explicitly of course. See the comments below about how phantom edges * are taken into account. */ no_of_nodes = igraph_vcount(graph); no_of_edges = igraph_ecount(graph); if (eps < 0) { IGRAPH_WARNING("negative epsilon given, clamping to zero"); eps = 0; } /* (1) Initialize data structures */ IGRAPH_CHECK(igraph_vector_long_init(&match, no_of_nodes)); IGRAPH_FINALLY(igraph_vector_long_destroy, &match); IGRAPH_CHECK(igraph_vector_init(&slack, no_of_edges)); IGRAPH_FINALLY(igraph_vector_destroy, &slack); IGRAPH_VECTOR_INIT_FINALLY(&vec1, 0); IGRAPH_VECTOR_INIT_FINALLY(&vec2, 0); IGRAPH_VECTOR_INIT_FINALLY(&labels, no_of_nodes); IGRAPH_CHECK(igraph_dqueue_long_init(&q, 0)); IGRAPH_FINALLY(igraph_dqueue_long_destroy, &q); IGRAPH_VECTOR_INIT_FINALLY(&parent, no_of_nodes); IGRAPH_CHECK(igraph_adjlist_init_empty(&tight_phantom_edges, (igraph_integer_t) no_of_nodes)); IGRAPH_FINALLY(igraph_adjlist_destroy, &tight_phantom_edges); IGRAPH_CHECK(igraph_inclist_init(graph, &inclist, IGRAPH_ALL)); IGRAPH_FINALLY(igraph_inclist_destroy, &inclist); /* (2) Find which set is the smaller one */ j = 0; for (i = 0; i < no_of_nodes; i++) { if (VECTOR(*types)[i] == 0) j++; } smaller_set = (j > no_of_nodes / 2); smaller_set_size = smaller_set ? (no_of_nodes - j) : j; /* (3) Calculate the initial labeling and the set of tight edges. Use the * smaller set only. Here we can assume that there are no phantom edges * among the tight ones. */ dual = 0; for (i = 0; i < no_of_nodes; i++) { igraph_real_t max_weight = 0; if (VECTOR(*types)[i] != smaller_set) { VECTOR(labels)[i] = 0; continue; } neis = igraph_inclist_get(&inclist, i); n = igraph_vector_size(neis); for (j = 0, k = 0; j < n; j++) { if (VECTOR(*weights)[(long int)VECTOR(*neis)[j]] > max_weight) { k = (long int) VECTOR(*neis)[j]; max_weight = VECTOR(*weights)[k]; } } VECTOR(labels)[i] = max_weight; dual += max_weight; } igraph_vector_clear(&vec1); IGRAPH_CHECK(igraph_get_edgelist(graph, &vec2, 0)); #define IS_TIGHT(i) (VECTOR(slack)[i] <= eps) for (i = 0, j = 0; i < no_of_edges; i++, j+=2) { u = (igraph_integer_t) VECTOR(vec2)[j]; v = (igraph_integer_t) VECTOR(vec2)[j+1]; VECTOR(slack)[i] = VECTOR(labels)[u] + VECTOR(labels)[v] - VECTOR(*weights)[i]; if (IS_TIGHT(i)) { IGRAPH_CHECK(igraph_vector_push_back(&vec1, u)); IGRAPH_CHECK(igraph_vector_push_back(&vec1, v)); } } igraph_vector_clear(&vec2); /* (4) Construct a temporary graph on which the initial maximum matching * will be calculated (only on the subset of tight edges) */ IGRAPH_CHECK(igraph_create(&newgraph, &vec1, (igraph_integer_t) no_of_nodes, 0)); IGRAPH_FINALLY(igraph_destroy, &newgraph); IGRAPH_CHECK(igraph_maximum_bipartite_matching(&newgraph, types, &msize, 0, &match, 0, 0)); igraph_destroy(&newgraph); IGRAPH_FINALLY_CLEAN(1); /* (5) Main loop until the matching becomes maximal */ while (msize < smaller_set_size) { igraph_real_t min_slack, min_slack_2; igraph_integer_t min_slack_u, min_slack_v; /* (7) Fill the push queue with the unmatched nodes from the smaller set. */ igraph_vector_clear(&vec1); igraph_vector_clear(&vec2); igraph_vector_fill(&parent, -1); for (i = 0; i < no_of_nodes; i++) { if (UNMATCHED(i) && VECTOR(*types)[i] == smaller_set) { IGRAPH_CHECK(igraph_dqueue_long_push(&q, i)); VECTOR(parent)[i] = i; IGRAPH_CHECK(igraph_vector_push_back(&vec1, i)); } } #ifdef MATCHING_DEBUG debug("Matching:"); igraph_vector_long_print(&match); debug("Unmatched vertices are marked by non-negative numbers:\n"); igraph_vector_print(&parent); debug("Labeling:"); igraph_vector_print(&labels); debug("Slacks:"); igraph_vector_print(&slack); #endif /* (8) Run the BFS */ alternating_path_endpoint = -1; while (!igraph_dqueue_long_empty(&q)) { v = (int) igraph_dqueue_long_pop(&q); debug("Considering vertex %ld\n", (long int)v); /* v is always in the smaller set. Find the neighbors of v, which * are all in the larger set. Find the pairs of these nodes in * the smaller set and push them to the queue. Mark the traversed * nodes as seen. * * Here we have to be careful as there are two types of incident * edges on v: real edges and phantom ones. Real edges are * given by igraph_inclist_get. Phantom edges are not given so we * (ab)use an adjacency list data structure that lists the * vertices connected to v by phantom edges only. */ neis = igraph_inclist_get(&inclist, v); n = igraph_vector_size(neis); for (i = 0; i < n; i++) { j = (long int) VECTOR(*neis)[i]; /* We only care about tight edges */ if (!IS_TIGHT(j)) continue; /* Have we seen the other endpoint already? */ u = IGRAPH_OTHER(graph, j, v); if (VECTOR(parent)[u] >= 0) continue; debug(" Reached vertex %ld via edge %ld\n", (long)u, (long)j); VECTOR(parent)[u] = v; IGRAPH_CHECK(igraph_vector_push_back(&vec2, u)); w = (int) VECTOR(match)[u]; if (w == -1) { /* u is unmatched and it is in the larger set. Therefore, we * could improve the matching by following the parents back * from u to the root. */ alternating_path_endpoint = u; break; /* since we don't need any more endpoints that come from v */ } else { IGRAPH_CHECK(igraph_dqueue_long_push(&q, w)); VECTOR(parent)[w] = u; } IGRAPH_CHECK(igraph_vector_push_back(&vec1, w)); } /* Now do the same with the phantom edges */ neis2 = igraph_adjlist_get(&tight_phantom_edges, v); n = igraph_vector_int_size(neis2); for (i = 0; i < n; i++) { u = (igraph_integer_t) VECTOR(*neis2)[i]; /* Have we seen u already? */ if (VECTOR(parent)[u] >= 0) continue; /* Check if the edge is really tight; it might have happened that the * edge became non-tight in the meanwhile. We do not remove these from * tight_phantom_edges at the moment, so we check them once again here. */ if (fabs(VECTOR(labels)[(long int)v] + VECTOR(labels)[(long int)u]) > eps) continue; debug(" Reached vertex %ld via tight phantom edge\n", (long)u); VECTOR(parent)[u] = v; IGRAPH_CHECK(igraph_vector_push_back(&vec2, u)); w = (int) VECTOR(match)[u]; if (w == -1) { /* u is unmatched and it is in the larger set. Therefore, we * could improve the matching by following the parents back * from u to the root. */ alternating_path_endpoint = u; break; /* since we don't need any more endpoints that come from v */ } else { IGRAPH_CHECK(igraph_dqueue_long_push(&q, w)); VECTOR(parent)[w] = u; } IGRAPH_CHECK(igraph_vector_push_back(&vec1, w)); } } /* Okay; did we have an alternating path? */ if (alternating_path_endpoint != -1) { #ifdef MATCHING_DEBUG debug("BFS parent tree:"); igraph_vector_print(&parent); #endif /* Increase the size of the matching with the alternating path. */ v = alternating_path_endpoint; u = (igraph_integer_t) VECTOR(parent)[v]; debug("Extending matching with alternating path ending in %ld.\n", (long int)v); while (u != v) { w = (int) VECTOR(match)[v]; if (w != -1) VECTOR(match)[w] = -1; VECTOR(match)[v] = u; VECTOR(match)[v] = u; w = (int) VECTOR(match)[u]; if (w != -1) VECTOR(match)[w] = -1; VECTOR(match)[u] = v; v = (igraph_integer_t) VECTOR(parent)[u]; u = (igraph_integer_t) VECTOR(parent)[v]; } msize++; #ifdef MATCHING_DEBUG debug("New matching after update:"); igraph_vector_long_print(&match); debug("Matching size is now: %ld\n", (long)msize); #endif continue; } #ifdef MATCHING_DEBUG debug("Vertices reachable from unmatched ones via tight edges:\n"); igraph_vector_print(&vec1); igraph_vector_print(&vec2); #endif /* At this point, vec1 contains the nodes in the smaller set (A) * reachable from unmatched nodes in A via tight edges only, while vec2 * contains the nodes in the larger set (B) reachable from unmatched * nodes in A via tight edges only. Also, parent[i] >= 0 if node i * is reachable */ /* Check the edges between reachable nodes in A and unreachable * nodes in B, and find the minimum slack on them. * * Since the weights are positive, we do no harm if we first * assume that there are no "real" edges between the two sets * mentioned above and determine an upper bound for min_slack * based on this. */ min_slack = IGRAPH_INFINITY; min_slack_u = min_slack_v = 0; n = igraph_vector_size(&vec1); for (i = 0; i < no_of_nodes; i++) { if (VECTOR(*types)[i] == smaller_set) continue; if (VECTOR(labels)[i] < min_slack) { min_slack = VECTOR(labels)[i]; min_slack_v = (igraph_integer_t) i; } } min_slack_2 = IGRAPH_INFINITY; for (i = 0; i < n; i++) { u = (igraph_integer_t) VECTOR(vec1)[i]; /* u is surely from the smaller set, but we are interested in it * only if it is reachable from an unmatched vertex */ if (VECTOR(parent)[u] < 0) continue; if (VECTOR(labels)[u] < min_slack_2) { min_slack_2 = VECTOR(labels)[u]; min_slack_u = u; } } min_slack += min_slack_2; debug("Starting approximation for min_slack = %.4f (based on vertex pair %ld--%ld)\n", min_slack, (long int)min_slack_u, (long int)min_slack_v); n = igraph_vector_size(&vec1); for (i = 0; i < n; i++) { u = (igraph_integer_t) VECTOR(vec1)[i]; /* u is a reachable node in A; get its incident edges. * * There are two types of incident edges: 1) real edges, * 2) phantom edges. Phantom edges were treated earlier * when we determined the initial value for min_slack. */ debug("Trying to expand along vertex %ld\n", (long int)u); neis = igraph_inclist_get(&inclist, u); k = igraph_vector_size(neis); for (j = 0; j < k; j++) { /* v is the vertex sitting at the other end of an edge incident * on u; check whether it was reached */ v = IGRAPH_OTHER(graph, VECTOR(*neis)[j], u); debug(" Edge %ld -- %ld (ID=%ld)\n", (long int)u, (long int)v, (long int)VECTOR(*neis)[j]); if (VECTOR(parent)[v] >= 0) { /* v was reached, so we are not interested in it */ debug(" %ld was reached, so we are not interested in it\n", (long int)v); continue; } /* v is the ID of the edge from now on */ v = (igraph_integer_t) VECTOR(*neis)[j]; if (VECTOR(slack)[v] < min_slack) { min_slack = VECTOR(slack)[v]; min_slack_u = u; min_slack_v = IGRAPH_OTHER(graph, v, u); } debug(" Slack of this edge: %.4f, min slack is now: %.4f\n", VECTOR(slack)[v], min_slack); } } debug("Minimum slack: %.4f on edge %d--%d\n", min_slack, (int)min_slack_u, (int)min_slack_v); if (min_slack > 0) { /* Decrease the label of reachable nodes in A by min_slack. * Also update the dual solution */ n = igraph_vector_size(&vec1); for (i = 0; i < n; i++) { u = (igraph_integer_t) VECTOR(vec1)[i]; VECTOR(labels)[u] -= min_slack; neis = igraph_inclist_get(&inclist, u); k = igraph_vector_size(neis); for (j = 0; j < k; j++) { debug(" Decreasing slack of edge %ld (%ld--%ld) by %.4f\n", (long)VECTOR(*neis)[j], (long)u, (long)IGRAPH_OTHER(graph, VECTOR(*neis)[j], u), min_slack); VECTOR(slack)[(long int)VECTOR(*neis)[j]] -= min_slack; } dual -= min_slack; } /* Increase the label of reachable nodes in B by min_slack. * Also update the dual solution */ n = igraph_vector_size(&vec2); for (i = 0; i < n; i++) { u = (igraph_integer_t) VECTOR(vec2)[i]; VECTOR(labels)[u] += min_slack; neis = igraph_inclist_get(&inclist, u); k = igraph_vector_size(neis); for (j = 0; j < k; j++) { debug(" Increasing slack of edge %ld (%ld--%ld) by %.4f\n", (long)VECTOR(*neis)[j], (long)u, (long)IGRAPH_OTHER(graph, (long)VECTOR(*neis)[j], u), min_slack); VECTOR(slack)[(long int)VECTOR(*neis)[j]] += min_slack; } dual += min_slack; } } /* Update the set of tight phantom edges. * Note that we must do it even if min_slack is zero; the reason is that * it can happen that min_slack is zero in the first step if there are * isolated nodes in the input graph. * * TODO: this is O(n^2) here. Can we do it faster? */ for (u = 0; u < no_of_nodes; u++) { if (VECTOR(*types)[u] != smaller_set) continue; for (v = 0; v < no_of_nodes; v++) { if (VECTOR(*types)[v] == smaller_set) continue; if (VECTOR(labels)[(long int)u] + VECTOR(labels)[(long int)v] <= eps) { /* Tight phantom edge found. Note that we don't have to check whether * u and v are connected; if they were, then the slack of this edge * would be negative. */ neis2 = igraph_adjlist_get(&tight_phantom_edges, u); if (!igraph_vector_int_binsearch(neis2, v, &i)) { debug("New tight phantom edge: %ld -- %ld\n", (long)u, (long)v); IGRAPH_CHECK(igraph_vector_int_insert(neis2, i, v)); } } } } #ifdef MATCHING_DEBUG debug("New labels:"); igraph_vector_print(&labels); debug("Slacks after updating with min_slack:"); igraph_vector_print(&slack); #endif } /* Cleanup: remove phantom edges from the matching */ for (i = 0; i < no_of_nodes; i++) { if (VECTOR(*types)[i] != smaller_set) continue; if (VECTOR(match)[i] != -1) { j = VECTOR(match)[i]; neis2 = igraph_adjlist_get(&tight_phantom_edges, i); if (igraph_vector_int_binsearch(neis2, j, 0)) { VECTOR(match)[i] = VECTOR(match)[j] = -1; msize--; } } } /* Fill the output parameters */ if (matching != 0) { IGRAPH_CHECK(igraph_vector_long_update(matching, &match)); } if (matching_size != 0) { *matching_size = msize; } if (matching_weight != 0) { *matching_weight = 0; for (i = 0; i < no_of_edges; i++) { if (IS_TIGHT(i)) { IGRAPH_CHECK(igraph_edge(graph, (igraph_integer_t) i, &u, &v)); if (VECTOR(match)[u] == v) *matching_weight += VECTOR(*weights)[i]; } } } /* Release everything */ #undef IS_TIGHT igraph_inclist_destroy(&inclist); igraph_adjlist_destroy(&tight_phantom_edges); igraph_vector_destroy(&parent); igraph_dqueue_long_destroy(&q); igraph_vector_destroy(&labels); igraph_vector_destroy(&vec1); igraph_vector_destroy(&vec2); igraph_vector_destroy(&slack); igraph_vector_long_destroy(&match); IGRAPH_FINALLY_CLEAN(9); return IGRAPH_SUCCESS; }