int main() { igraph_t g; igraph_vector_t y; /* turn on attribute handling */ igraph_i_set_attribute_table(&igraph_cattribute_table); /* Create a graph, add some attributes and save it as a GraphML file */ igraph_famous(&g, "Petersen"); SETGAS(&g, "name", "Petersen's graph"); SETGAN(&g, "vertices", igraph_vcount(&g)); SETGAN(&g, "edges", igraph_ecount(&g)); igraph_vector_init_seq(&y, 1, igraph_vcount(&g)); SETVANV(&g, "id", &y); igraph_vector_destroy(&y); SETVAS(&g, "name", 0, "foo"); SETVAS(&g, "name", 1, "foobar"); igraph_vector_init_seq(&y, 1, igraph_ecount(&g)); SETEANV(&g, "id", &y); igraph_vector_destroy(&y); SETEAS(&g, "name", 0, "FOO"); SETEAS(&g, "name", 1, "FOOBAR"); igraph_write_graph_gml(&g, stdout, 0, ""); igraph_write_graph_graphml(&g, stdout); igraph_destroy(&g); 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_i_maximal_cliques(const igraph_t *graph, igraph_i_maximal_clique_func_t func, void* data) { int directed=igraph_is_directed(graph); long int i, j, k, l; igraph_integer_t no_of_nodes, nodes_to_check, nodes_done; igraph_integer_t best_cand = 0, best_cand_degree = 0, best_fini_cand_degree; igraph_adjlist_t adj_list; igraph_stack_ptr_t stack; igraph_i_maximal_cliques_stack_frame frame, *new_frame_ptr; igraph_vector_t clique, new_cand, new_fini, cn, best_cand_nbrs, best_fini_cand_nbrs; igraph_bool_t cont = 1; int assret; if (directed) IGRAPH_WARNING("directionality of edges is ignored for directed graphs"); no_of_nodes = igraph_vcount(graph); if (no_of_nodes == 0) return IGRAPH_SUCCESS; /* Construct an adjacency list representation */ IGRAPH_CHECK(igraph_adjlist_init(graph, &adj_list, IGRAPH_ALL)); IGRAPH_FINALLY(igraph_adjlist_destroy, &adj_list); IGRAPH_CHECK(igraph_adjlist_simplify(&adj_list)); igraph_adjlist_sort(&adj_list); /* Initialize stack */ IGRAPH_CHECK(igraph_stack_ptr_init(&stack, 0)); IGRAPH_FINALLY(igraph_i_maximal_cliques_stack_destroy, &stack); /* Create the initial (empty) clique */ IGRAPH_VECTOR_INIT_FINALLY(&clique, 0); /* Initialize new_cand, new_fini, cn, best_cand_nbrs and best_fini_cand_nbrs (will be used later) */ IGRAPH_VECTOR_INIT_FINALLY(&new_cand, 0); IGRAPH_VECTOR_INIT_FINALLY(&new_fini, 0); IGRAPH_VECTOR_INIT_FINALLY(&cn, 0); IGRAPH_VECTOR_INIT_FINALLY(&best_cand_nbrs, 0); IGRAPH_VECTOR_INIT_FINALLY(&best_fini_cand_nbrs, 0); /* Find the vertex with the highest degree */ best_cand = 0; best_cand_degree = igraph_vector_size(igraph_adjlist_get(&adj_list, 0)); for (i = 1; i < no_of_nodes; i++) { j = igraph_vector_size(igraph_adjlist_get(&adj_list, i)); if (j > best_cand_degree) { best_cand = i; best_cand_degree = j; } } /* Create the initial stack frame */ IGRAPH_CHECK(igraph_vector_init_seq(&frame.cand, 0, no_of_nodes-1)); IGRAPH_FINALLY(igraph_vector_destroy, &frame.cand); IGRAPH_CHECK(igraph_vector_init(&frame.fini, 0)); IGRAPH_FINALLY(igraph_vector_destroy, &frame.fini); IGRAPH_CHECK(igraph_vector_init(&frame.cand_filtered, 0)); IGRAPH_FINALLY(igraph_vector_destroy, &frame.cand_filtered); IGRAPH_CHECK(igraph_vector_difference_sorted(&frame.cand, igraph_adjlist_get(&adj_list, best_cand), &frame.cand_filtered)); IGRAPH_FINALLY_CLEAN(3); IGRAPH_FINALLY(igraph_i_maximal_cliques_stack_frame_destroy, &frame); /* TODO: frame.cand and frame.fini should be a set instead of a vector */ /* Main loop starts here */ nodes_to_check = igraph_vector_size(&frame.cand_filtered); nodes_done = 0; while (!igraph_vector_empty(&frame.cand_filtered) || !igraph_stack_ptr_empty(&stack)) { if (igraph_vector_empty(&frame.cand_filtered)) { /* No candidates left to check in this stack frame, pop out the previous stack frame */ igraph_i_maximal_cliques_stack_frame *newframe = igraph_stack_ptr_pop(&stack); igraph_i_maximal_cliques_stack_frame_destroy(&frame); frame = *newframe; free(newframe); if (igraph_stack_ptr_size(&stack) == 1) { /* We will be using the next candidate node in the next iteration, so we can increase * nodes_done by 1 */ nodes_done++; } /* For efficiency reasons, we only check for interruption and show progress here */ IGRAPH_PROGRESS("Maximal cliques: ", 100.0 * nodes_done / nodes_to_check, NULL); IGRAPH_ALLOW_INTERRUPTION(); igraph_vector_pop_back(&clique); continue; } /* Try the next node in the clique */ i = igraph_vector_pop_back(&frame.cand_filtered); IGRAPH_CHECK(igraph_vector_push_back(&clique, i)); /* Remove the node from the candidate list */ assret=igraph_vector_binsearch(&frame.cand, i, &j); assert(assret); igraph_vector_remove(&frame.cand, j); /* Add the node to the finished list */ assret = !igraph_vector_binsearch(&frame.fini, i, &j); assert(assret); IGRAPH_CHECK(igraph_vector_insert(&frame.fini, j, i)); /* Create new_cand and new_fini */ IGRAPH_CHECK(igraph_vector_intersect_sorted(&frame.cand, igraph_adjlist_get(&adj_list, i), &new_cand)); IGRAPH_CHECK(igraph_vector_intersect_sorted(&frame.fini, igraph_adjlist_get(&adj_list, i), &new_fini)); /* Do we have anything more to search? */ if (igraph_vector_empty(&new_cand)) { if (igraph_vector_empty(&new_fini)) { /* We have a maximal clique here */ IGRAPH_CHECK(func(&clique, data, &cont)); if (!cont) { /* The callback function requested to stop the search */ break; } } igraph_vector_pop_back(&clique); continue; } if (igraph_vector_empty(&new_fini) && igraph_vector_size(&new_cand) == 1) { /* Shortcut: only one node left */ IGRAPH_CHECK(igraph_vector_push_back(&clique, VECTOR(new_cand)[0])); IGRAPH_CHECK(func(&clique, data, &cont)); if (!cont) { /* The callback function requested to stop the search */ break; } igraph_vector_pop_back(&clique); igraph_vector_pop_back(&clique); continue; } /* Find the next best candidate node in new_fini */ l = igraph_vector_size(&new_cand); best_cand_degree = -1; j = igraph_vector_size(&new_fini); for (i = 0; i < j; i++) { k = (long int)VECTOR(new_fini)[i]; IGRAPH_CHECK(igraph_vector_intersect_sorted(&new_cand, igraph_adjlist_get(&adj_list, k), &cn)); if (igraph_vector_size(&cn) > best_cand_degree) { best_cand_degree = igraph_vector_size(&cn); IGRAPH_CHECK(igraph_vector_update(&best_fini_cand_nbrs, &cn)); if (best_cand_degree == l) { /* Cool, we surely have the best candidate node here as best_cand_degree can't get any better */ break; } } } /* Shortcut here: we don't have to examine new_cand */ if (best_cand_degree == l) { igraph_vector_pop_back(&clique); continue; } /* Still finding best candidate node */ best_fini_cand_degree = best_cand_degree; best_cand_degree = -1; j = igraph_vector_size(&new_cand); l = l - 1; for (i = 0; i < j; i++) { k = (long int)VECTOR(new_cand)[i]; IGRAPH_CHECK(igraph_vector_intersect_sorted(&new_cand, igraph_adjlist_get(&adj_list, k), &cn)); if (igraph_vector_size(&cn) > best_cand_degree) { best_cand_degree = igraph_vector_size(&cn); IGRAPH_CHECK(igraph_vector_update(&best_cand_nbrs, &cn)); if (best_cand_degree == l) { /* Cool, we surely have the best candidate node here as best_cand_degree can't get any better */ break; } } } /* Create a new stack frame in case we back out later */ new_frame_ptr = igraph_Calloc(1, igraph_i_maximal_cliques_stack_frame); if (new_frame_ptr == 0) { IGRAPH_ERROR("cannot allocate new stack frame", IGRAPH_ENOMEM); } IGRAPH_FINALLY(igraph_free, new_frame_ptr); *new_frame_ptr = frame; memset(&frame, 0, sizeof(frame)); IGRAPH_CHECK(igraph_stack_ptr_push(&stack, new_frame_ptr)); IGRAPH_FINALLY_CLEAN(1); /* ownership of new_frame_ptr taken by the stack */ /* Ownership of the current frame and its vectors (frame.cand, frame.done, frame.cand_filtered) * is taken by the stack from now on. Vectors in frame must be re-initialized with new_cand, * new_fini and stuff. The old frame.cand and frame.fini won't be leaked because they are * managed by the stack now. */ frame.cand = new_cand; frame.fini = new_fini; IGRAPH_CHECK(igraph_vector_init(&new_cand, 0)); IGRAPH_CHECK(igraph_vector_init(&new_fini, 0)); IGRAPH_CHECK(igraph_vector_init(&frame.cand_filtered, 0)); /* Adjust frame.cand_filtered */ if (best_cand_degree < best_fini_cand_degree) { IGRAPH_CHECK(igraph_vector_difference_sorted(&frame.cand, &best_fini_cand_nbrs, &frame.cand_filtered)); } else { IGRAPH_CHECK(igraph_vector_difference_sorted(&frame.cand, &best_cand_nbrs, &frame.cand_filtered)); } } IGRAPH_PROGRESS("Maximal cliques: ", 100.0, NULL); igraph_adjlist_destroy(&adj_list); igraph_vector_destroy(&clique); igraph_vector_destroy(&new_cand); igraph_vector_destroy(&new_fini); igraph_vector_destroy(&cn); igraph_vector_destroy(&best_cand_nbrs); igraph_vector_destroy(&best_fini_cand_nbrs); igraph_i_maximal_cliques_stack_frame_destroy(&frame); igraph_i_maximal_cliques_stack_destroy(&stack); IGRAPH_FINALLY_CLEAN(9); return IGRAPH_SUCCESS; }
igraph_vector_t * ggen_analyze_longest_antichain(igraph_t *g) { /* The following steps are implemented : * - Convert our DAG to a specific bipartite graph B * - solve maximum matching on B * - conver maximum matching to min vectex cover * - convert min vertex cover to antichain on G */ int err; unsigned long i,vg,found,added; igraph_t b,gstar; igraph_vector_t edges,*res = NULL; igraph_vector_t c,s,t,todo,n,next,l,r; igraph_eit_t eit; igraph_es_t es; igraph_integer_t from,to; igraph_vit_t vit; igraph_vs_t vs; igraph_real_t value; if(g == NULL) return NULL; /* before creating the bipartite graph, we need all relations * between any two vertices : the transitive closure of g */ err = igraph_copy(&gstar,g); if(err) return NULL; err = ggen_transform_transitive_closure(&gstar); if(err) goto error; /* Bipartite convertion : let G = (S,C), * we build B = (U,V,E) with * - U = V = S (each vertex is present twice) * - (u,v) \in E iff : * - u \in U * - v \in V * - u < v in C (warning, this means that we take * transitive closure into account, not just the * original edges) * We will also need two additional nodes further in the code. */ vg = igraph_vcount(g); err = igraph_empty(&b,vg*2,1); if(err) goto error; /* id and id+vg will be a vertex in U and its copy in V, * iterate over gstar edges to create edges in b */ err = igraph_vector_init(&edges,igraph_ecount(&gstar)); if(err) goto d_b; igraph_vector_clear(&edges); err = igraph_eit_create(&gstar,igraph_ess_all(IGRAPH_EDGEORDER_ID),&eit); if(err) goto d_edges; for(IGRAPH_EIT_RESET(eit); !IGRAPH_EIT_END(eit); IGRAPH_EIT_NEXT(eit)) { err = igraph_edge(&gstar,IGRAPH_EIT_GET(eit),&from,&to); if(err) { igraph_eit_destroy(&eit); goto d_edges; } to += vg; igraph_vector_push_back(&edges,(igraph_real_t)from); igraph_vector_push_back(&edges,(igraph_real_t)to); } igraph_eit_destroy(&eit); err = igraph_add_edges(&b,&edges,NULL); if(err) goto d_edges; /* maximum matching on b */ igraph_vector_clear(&edges); err = bipartite_maximum_matching(&b,&edges); if(err) goto d_edges; /* Let M be the max matching, and N be E - M * Define T as all unmatched vectices from U as well as all vertices * reachable from those by going left-to-right along N and right-to-left along * M. * Define L = U - T, R = V \inter T * C:= L + R * C is a minimum vertex cover */ err = igraph_vector_init_seq(&n,0,igraph_ecount(&b)-1); if(err) goto d_edges; err = vector_diff(&n,&edges); if(err) goto d_n; err = igraph_vector_init(&c,vg); if(err) goto d_n; igraph_vector_clear(&c); /* matched vertices : S */ err = igraph_vector_init(&s,vg); if(err) goto d_c; igraph_vector_clear(&s); for(i = 0; i < igraph_vector_size(&edges); i++) { err = igraph_edge(&b,VECTOR(edges)[i],&from,&to); if(err) goto d_s; igraph_vector_push_back(&s,from); } /* we may have inserted the same vertex multiple times */ err = vector_uniq(&s); if(err) goto d_s; /* unmatched */ err = igraph_vector_init_seq(&t,0,vg-1); if(err) goto d_s; err = vector_diff(&t,&s); if(err) goto d_t; /* alternating paths */ err = igraph_vector_copy(&todo,&t); if(err) goto d_t; err = igraph_vector_init(&next,vg); if(err) goto d_todo; igraph_vector_clear(&next); do { vector_uniq(&todo); added = 0; for(i = 0; i < igraph_vector_size(&todo); i++) { if(VECTOR(todo)[i] < vg) { /* scan edges */ err = igraph_es_adj(&es,VECTOR(todo)[i],IGRAPH_OUT); if(err) goto d_next; err = igraph_eit_create(&b,es,&eit); if(err) { igraph_es_destroy(&es); goto d_next; } for(IGRAPH_EIT_RESET(eit); !IGRAPH_EIT_END(eit); IGRAPH_EIT_NEXT(eit)) { if(igraph_vector_binsearch(&n,IGRAPH_EIT_GET(eit),NULL)) { err = igraph_edge(&b,IGRAPH_EIT_GET(eit),&from,&to); if(err) { igraph_eit_destroy(&eit); igraph_es_destroy(&es); goto d_next; } if(!igraph_vector_binsearch(&t,to,NULL)) { igraph_vector_push_back(&next,to); added = 1; } } } } else { /* scan edges */ err = igraph_es_adj(&es,VECTOR(todo)[i],IGRAPH_IN); if(err) goto d_next; err = igraph_eit_create(&b,es,&eit); if(err) { igraph_es_destroy(&es); goto d_next; } for(IGRAPH_EIT_RESET(eit); !IGRAPH_EIT_END(eit); IGRAPH_EIT_NEXT(eit)) { if(igraph_vector_binsearch(&edges,IGRAPH_EIT_GET(eit),NULL)) { err = igraph_edge(&b,IGRAPH_EIT_GET(eit),&from,&to); if(err) { igraph_eit_destroy(&eit); igraph_es_destroy(&es); goto d_next; } if(!igraph_vector_binsearch(&t,to,NULL)) { igraph_vector_push_back(&next,from); added = 1; } } } } igraph_es_destroy(&es); igraph_eit_destroy(&eit); } igraph_vector_append(&t,&todo); igraph_vector_clear(&todo); igraph_vector_append(&todo,&next); igraph_vector_clear(&next); } while(added); err = igraph_vector_init_seq(&l,0,vg-1); if(err) goto d_t; err = vector_diff(&l,&t); if(err) goto d_l; err = igraph_vector_update(&c,&l); if(err) goto d_l; err = igraph_vector_init(&r,vg); if(err) goto d_l; igraph_vector_clear(&r); /* compute V \inter T */ for(i = 0; i < igraph_vector_size(&t); i++) { if(VECTOR(t)[i] >= vg) igraph_vector_push_back(&r,VECTOR(t)[i]); } igraph_vector_add_constant(&r,(igraph_real_t)-vg); err = vector_union(&c,&r); if(err) goto d_r; /* our antichain is U - C */ res = malloc(sizeof(igraph_vector_t)); if(res == NULL) goto d_r; err = igraph_vector_init_seq(res,0,vg-1); if(err) goto f_res; err = vector_diff(res,&c); if(err) goto d_res; goto ret; d_res: igraph_vector_destroy(res); f_res: free(res); res = NULL; ret: d_r: igraph_vector_destroy(&r); d_l: igraph_vector_destroy(&l); d_next: igraph_vector_destroy(&next); d_todo: igraph_vector_destroy(&todo); d_t: igraph_vector_destroy(&t); d_s: igraph_vector_destroy(&s); d_c: igraph_vector_destroy(&c); d_n: igraph_vector_destroy(&n); d_edges: igraph_vector_destroy(&edges); d_b: igraph_destroy(&b); error: igraph_destroy(&gstar); return res; }
int igraph_dijkstra_shortest_paths(const igraph_t *graph, igraph_matrix_t *res, const igraph_vs_t from, const igraph_vector_t *wghts, igraph_neimode_t mode) { long int no_of_nodes=igraph_vcount(graph); long int no_of_from; igraph_real_t *shortest; igraph_real_t min,alt; int i, j, uj, included; igraph_integer_t eid, u,v; igraph_vector_t q; igraph_vit_t fromvit; igraph_vector_t neis; IGRAPH_CHECK(igraph_vit_create(graph, from, &fromvit)); IGRAPH_FINALLY(igraph_vit_destroy, &fromvit); no_of_from=IGRAPH_VIT_SIZE(fromvit); if (mode != IGRAPH_OUT && mode != IGRAPH_IN && mode != IGRAPH_ALL) { IGRAPH_ERROR("Invalid mode argument", IGRAPH_EINVMODE); } shortest=calloc(no_of_nodes, sizeof(igraph_real_t)); if (shortest==0) { IGRAPH_ERROR("shortest paths failed", IGRAPH_ENOMEM); } IGRAPH_FINALLY(free, shortest); IGRAPH_CHECK(igraph_matrix_resize(res, no_of_from, no_of_nodes)); igraph_matrix_null(res); for (IGRAPH_VIT_RESET(fromvit), i=0; !IGRAPH_VIT_END(fromvit); IGRAPH_VIT_NEXT(fromvit), i++) { //Start shortest and previous for(j=0;j<no_of_nodes;j++){ shortest[j] = INFINITY; //memset(previous,NAN, no_of_nodes); } shortest[(int)IGRAPH_VIT_GET(fromvit)] = 0; igraph_vector_init_seq(&q,0,no_of_nodes-1); while(igraph_vector_size(&q) != 0){ min = INFINITY; u = no_of_nodes; uj = igraph_vector_size(&q); for(j=0;j<igraph_vector_size(&q);j++){ v = VECTOR(q)[j]; if(shortest[(int)v] < min){ min = shortest[(int)v]; u = v; uj = j; } } if(min == INFINITY) break; igraph_vector_remove(&q,uj); igraph_vector_init(&neis,0); igraph_neighbors(graph,&neis,u,mode); for(j=0;j<igraph_vector_size(&neis);j++){ v = VECTOR(neis)[j]; //v must be in Q included = 0; for(j=0;j<igraph_vector_size(&q);j++){ if(v == VECTOR(q)[j]){ included = 1; break; } } if(!included) continue; igraph_get_eid(graph,&eid,u,v,1); alt = shortest[(int)u] + VECTOR(*wghts)[(int)eid]; if(alt < shortest[(int)v]){ shortest[(int)v] = alt; } } igraph_vector_destroy(&neis); } for(j=0;j<no_of_nodes;j++){ MATRIX(*res,i,j) = shortest[j]; } igraph_vector_destroy(&q); } /* Clean */ free(shortest); igraph_vit_destroy(&fromvit); IGRAPH_FINALLY_CLEAN(2); return 0; }
/* Random Orders Method : */ igraph_t * ggen_generate_random_orders(gsl_rng *r, unsigned long n, unsigned int orders) { igraph_t *g = NULL; igraph_matrix_t m,edge_validity; int err = 0; long long i = 0,j,k; igraph_vector_ptr_t posets; igraph_vector_ptr_t indexes; igraph_vector_t *v,*w; ggen_error_start_stack(); if(r == NULL) GGEN_SET_ERRNO(GGEN_EINVAL); if(orders == 0) GGEN_SET_ERRNO(GGEN_EINVAL); // init structures g = malloc(sizeof(igraph_t)); GGEN_CHECK_ALLOC(g); GGEN_FINALLY3(free,g,1); GGEN_CHECK_IGRAPH(igraph_matrix_init(&m,n,n)); GGEN_FINALLY(igraph_matrix_destroy,&m); GGEN_CHECK_IGRAPH(igraph_matrix_init(&edge_validity,n,n)); GGEN_FINALLY(igraph_matrix_destroy,&edge_validity); GGEN_CHECK_IGRAPH(igraph_vector_ptr_init(&posets,orders)); IGRAPH_VECTOR_PTR_SET_ITEM_DESTRUCTOR(&posets,igraph_vector_destroy); GGEN_FINALLY(igraph_vector_ptr_destroy_all,&posets); GGEN_CHECK_IGRAPH(igraph_vector_ptr_init(&indexes,orders)); IGRAPH_VECTOR_PTR_SET_ITEM_DESTRUCTOR(&indexes,igraph_vector_destroy); GGEN_FINALLY(igraph_vector_ptr_destroy_all,&indexes); for(i = 0; i < orders; i++) { // posets is used for permutation computations // it should contain vertices VECTOR(posets)[i] = calloc(1,sizeof(igraph_vector_t)); GGEN_CHECK_ALLOC(VECTOR(posets)[i]); GGEN_CHECK_IGRAPH_VECTPTR(igraph_vector_init_seq(VECTOR(posets)[i],0,n-1),posets,i); VECTOR(indexes)[i] = calloc(1,sizeof(igraph_vector_t)); GGEN_CHECK_ALLOC(VECTOR(indexes)[i]); GGEN_CHECK_IGRAPH_VECTPTR(igraph_vector_init(VECTOR(indexes)[i],n),indexes,i); } // zero all structs igraph_matrix_null(&m); igraph_matrix_null(&edge_validity); // use gsl to shuffle each poset for( j = 0; j < orders; j++) { v = VECTOR(posets)[j]; GGEN_CHECK_GSL_DO(gsl_ran_shuffle(r,VECTOR(*v), n, sizeof(VECTOR(*v)[0]))); } // index saves the indices of each vertex in each permutation for( i = 0; i < orders; i++) for( j = 0; j < n; j++) { v = VECTOR(posets)[i]; w = VECTOR(indexes)[i]; k = VECTOR(*v)[j]; VECTOR(*w)[k] = j; } // edge_validity count if an edge is in all permutations for( i = 0; i < n; i++) for( j = 0; j < n; j++) for( k = 0; k < orders; k++) { v = VECTOR(indexes)[k]; if( VECTOR(*v)[i] < VECTOR(*v)[j]) igraph_matrix_set(&edge_validity,i,j, igraph_matrix_e(&edge_validity,i,j)+1); } // if an edge is present in all permutations then add it to the graph for( i = 0; i < n; i++) for( j = 0; j < n; j++) if(igraph_matrix_e(&edge_validity,i,j) == orders) igraph_matrix_set(&m,i,j,1); // translate the matrix to a graph GGEN_CHECK_IGRAPH(igraph_adjacency(g,&m,IGRAPH_ADJ_DIRECTED)); ggen_error_clean(1); return g; ggen_error_label: return NULL; }
int main() { igraph_t g, g2; FILE *ifile; igraph_vector_t gtypes, vtypes, etypes; igraph_strvector_t gnames, vnames, enames; long int i; igraph_vector_t y; igraph_strvector_t id; char str[20]; /* turn on attribute handling */ igraph_i_set_attribute_table(&igraph_cattribute_table); ifile=fopen("LINKS.NET", "r"); if (ifile==0) { return 10; } igraph_read_graph_pajek(&g, ifile); fclose(ifile); igraph_vector_init(>ypes, 0); igraph_vector_init(&vtypes, 0); igraph_vector_init(&etypes, 0); igraph_strvector_init(&gnames, 0); igraph_strvector_init(&vnames, 0); igraph_strvector_init(&enames, 0); igraph_cattribute_list(&g, &gnames, >ypes, &vnames, &vtypes, &enames, &etypes); /* List attribute names and types */ printf("Graph attributes: "); for (i=0; i<igraph_strvector_size(&gnames); i++) { printf("%s (%i) ", STR(gnames, i), (int)VECTOR(gtypes)[i]); } printf("\n"); printf("Vertex attributes: "); for (i=0; i<igraph_strvector_size(&vnames); i++) { printf("%s (%i) ", STR(vnames, i), (int)VECTOR(vtypes)[i]); } printf("\n"); printf("Edge attributes: "); for (i=0; i<igraph_strvector_size(&enames); i++) { printf("%s (%i) ", STR(enames, i), (int)VECTOR(etypes)[i]); } printf("\n"); print_attributes(&g); /* Copying a graph */ igraph_copy(&g2, &g); print_attributes(&g2); igraph_destroy(&g2); /* Adding vertices */ igraph_add_vertices(&g, 3, 0); print_attributes(&g); /* Adding edges */ igraph_add_edge(&g, 1, 1); igraph_add_edge(&g, 2, 5); igraph_add_edge(&g, 3, 6); print_attributes(&g); /* Deleting vertices */ igraph_delete_vertices(&g, igraph_vss_1(1)); igraph_delete_vertices(&g, igraph_vss_1(4)); print_attributes(&g); /* Deleting edges */ igraph_delete_edges(&g, igraph_ess_1(igraph_ecount(&g)-1)); igraph_delete_edges(&g, igraph_ess_1(0)); print_attributes(&g); /* Set graph attributes */ SETGAN(&g, "id", 10); if (GAN(&g, "id") != 10) { return 11; } SETGAS(&g, "name", "toy"); if (strcmp(GAS(&g, "name"), "toy")) { return 12; } /* Delete graph attributes */ DELGA(&g, "id"); DELGA(&g, "name"); igraph_cattribute_list(&g, &gnames, 0,0,0,0,0); if (igraph_strvector_size(&gnames) != 0) { return 14; } /* Delete vertex attributes */ DELVA(&g, "x"); DELVA(&g, "shape"); DELVA(&g, "xfact"); DELVA(&g, "yfact"); igraph_cattribute_list(&g, 0,0, &vnames, 0,0,0); if (igraph_strvector_size(&vnames) != 2) { return 15; } /* Delete edge attributes */ igraph_cattribute_list(&g, 0,0,0,0,&enames,0); i=igraph_strvector_size(&enames); DELEA(&g, "hook1"); DELEA(&g, "hook2"); DELEA(&g, "label"); igraph_cattribute_list(&g, 0,0,0,0,&enames,0); if (igraph_strvector_size(&enames) != i-3) { return 16; } /* Set vertex attributes */ SETVAN(&g, "y", 0, -1); SETVAN(&g, "y", 1, 2.1); if (VAN(&g, "y", 0) != -1 || VAN(&g, "y", 1) != 2.1) { return 17; } SETVAS(&g, "id", 0, "foo"); SETVAS(&g, "id", 1, "bar"); if (strcmp(VAS(&g, "id", 0), "foo") || strcmp(VAS(&g, "id", 1), "bar")) { return 18; } /* Set edge attributes */ SETEAN(&g, "weight", 2, 100.0); SETEAN(&g, "weight", 0, -100.1); if (EAN(&g, "weight", 2) != 100.0 || EAN(&g, "weight", 0) != -100.1) { return 19; } SETEAS(&g, "color", 2, "RED"); SETEAS(&g, "color", 0, "Blue"); if (strcmp(EAS(&g, "color", 2), "RED") || strcmp(EAS(&g, "color", 0), "Blue")) { return 20; } /* Set vector attributes as vector */ igraph_vector_init(&y, igraph_vcount(&g)); igraph_vector_fill(&y, 1.23); SETVANV(&g, "y", &y); igraph_vector_destroy(&y); for (i=0; i<igraph_vcount(&g); i++) { if (VAN(&g, "y", i) != 1.23) { return 21; } } igraph_vector_init_seq(&y, 0, igraph_vcount(&g)-1); SETVANV(&g, "foobar", &y); igraph_vector_destroy(&y); for (i=0; i<igraph_vcount(&g); i++) { if (VAN(&g, "foobar", i) != i) { return 22; } } igraph_strvector_init(&id, igraph_vcount(&g)); for (i=0; i<igraph_vcount(&g); i++) { snprintf(str, sizeof(str)-1, "%li", i); igraph_strvector_set(&id, i, str); } SETVASV(&g, "foo", &id); igraph_strvector_destroy(&id); for (i=0; i<igraph_vcount(&g); i++) { printf("%s ", VAS(&g, "foo", i)); } printf("\n"); igraph_strvector_init(&id, igraph_vcount(&g)); for (i=0; i<igraph_vcount(&g); i++) { snprintf(str, sizeof(str)-1, "%li", i); igraph_strvector_set(&id, i, str); } SETVASV(&g, "id", &id); igraph_strvector_destroy(&id); for (i=0; i<igraph_vcount(&g); i++) { printf("%s ", VAS(&g, "id", i)); } printf("\n"); /* Set edge attributes as vector */ igraph_vector_init(&y, igraph_ecount(&g)); igraph_vector_fill(&y, 12.3); SETEANV(&g, "weight", &y); igraph_vector_destroy(&y); for (i=0; i<igraph_ecount(&g); i++) { if (EAN(&g, "weight", i) != 12.3) { return 23; } } igraph_vector_init_seq(&y, 0, igraph_ecount(&g)-1); SETEANV(&g, "foobar", &y); igraph_vector_destroy(&y); for (i=0; i<igraph_ecount(&g); i++) { if (VAN(&g, "foobar", i) != i) { return 24; } } igraph_strvector_init(&id, igraph_ecount(&g)); for (i=0; i<igraph_ecount(&g); i++) { snprintf(str, sizeof(str)-1, "%li", i); igraph_strvector_set(&id, i, str); } SETEASV(&g, "foo", &id); igraph_strvector_destroy(&id); for (i=0; i<igraph_ecount(&g); i++) { printf("%s ", EAS(&g, "foo", i)); } printf("\n"); igraph_strvector_init(&id, igraph_ecount(&g)); for (i=0; i<igraph_ecount(&g); i++) { snprintf(str, sizeof(str)-1, "%li", i); igraph_strvector_set(&id, i, str); } SETEASV(&g, "color", &id); igraph_strvector_destroy(&id); for (i=0; i<igraph_ecount(&g); i++) { printf("%s ", EAS(&g, "color", i)); } printf("\n"); /* Delete all remaining attributes */ DELALL(&g); igraph_cattribute_list(&g, &gnames, >ypes, &vnames, &vtypes, &enames, &etypes); if (igraph_strvector_size(&gnames) != 0 || igraph_strvector_size(&vnames) != 0 || igraph_strvector_size(&enames) != 0) { return 25; } /* Destroy */ igraph_vector_destroy(>ypes); igraph_vector_destroy(&vtypes); igraph_vector_destroy(&etypes); igraph_strvector_destroy(&gnames); igraph_strvector_destroy(&vnames); igraph_strvector_destroy(&enames); igraph_destroy(&g); return 0; }
int main() { igraph_t g, g2, cli; igraph_vector_t perm; igraph_vector_ptr_t cliques; igraph_integer_t no; int i; igraph_rng_seed(igraph_rng_default(), 42); /* Create a graph that has a random component, plus a number of relatively small cliques */ igraph_vector_init_seq(&perm, 0, NODES-1); igraph_erdos_renyi_game(&g, IGRAPH_ERDOS_RENYI_GNM, NODES, NODES, /*directed=*/ 0, /*loops=*/ 0, igraph_rng_default()); igraph_full(&cli, CLIQUE_SIZE, /*directed=*/ 0, /*loops=*/ 0); for (i=0; i<NO_CLIQUES; i++) { /* Permute vertices of g */ permutation(&perm); igraph_permute_vertices(&g, &g2, &perm); igraph_destroy(&g); g=g2; /* Add a clique */ igraph_union(&g2, &g, &cli, /*edge_map1=*/ 0, /*edge_map2=*/ 0); igraph_destroy(&g); g=g2; } igraph_simplify(&g, /*multiple=*/ 1, /*loop=*/ 0, /*edge_comb=*/ 0); igraph_vector_destroy(&perm); igraph_destroy(&cli); /* Find the maximal cliques */ igraph_vector_ptr_init(&cliques, 0); igraph_maximal_cliques(&g, &cliques, /*min_size=*/ 3, /*max_size=*/ 0 /*no limit*/); igraph_maximal_cliques_count(&g, &no, /*min_size=*/ 3, /*max_size=*/ 0 /*no limit*/); if (no != igraph_vector_ptr_size(&cliques)) { return 1; } /* Print and destroy them */ print_and_destroy_cliques(&cliques); /* Clean up */ igraph_vector_ptr_destroy(&cliques); igraph_destroy(&g); /* Build a triangle with a loop (thanks to Emmanuel Navarro) */ igraph_small(&g, 3, IGRAPH_UNDIRECTED, 0, 1, 1, 2, 2, 0, 0, 0, -1); /* Find the maximal cliques */ igraph_vector_ptr_init(&cliques, 0); igraph_maximal_cliques(&g, &cliques, /*min_size=*/ 3, /*max_size=*/ 0 /*no limit*/); igraph_maximal_cliques_count(&g, &no, /*min_size=*/ 3, /*max_size=*/ 0 /*no limit*/); if (no != igraph_vector_ptr_size(&cliques)) { return 2; } /* Print and destroy them */ print_and_destroy_cliques(&cliques); /* Clean up */ igraph_vector_ptr_destroy(&cliques); igraph_destroy(&g); return 0; }
int main() { igraph_t g, g2; igraph_vector_t weight; igraph_attribute_combination_t comb; igraph_i_set_attribute_table(&igraph_cattribute_table); igraph_small(&g, 4, IGRAPH_DIRECTED, 0, 1, 0, 1, 0, 1, 1, 2, 2, 3, -1); igraph_vector_init_seq(&weight, 1, igraph_ecount(&g)); SETEANV(&g, "weight", &weight); igraph_vector_destroy(&weight); /* ****************************************************** */ igraph_copy(&g2, &g); igraph_attribute_combination(&comb, "weight", IGRAPH_ATTRIBUTE_COMBINE_SUM, "", IGRAPH_ATTRIBUTE_COMBINE_IGNORE, IGRAPH_NO_MORE_ATTRIBUTES); igraph_simplify(&g2, /*multiple=*/ 1, /*loops=*/ 1, &comb); igraph_attribute_combination_destroy(&comb); igraph_write_graph_graphml(&g2, stdout); igraph_destroy(&g2); /* ****************************************************** */ /* ****************************************************** */ igraph_copy(&g2, &g); igraph_attribute_combination(&comb, "weight", IGRAPH_ATTRIBUTE_COMBINE_PROD, "", IGRAPH_ATTRIBUTE_COMBINE_IGNORE, IGRAPH_NO_MORE_ATTRIBUTES); igraph_simplify(&g2, /*multiple=*/ 1, /*loops=*/ 1, &comb); igraph_attribute_combination_destroy(&comb); igraph_write_graph_graphml(&g2, stdout); igraph_destroy(&g2); /* ****************************************************** */ /* ****************************************************** */ igraph_copy(&g2, &g); igraph_attribute_combination(&comb, "weight", IGRAPH_ATTRIBUTE_COMBINE_MIN, "", IGRAPH_ATTRIBUTE_COMBINE_IGNORE, IGRAPH_NO_MORE_ATTRIBUTES); igraph_simplify(&g2, /*multiple=*/ 1, /*loops=*/ 1, &comb); igraph_attribute_combination_destroy(&comb); igraph_write_graph_graphml(&g2, stdout); igraph_destroy(&g2); /* ****************************************************** */ /* ****************************************************** */ igraph_copy(&g2, &g); igraph_attribute_combination(&comb, "weight", IGRAPH_ATTRIBUTE_COMBINE_MAX, "", IGRAPH_ATTRIBUTE_COMBINE_IGNORE, IGRAPH_NO_MORE_ATTRIBUTES); igraph_simplify(&g2, /*multiple=*/ 1, /*loops=*/ 1, &comb); igraph_attribute_combination_destroy(&comb); igraph_write_graph_graphml(&g2, stdout); igraph_destroy(&g2); /* ****************************************************** */ /* ****************************************************** */ igraph_copy(&g2, &g); igraph_attribute_combination(&comb, "weight", IGRAPH_ATTRIBUTE_COMBINE_FIRST, "", IGRAPH_ATTRIBUTE_COMBINE_IGNORE, IGRAPH_NO_MORE_ATTRIBUTES); igraph_simplify(&g2, /*multiple=*/ 1, /*loops=*/ 1, &comb); igraph_attribute_combination_destroy(&comb); igraph_write_graph_graphml(&g2, stdout); igraph_destroy(&g2); /* ****************************************************** */ /* ****************************************************** */ igraph_copy(&g2, &g); igraph_attribute_combination(&comb, "weight", IGRAPH_ATTRIBUTE_COMBINE_LAST, "", IGRAPH_ATTRIBUTE_COMBINE_IGNORE, IGRAPH_NO_MORE_ATTRIBUTES); igraph_simplify(&g2, /*multiple=*/ 1, /*loops=*/ 1, &comb); igraph_attribute_combination_destroy(&comb); igraph_write_graph_graphml(&g2, stdout); igraph_destroy(&g2); /* ****************************************************** */ /* ****************************************************** */ igraph_copy(&g2, &g); igraph_attribute_combination(&comb, "weight", IGRAPH_ATTRIBUTE_COMBINE_MEAN, "", IGRAPH_ATTRIBUTE_COMBINE_IGNORE, IGRAPH_NO_MORE_ATTRIBUTES); igraph_simplify(&g2, /*multiple=*/ 1, /*loops=*/ 1, &comb); igraph_attribute_combination_destroy(&comb); igraph_write_graph_graphml(&g2, stdout); igraph_destroy(&g2); /* ****************************************************** */ /* ****************************************************** */ igraph_copy(&g2, &g); igraph_attribute_combination(&comb, "weight", IGRAPH_ATTRIBUTE_COMBINE_FUNCTION, mf, "", IGRAPH_ATTRIBUTE_COMBINE_IGNORE, IGRAPH_NO_MORE_ATTRIBUTES); igraph_simplify(&g2, /*multiple=*/ 1, /*loops=*/ 1, &comb); igraph_attribute_combination_destroy(&comb); igraph_write_graph_graphml(&g2, stdout); igraph_destroy(&g2); /* ****************************************************** */ /* ****************************************************** */ igraph_copy(&g2, &g); igraph_attribute_combination(&comb, "", IGRAPH_ATTRIBUTE_COMBINE_MEAN, IGRAPH_NO_MORE_ATTRIBUTES); igraph_simplify(&g2, /*multiple=*/ 1, /*loops=*/ 1, &comb); igraph_attribute_combination_destroy(&comb); igraph_write_graph_graphml(&g2, stdout); igraph_destroy(&g2); /* ****************************************************** */ igraph_destroy(&g); return 0; }
void test_bliss() { igraph_t ring1, ring2, directed_ring; igraph_vector_t perm; igraph_bool_t iso; igraph_bliss_info_t info; igraph_vector_int_t color; igraph_vector_ptr_t generators; igraph_ring(&ring1, 100, /*directed=*/ 0, /*mutual=*/ 0, /*circular=*/1); igraph_vector_init_seq(&perm, 0, igraph_vcount(&ring1)-1); random_permutation(&perm); igraph_permute_vertices(&ring1, &ring2, &perm); igraph_ring(&directed_ring, 100, /* directed= */ 1, /* mutual = */0, /* circular = */1); igraph_vector_ptr_init(&generators, 0); IGRAPH_VECTOR_PTR_SET_ITEM_DESTRUCTOR(&generators, igraph_vector_destroy); igraph_isomorphic_bliss(&ring1, &ring2, NULL, NULL, &iso, NULL, NULL, IGRAPH_BLISS_F, NULL, NULL); if (! iso) printf("Bliss failed on ring isomorphism.\n"); igraph_automorphisms(&ring1, NULL, IGRAPH_BLISS_F, &info); if (strcmp(info.group_size, "200") != 0) printf("Biss automorphism count failed: ring1.\n"); igraph_free(info.group_size); igraph_automorphisms(&ring2, NULL, IGRAPH_BLISS_F, &info); if (strcmp(info.group_size, "200") != 0) printf("Biss automorphism count failed: ring2.\n"); igraph_free(info.group_size); igraph_automorphisms(&directed_ring, NULL, IGRAPH_BLISS_F, &info); if (strcmp(info.group_size, "100") != 0) printf("Biss automorphism count failed: directed_ring.\n"); igraph_free(info.group_size); // The follwing test is included so there is at least one call to igraph_automorphism_group // in the test suite. However, the generator set returned may depend on the splitting // heursitics as well as on the Bliss version. If the test fails, please verify manually // that the generating set is valid. For a undirected cycle graph like ring2, there should // be two generators: a cyclic permutation and a reversal of the vertex order. igraph_automorphism_group(&ring2, NULL, &generators, IGRAPH_BLISS_F, NULL); if (igraph_vector_ptr_size(&generators) != 2) printf("Bliss automorphism generators may have failed with ring2. " "Please verify the generators manually. " "Note that the generator set is not guaranteed to be minimal.\n"); igraph_vector_ptr_free_all(&generators); // For a directed ring, the only generator should be a cyclic permutation. igraph_automorphism_group(&directed_ring, NULL, &generators, IGRAPH_BLISS_F, NULL); if (igraph_vector_ptr_size(&generators) != 1) printf("Bliss automorphism generators may have failed with directed_ring. " "Please verify the generators manually. " "Note that the generator set is not guaranteed to be minimal.\n"); igraph_vector_ptr_free_all(&generators); igraph_vector_int_init_seq(&color, 0, igraph_vcount(&ring1)-1); igraph_automorphisms(&ring1, &color, IGRAPH_BLISS_F, &info); if (strcmp(info.group_size, "1") != 0) printf("Biss automorphism count with color failed: ring1.\n"); igraph_free(info.group_size); // There's only one automorphism for this coloured graph, so the generating set is empty. igraph_automorphism_group(&ring1, &color, &generators, IGRAPH_BLISS_F, NULL); if (igraph_vector_ptr_size(&generators) != 0) printf("Bliss automorphism generators failed with colored graph.\n"); igraph_vector_ptr_destroy_all(&generators); igraph_vector_int_destroy(&color); igraph_vector_destroy(&perm); igraph_destroy(&ring1); igraph_destroy(&ring2); igraph_destroy(&directed_ring); }