int igraph_complementer(igraph_t *res, const igraph_t *graph, igraph_bool_t loops) { long int no_of_nodes=igraph_vcount(graph); igraph_vector_t edges; igraph_vector_t neis; long int i, j; long int zero=0, *limit; IGRAPH_VECTOR_INIT_FINALLY(&edges, 0); IGRAPH_VECTOR_INIT_FINALLY(&neis, 0); if (igraph_is_directed(graph)) { limit=&zero; } else { limit=&i; } for (i=0; i<no_of_nodes; i++) { IGRAPH_ALLOW_INTERRUPTION(); IGRAPH_CHECK(igraph_neighbors(graph, &neis, (igraph_integer_t) i, IGRAPH_OUT)); if (loops) { for (j=no_of_nodes-1; j>=*limit; j--) { if (igraph_vector_empty(&neis) || j>igraph_vector_tail(&neis)) { IGRAPH_CHECK(igraph_vector_push_back(&edges, i)); IGRAPH_CHECK(igraph_vector_push_back(&edges, j)); } else { igraph_vector_pop_back(&neis); } } } else { for (j=no_of_nodes-1; j>=*limit; j--) { if (igraph_vector_empty(&neis) || j>igraph_vector_tail(&neis)) { if (i!=j) { IGRAPH_CHECK(igraph_vector_push_back(&edges, i)); IGRAPH_CHECK(igraph_vector_push_back(&edges, j)); } } else { igraph_vector_pop_back(&neis); } } } } IGRAPH_CHECK(igraph_create(res, &edges, (igraph_integer_t) no_of_nodes, igraph_is_directed(graph))); igraph_vector_destroy(&edges); igraph_vector_destroy(&neis); IGRAPH_I_ATTRIBUTE_DESTROY(res); IGRAPH_I_ATTRIBUTE_COPY(res, graph, /*graph=*/1, /*vertex=*/1, /*edge=*/0); IGRAPH_FINALLY_CLEAN(2); return 0; }
/** * \ingroup interface * \function igraph_destroy * \brief Frees the memory allocated for a graph object. * * </para><para> * This function should be called for every graph object exactly once. * * </para><para> * This function invalidates all iterators (of course), but the * iterators of are graph should be destroyed before the graph itself * anyway. * \param graph Pointer to the graph to free. * \return Error code. * * Time complexity: operating system specific. */ int igraph_destroy(igraph_t *graph) { IGRAPH_I_ATTRIBUTE_DESTROY(graph); igraph_vector_destroy(&graph->from); igraph_vector_destroy(&graph->to); igraph_vector_destroy(&graph->oi); igraph_vector_destroy(&graph->ii); igraph_vector_destroy(&graph->os); igraph_vector_destroy(&graph->is); return 0; }
int igraph_difference(igraph_t *res, const igraph_t *orig, const igraph_t *sub) { /* Quite nasty, but we will use that an edge adjacency list contains the vertices according to the order of the vertex ids at the "other" end of the edge. */ long int no_of_nodes_orig=igraph_vcount(orig); long int no_of_nodes_sub =igraph_vcount(sub); long int no_of_nodes=no_of_nodes_orig; long int smaller_nodes; igraph_bool_t directed=igraph_is_directed(orig); igraph_vector_t edges; igraph_vector_t edge_ids; igraph_vector_t *nei1, *nei2; igraph_inclist_t inc_orig, inc_sub; long int i; igraph_integer_t v1, v2; if (directed != igraph_is_directed(sub)) { IGRAPH_ERROR("Cannot subtract directed and undirected graphs", IGRAPH_EINVAL); } IGRAPH_VECTOR_INIT_FINALLY(&edge_ids, 0); IGRAPH_VECTOR_INIT_FINALLY(&edges, 0); IGRAPH_CHECK(igraph_inclist_init(orig, &inc_orig, IGRAPH_OUT)); IGRAPH_FINALLY(igraph_inclist_destroy, &inc_orig); IGRAPH_CHECK(igraph_inclist_init(sub, &inc_sub, IGRAPH_OUT)); IGRAPH_FINALLY(igraph_inclist_destroy, &inc_sub); smaller_nodes=no_of_nodes_orig > no_of_nodes_sub ? no_of_nodes_sub : no_of_nodes_orig; for (i=0; i<smaller_nodes; i++) { long int n1, n2, e1, e2; IGRAPH_ALLOW_INTERRUPTION(); nei1=igraph_inclist_get(&inc_orig, i); nei2=igraph_inclist_get(&inc_sub, i); n1=igraph_vector_size(nei1)-1; n2=igraph_vector_size(nei2)-1; while (n1>=0 && n2>=0) { e1=(long int) VECTOR(*nei1)[n1]; e2=(long int) VECTOR(*nei2)[n2]; v1=IGRAPH_OTHER(orig, e1, i); v2=IGRAPH_OTHER(sub, e2, i); if (!directed && v1<i) { n1--; } else if (!directed && v2<i) { n2--; } else if (v1>v2) { IGRAPH_CHECK(igraph_vector_push_back(&edge_ids, e1)); IGRAPH_CHECK(igraph_vector_push_back(&edges, i)); IGRAPH_CHECK(igraph_vector_push_back(&edges, v1)); n1--; } else if (v2>v1) { n2--; } else { n1--; n2--; } } /* Copy remaining edges */ while (n1>=0) { e1=(long int) VECTOR(*nei1)[n1]; v1=IGRAPH_OTHER(orig, e1, i); if (directed || v1 >= i) { IGRAPH_CHECK(igraph_vector_push_back(&edge_ids, e1)); IGRAPH_CHECK(igraph_vector_push_back(&edges, i)); IGRAPH_CHECK(igraph_vector_push_back(&edges, v1)); } n1--; } } /* copy remaining edges, use the previous value of 'i' */ for (; i<no_of_nodes_orig; i++) { long int n1, e1; nei1=igraph_inclist_get(&inc_orig, i); n1=igraph_vector_size(nei1)-1; while (n1>=0) { e1=(long int) VECTOR(*nei1)[n1]; v1=IGRAPH_OTHER(orig, e1, i); if (directed || v1 >= i) { IGRAPH_CHECK(igraph_vector_push_back(&edge_ids, e1)); IGRAPH_CHECK(igraph_vector_push_back(&edges, i)); IGRAPH_CHECK(igraph_vector_push_back(&edges, v1)); } n1--; } } igraph_inclist_destroy(&inc_sub); igraph_inclist_destroy(&inc_orig); IGRAPH_FINALLY_CLEAN(2); IGRAPH_CHECK(igraph_create(res, &edges, (igraph_integer_t) no_of_nodes, directed)); igraph_vector_destroy(&edges); IGRAPH_FINALLY_CLEAN(1); /* Attributes */ if (orig->attr) { IGRAPH_I_ATTRIBUTE_DESTROY(res); IGRAPH_I_ATTRIBUTE_COPY(res, orig, /*graph=*/1, /*vertex=*/1, /*edge=*/0); IGRAPH_CHECK(igraph_i_attribute_permute_edges(orig, res, &edge_ids)); } igraph_vector_destroy(&edge_ids); IGRAPH_FINALLY_CLEAN(1); 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_to_undirected(igraph_t *graph, igraph_to_undirected_t mode) { long int no_of_nodes=igraph_vcount(graph); long int no_of_edges=igraph_ecount(graph); igraph_vector_t edges; igraph_t newgraph; if (mode != IGRAPH_TO_UNDIRECTED_EACH && mode != IGRAPH_TO_UNDIRECTED_COLLAPSE) { IGRAPH_ERROR("Cannot undirect graph, invalid mode", IGRAPH_EINVAL); } if (!igraph_is_directed(graph)) { return 0; } IGRAPH_VECTOR_INIT_FINALLY(&edges, 0); if (mode==IGRAPH_TO_UNDIRECTED_EACH) { igraph_es_t es; igraph_eit_t eit; IGRAPH_CHECK(igraph_vector_reserve(&edges, no_of_edges*2)); IGRAPH_CHECK(igraph_es_all(&es, IGRAPH_EDGEORDER_ID)); IGRAPH_FINALLY(igraph_es_destroy, &es); IGRAPH_CHECK(igraph_eit_create(graph, es, &eit)); IGRAPH_FINALLY(igraph_eit_destroy, &eit); while (!IGRAPH_EIT_END(eit)) { long int edge=IGRAPH_EIT_GET(eit); igraph_integer_t from, to; igraph_edge(graph, edge, &from, &to); IGRAPH_CHECK(igraph_vector_push_back(&edges, from)); IGRAPH_CHECK(igraph_vector_push_back(&edges, to)); IGRAPH_EIT_NEXT(eit); } igraph_eit_destroy(&eit); igraph_es_destroy(&es); IGRAPH_FINALLY_CLEAN(2); IGRAPH_CHECK(igraph_create(&newgraph, &edges, no_of_nodes, IGRAPH_UNDIRECTED)); IGRAPH_FINALLY(igraph_destroy, &newgraph); igraph_vector_destroy(&edges); IGRAPH_I_ATTRIBUTE_DESTROY(&newgraph); IGRAPH_I_ATTRIBUTE_COPY(&newgraph, graph, 1,1,1); IGRAPH_FINALLY_CLEAN(2); igraph_destroy(graph); *graph=newgraph; } else if (mode==IGRAPH_TO_UNDIRECTED_COLLAPSE) { igraph_vector_t seen, nei; long int i,j; IGRAPH_CHECK(igraph_vector_reserve(&edges, no_of_edges*2)); IGRAPH_VECTOR_INIT_FINALLY(&seen, no_of_nodes); IGRAPH_VECTOR_INIT_FINALLY(&nei, 0); for (i=0; i<no_of_nodes; i++) { IGRAPH_CHECK(igraph_neighbors(graph, &nei, i, IGRAPH_ALL)); for (j=0; j<igraph_vector_size(&nei); j++) { long int node=VECTOR(nei)[j]; if (VECTOR(seen)[node] != i+1 && node >= i) { IGRAPH_CHECK(igraph_vector_push_back(&edges, i)); IGRAPH_CHECK(igraph_vector_push_back(&edges, node)); VECTOR(seen)[node]=i+1; } } } igraph_vector_destroy(&nei); igraph_vector_destroy(&seen); IGRAPH_FINALLY_CLEAN(2); IGRAPH_CHECK(igraph_create(&newgraph, &edges, no_of_nodes, IGRAPH_UNDIRECTED)); IGRAPH_FINALLY(igraph_destroy, &newgraph); igraph_vector_destroy(&edges); IGRAPH_I_ATTRIBUTE_DESTROY(&newgraph); IGRAPH_I_ATTRIBUTE_COPY(&newgraph, graph, 1,1,0); /* no edge attributes */ IGRAPH_FINALLY_CLEAN(2); igraph_destroy(graph); *graph=newgraph; } return 0; }
int igraph_to_directed(igraph_t *graph, igraph_to_directed_t mode) { if (mode != IGRAPH_TO_DIRECTED_ARBITRARY && mode != IGRAPH_TO_DIRECTED_MUTUAL) { IGRAPH_ERROR("Cannot directed graph, invalid mode", IGRAPH_EINVAL); } if (igraph_is_directed(graph)) { return 0; } if (mode==IGRAPH_TO_DIRECTED_ARBITRARY) { igraph_t newgraph; igraph_vector_t edges; long int no_of_edges=igraph_ecount(graph); long int no_of_nodes=igraph_vcount(graph); long int size=no_of_edges*2; IGRAPH_VECTOR_INIT_FINALLY(&edges, size); IGRAPH_CHECK(igraph_get_edgelist(graph, &edges, 0)); IGRAPH_CHECK(igraph_create(&newgraph, &edges, no_of_nodes, IGRAPH_DIRECTED)); IGRAPH_FINALLY(igraph_destroy, &newgraph); igraph_vector_destroy(&edges); IGRAPH_I_ATTRIBUTE_DESTROY(&newgraph); IGRAPH_I_ATTRIBUTE_COPY(&newgraph, graph, 1,1,1); IGRAPH_FINALLY_CLEAN(2); igraph_destroy(graph); *graph=newgraph; } else if (mode==IGRAPH_TO_DIRECTED_MUTUAL) { igraph_t newgraph; igraph_vector_t edges; igraph_vector_t index; long int no_of_edges=igraph_ecount(graph); long int no_of_nodes=igraph_vcount(graph); long int size=no_of_edges*4; long int i; IGRAPH_VECTOR_INIT_FINALLY(&edges, 0); IGRAPH_CHECK(igraph_vector_reserve(&edges, size)); IGRAPH_CHECK(igraph_get_edgelist(graph, &edges, 0)); IGRAPH_CHECK(igraph_vector_resize(&edges, no_of_edges*4)); IGRAPH_VECTOR_INIT_FINALLY(&index, no_of_edges*2); for (i=0; i<no_of_edges; i++) { VECTOR(edges)[no_of_edges*2+i*2] =VECTOR(edges)[i*2+1]; VECTOR(edges)[no_of_edges*2+i*2+1]=VECTOR(edges)[i*2]; VECTOR(index)[i] = VECTOR(index)[no_of_edges+i] = i+1; } IGRAPH_CHECK(igraph_create(&newgraph, &edges, no_of_nodes, IGRAPH_DIRECTED)); IGRAPH_FINALLY(igraph_destroy, &newgraph); IGRAPH_I_ATTRIBUTE_DESTROY(&newgraph); IGRAPH_I_ATTRIBUTE_COPY(&newgraph, graph, 1,1,1); IGRAPH_CHECK(igraph_i_attribute_permute_edges(&newgraph, &index)); igraph_vector_destroy(&index); igraph_vector_destroy(&edges); igraph_destroy(graph); IGRAPH_FINALLY_CLEAN(3); *graph=newgraph; } return 0; }