int igraph_get_edgelist(const igraph_t *graph, igraph_vector_t *res, igraph_bool_t bycol) { igraph_eit_t edgeit; long int no_of_edges=igraph_ecount(graph); long int vptr=0; igraph_integer_t from, to; IGRAPH_CHECK(igraph_vector_resize(res, no_of_edges*2)); IGRAPH_CHECK(igraph_eit_create(graph, igraph_ess_all(IGRAPH_EDGEORDER_ID), &edgeit)); IGRAPH_FINALLY(igraph_eit_destroy, &edgeit); if (bycol) { while (!IGRAPH_EIT_END(edgeit)) { igraph_edge(graph, IGRAPH_EIT_GET(edgeit), &from, &to); VECTOR(*res)[vptr]=from; VECTOR(*res)[vptr+no_of_edges]=to; vptr++; IGRAPH_EIT_NEXT(edgeit); } } else { while (!IGRAPH_EIT_END(edgeit)) { igraph_edge(graph, IGRAPH_EIT_GET(edgeit), &from, &to); VECTOR(*res)[vptr++]=from; VECTOR(*res)[vptr++]=to; IGRAPH_EIT_NEXT(edgeit); } } igraph_eit_destroy(&edgeit); IGRAPH_FINALLY_CLEAN(1); return 0; }
/* Shrinks communities into single vertices, keeping all the edges. * This method is internal because it destroys the graph in-place and * creates a new one -- this is fine for the multilevel community * detection where a copy of the original graph is used anyway. * The membership vector will also be rewritten by the underlying * igraph_membership_reindex call */ int igraph_i_multilevel_shrink(igraph_t *graph, igraph_vector_t *membership) { igraph_vector_t edges; long int no_of_nodes = igraph_vcount(graph); long int no_of_edges = igraph_ecount(graph); igraph_bool_t directed = igraph_is_directed(graph); long int i; igraph_eit_t eit; if (no_of_nodes == 0) return 0; if (igraph_vector_size(membership) < no_of_nodes) { IGRAPH_ERROR("cannot shrink graph, membership vector too short", IGRAPH_EINVAL); } IGRAPH_VECTOR_INIT_FINALLY(&edges, no_of_edges * 2); IGRAPH_CHECK(igraph_reindex_membership(membership, 0)); /* Create the new edgelist */ igraph_eit_create(graph, igraph_ess_all(IGRAPH_EDGEORDER_ID), &eit); IGRAPH_FINALLY(igraph_eit_destroy, &eit); i = 0; while (!IGRAPH_EIT_END(eit)) { igraph_integer_t from, to; IGRAPH_CHECK(igraph_edge(graph, IGRAPH_EIT_GET(eit), &from, &to)); VECTOR(edges)[i++] = VECTOR(*membership)[(long int) from]; VECTOR(edges)[i++] = VECTOR(*membership)[(long int) to]; IGRAPH_EIT_NEXT(eit); } igraph_eit_destroy(&eit); IGRAPH_FINALLY_CLEAN(1); /* Create the new graph */ igraph_destroy(graph); no_of_nodes = (long int) igraph_vector_max(membership)+1; IGRAPH_CHECK(igraph_create(graph, &edges, (igraph_integer_t) no_of_nodes, directed)); igraph_vector_destroy(&edges); IGRAPH_FINALLY_CLEAN(1); return 0; }
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 ggen_write_graph(igraph_t *g, FILE *output) { Agraph_t *cg; Agnode_t *f,*t; Agedge_t *edge; igraph_vector_ptr_t vertices; igraph_eit_t eit; int err; unsigned long i,j; unsigned long vcount = igraph_vcount(g); igraph_integer_t from,to; char name[GGEN_DEFAULT_NAME_SIZE]; char *str = NULL; igraph_strvector_t gnames,vnames,enames; igraph_vector_t gtypes,vtypes,etypes; Agsym_t *attr; /* see warning below */ igraph_error_handler_t *error_handler; err = igraph_vector_ptr_init(&vertices,vcount); if(err) return 1; /* WARNING: this should be changed if igraph-0.6 gets * stable. * We need to ignore some igraph_cattribute errors * because we try to retrieve special attributes (ggen specifics). * igraph version 0.6 include a cattribute_has_attr that should be * used instead of ignoring errors. */ error_handler = igraph_set_error_handler(igraph_error_handler_ignore); /* open graph * its name is saved in __ggen_graph_name if it exists */ str =(char *) GAS(g,GGEN_GRAPH_NAME_ATTR); if(!str) cg = agopen(GGEN_DEFAULT_GRAPH_NAME,Agdirected,NULL); else cg = agopen(str,Agdirected,NULL); if(!cg) { err = 1; goto d_v; } /* save a pointer to each vertex */ for(i = 0; i < vcount; i++) { /* find a vertex name */ str = vid2vname_unsafe(name,g,i); if(!str) f = agnode(cg,name,1); else f = agnode(cg,str,1); VECTOR(vertices)[i] = (void *)f; } /* We have finished with dangerous attributes accesses */ igraph_set_error_handler(error_handler); /* now loop through edges in the igraph */ err = igraph_eit_create(g,igraph_ess_all(IGRAPH_EDGEORDER_ID),&eit); if(err) goto c_ag; for(IGRAPH_EIT_RESET(eit); !IGRAPH_EIT_END(eit); IGRAPH_EIT_NEXT(eit)) { err = igraph_edge(g,IGRAPH_EIT_GET(eit),&from,&to); if(err) goto d_eit; f = (Agnode_t *) VECTOR(vertices)[(unsigned long)from]; t = (Agnode_t *) VECTOR(vertices)[(unsigned long)to]; agedge(cg,f,t,NULL,1); } /* find all properties */ igraph_strvector_init(&gnames,1); igraph_strvector_init(&vnames,vcount); igraph_strvector_init(&enames,igraph_ecount(g)); igraph_vector_init(>ypes,1); igraph_vector_init(&vtypes,vcount); igraph_vector_init(&etypes,igraph_ecount(g)); err = igraph_cattribute_list(g,&gnames,>ypes,&vnames,&vtypes,&enames,&etypes); if(err) goto d_eit; /* add graph properties */ for(i = 0; i < igraph_strvector_size(&gnames); i++) { if(strcmp(GGEN_GRAPH_NAME_ATTR,STR(gnames,i))) { if(VECTOR(gtypes)[i]==IGRAPH_ATTRIBUTE_NUMERIC) { snprintf(name,GGEN_DEFAULT_NAME_SIZE,"%f", (double)GAN(g,STR(gnames,i))); agattr(cg,AGRAPH,(char *)STR(gnames,i),name); } else agattr(cg,AGRAPH,(char *)STR(gnames,i), (char *)GAS(g,STR(gnames,i))); } } /* add vertex properties */ for(i = 0; i < igraph_strvector_size(&vnames); i++) { if(strcmp(GGEN_VERTEX_NAME_ATTR,STR(vnames,i))) { /* creates the attribute but we still need to set it for each vertex */ attr = agattr(cg,AGNODE,(char *)STR(vnames,i),GGEN_CGRAPH_DEFAULT_VALUE); for(j = 0; j < vcount; j++) { f = (Agnode_t *) VECTOR(vertices)[j]; if(VECTOR(vtypes)[i]==IGRAPH_ATTRIBUTE_NUMERIC) { snprintf(name,GGEN_DEFAULT_NAME_SIZE,"%f", (double)VAN(g,STR(vnames,i),j)); agxset(f,attr,name); } else agxset(f,attr,(char *)VAS(g,STR(vnames,i),j)); } } } /* add edges properties */ for(i = 0; i < igraph_strvector_size(&enames); i++) { /* creates the attribute but we still need to set it for each edge */ attr = agattr(cg,AGEDGE,(char *)STR(enames,i),GGEN_CGRAPH_DEFAULT_VALUE); for(j = 0; j < igraph_ecount(g); j++) { igraph_edge(g,j,&from,&to); f = (Agnode_t *) VECTOR(vertices)[(unsigned long)from]; t = (Agnode_t *) VECTOR(vertices)[(unsigned long)to]; edge = agedge(cg,f,t,NULL,0); if(VECTOR(etypes)[i]==IGRAPH_ATTRIBUTE_NUMERIC) { snprintf(name,GGEN_DEFAULT_NAME_SIZE,"%f", (double)EAN(g,STR(enames,i),j)); agxset(edge,attr,name); } else agxset(edge,attr,(char *)EAS(g,STR(enames,i),j)); } } /* write the graph */ err = agwrite(cg,(void *)output); d_eit: igraph_eit_destroy(&eit); c_ag: agclose(cg); d_v: igraph_vector_ptr_destroy(&vertices); return err; }
static GError* _tgengraph_parseGraphEdges(TGenGraph* g) { TGEN_ASSERT(g); tgen_debug("checking graph edges..."); /* we will iterate through the edges */ igraph_eit_t edgeIterator; gint result = igraph_eit_create(g->graph, igraph_ess_all(IGRAPH_EDGEORDER_ID), &edgeIterator); if(result != IGRAPH_SUCCESS) { return g_error_new(G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, "igraph_eit_create return non-success code %i", result); } /* count the edges as we iterate */ igraph_integer_t edgeCount = 0; GError* error = NULL; while (!IGRAPH_EIT_END(edgeIterator)) { igraph_integer_t edgeIndex = IGRAPH_EIT_GET(edgeIterator); igraph_integer_t fromVertexIndex, toVertexIndex; gint result = igraph_edge(g->graph, edgeIndex, &fromVertexIndex, &toVertexIndex); if(result != IGRAPH_SUCCESS) { error = g_error_new(G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, "igraph_edge return non-success code %i", result); break; } const gchar* fromIDStr = (g->knownAttributes&TGEN_VA_ID) ? VAS(g->graph, "id", fromVertexIndex) : NULL; if(!fromIDStr) { error = g_error_new(G_MARKUP_ERROR, G_MARKUP_ERROR_MISSING_ATTRIBUTE, "found vertex %li with missing 'id' attribute", (glong)fromVertexIndex); break; } const gchar* toIDStr = (g->knownAttributes&TGEN_VA_ID) ? VAS(g->graph, "id", toVertexIndex) : NULL; if(!toIDStr) { error = g_error_new(G_MARKUP_ERROR, G_MARKUP_ERROR_MISSING_ATTRIBUTE, "found vertex %li with missing 'id' attribute", (glong)toVertexIndex); break; } tgen_debug("found edge %li from vertex %li (%s) to vertex %li (%s)", (glong)edgeIndex, (glong)fromVertexIndex, fromIDStr, (glong)toVertexIndex, toIDStr); const gchar* weightStr = (g->knownAttributes&TGEN_EA_WEIGHT) ? EAS(g->graph, "weight", edgeIndex) : NULL; if(weightStr != NULL) { if(g_ascii_strncasecmp(weightStr, "\0", (gsize) 1)) { gdouble weight = g_ascii_strtod(weightStr, NULL); _tgengraph_storeWeight(g, weight, edgeIndex); } } edgeCount++; IGRAPH_EIT_NEXT(edgeIterator); } igraph_eit_destroy(&edgeIterator); if(!error) { g->edgeCount = igraph_ecount(g->graph); if(g->edgeCount != edgeCount) { tgen_warning("igraph_vcount %f does not match iterator count %f", g->edgeCount, edgeCount); } tgen_info("%u graph edges ok", (guint) g->edgeCount); } return error; }
/* Vertex selector constructors */ EdgeSelector EdgeSelector::All(EdgeOrder order) { static EdgeSelector instance( igraph_ess_all(static_cast<igraph_edgeorder_type_t>(order))); return instance; }
int TEgraphMF::readTopology(const char *file_name) { int ret = 0; Bitvector* lid; Bitvector* ilid; ifstream infile; string str; size_t found, first, second; FILE *instream; infile.open(file_name, ifstream::in); /*first the Global graph attributes - c igraph does not do it!!*/ while (infile.good()) { getline(infile, str); found = str.find("<data key=\"FID_LEN\">"); if (found != string::npos) { first = str.find(">"); second = str.find("<", first); sscanf(str.substr(first + 1, second - first - 1).c_str(), "%d", &fid_len); } found = str.find("<data key=\"TM\">"); if (found != string::npos) { first = str.find(">"); second = str.find("<", first); nodeID = str.substr(first + 1, second - first - 1); } found = str.find("<data key=\"RV\">"); if (found != string::npos) { first = str.find(">"); second = str.find("<", first); RVnodeID = str.substr(first + 1, second - first - 1); } found = str.find("<data key=\"TM_MODE\">"); if (found != string::npos) { first = str.find(">"); second = str.find("<", first); mode = str.substr(first + 1, second - first - 1); } } infile.close(); instream = fopen(file_name, "r"); if (instream == NULL) { return -1; } //EF_ALLOW_MALLOC_0=1; ret = igraph_read_graph_graphml(&graph, instream, 0); //EF_ALLOW_MALLOC_0=0; fclose(instream); if (ret < 0) { return ret; } //cout << "TM: " << igraph_vcount(&graph) << " nodes" << endl; //cout << "TM: " << igraph_ecount(&graph) << " edges" << endl; for (int i = 0; i < igraph_vcount(&graph); i++) { string nID = string(igraph_cattribute_VAS(&graph, "NODEID", i)); string iLID = string(igraph_cattribute_VAS(&graph, "iLID", i)); reverse_node_index.insert(pair<string, int>(nID, i)); ilid = new Bitvector(iLID); nodeID_iLID.insert(pair<string, Bitvector* >(nID, ilid)); vertex_iLID.insert(pair<int, Bitvector* >(i, ilid)); cout<<"node "<<i<<" has NODEID"<<nID<<endl; cout<<"node "<<i<<" has ILID"<<ilid->to_string()<<endl; } for (int i = 0; i < igraph_ecount(&graph); i++) { string LID = string(igraph_cattribute_EAS(&graph, "LID", i)); reverse_edge_index.insert(pair<string, int>(LID, i)); lid = new Bitvector(LID); edge_LID.insert(pair<int, Bitvector* >(i, lid)); igraph_integer_t head; igraph_integer_t tail; igraph_edge(&graph, i,&head,&tail); cout << "edge " << i <<" "<<head<<"->"<<tail<<" has LID " << lid->to_string() << endl; } std::vector<int> edgepairs; std::vector<double> capacities; igraph_eit_t ieit; igraph_eit_create(&graph,igraph_ess_all(IGRAPH_EDGEORDER_ID),&ieit); while(!IGRAPH_EIT_END(ieit)) { igraph_integer_t edgeid = IGRAPH_EIT_GET(ieit); igraph_integer_t head; igraph_integer_t tail; // WARNING all edge capacities are give the same value // this needs to come from deployment script capacities.push_back(defaultBW); igraph_edge(&graph, edgeid,&head,&tail); cout<<"edge"<<head<<"->"<<tail<<endl; edgepairs.push_back(head); edgepairs.push_back(tail); IGRAPH_EIT_NEXT(ieit); } igraph_eit_destroy(&ieit); // create an initial dmand matrix assuming equal traffic // between all node pairs - unlikely to be correct but // as booststrap we do not know any better // THIS WILL NEED TO BE DYNAMICALLY UPDATED LATER for (int i = 0; i < igraph_vcount(&graph); i++) { for (int j = 0; j < igraph_vcount(&graph); j++) { if( i == j) continue; mf_demand demand; demand.source = i; demand.sink = j; // WARNING HARDCODED VALUE, ok for initial boostrap // as it is all relative. It should be obtained from // the deployment script as an initial demand. demand.demand = 1.0; demandMapMeasured.insert(pair<intpair,mf_demand>(intpair(i,j), demand)); } } graphMF = Graph_mf((int)igraph_vcount(&graph),edgepairs,capacities); // now demands are set to half the maximum flow when // using shortest paths assuming equal flow between // all pairs - enough for boostrapping // initial demand matrix done! //update_paths(); preCalculateFids(); return ret; }
/** * \function igraph_community_fastgreedy * \brief Finding community structure by greedy optimization of modularity * * This function implements the fast greedy modularity optimization * algorithm for finding community structure, see * A Clauset, MEJ Newman, C Moore: Finding community structure in very * large networks, http://www.arxiv.org/abs/cond-mat/0408187 for the * details. * * </para><para> * Some improvements proposed in K Wakita, T Tsurumi: Finding community * structure in mega-scale social networks, * http://www.arxiv.org/abs/cs.CY/0702048v1 have also been implemented. * * \param graph The input graph. It must be a simple graph, i.e. a graph * without multiple and without loop edges. This is checked and an * error message is given for non-simple graphs. * \param weights Potentially a numeric vector containing edge * weights. Supply a null pointer here for unweighted graphs. The * weights are expected to be non-negative. * \param merges Pointer to an initialized matrix or NULL, the result of the * computation is stored here. The matrix has two columns and each * merge corresponds to one merge, the ids of the two merged * components are stored. The component ids are numbered from zero and * the first \c n components are the individual vertices, \c n is * the number of vertices in the graph. Component \c n is created * in the first merge, component \c n+1 in the second merge, etc. * The matrix will be resized as needed. If this argument is NULL * then it is ignored completely. * \param modularity Pointer to an initialized matrix or NULL pointer, * in the former case the modularity scores along the stages of the * computation are recorded here. The vector will be resized as * needed. * \return Error code. * * \sa \ref igraph_community_walktrap(), \ref * igraph_community_edge_betweenness() for other community detection * algorithms, \ref igraph_community_to_membership() to convert the * dendrogram to a membership vector. * * Time complexity: O(|E||V|log|V|) in the worst case, * O(|E|+|V|log^2|V|) typically, |V| is the number of vertices, |E| is * the number of edges. */ int igraph_community_fastgreedy(const igraph_t *graph, const igraph_vector_t *weights, igraph_matrix_t *merges, igraph_vector_t *modularity) { long int no_of_edges, no_of_nodes, no_of_joins, total_joins; long int i, j, k, n, m, from, to, dummy; igraph_integer_t ffrom, fto; igraph_eit_t edgeit; igraph_i_fastgreedy_commpair *pairs, *p1, *p2; igraph_i_fastgreedy_community_list communities; igraph_vector_t a; igraph_real_t q, maxq, *dq, weight_sum; igraph_bool_t simple; /*long int join_order[] = { 16,5, 5,6, 6,0, 4,0, 10,0, 26,29, 29,33, 23,33, 27,33, 25,24, 24,31, 12,3, 21,1, 30,8, 8,32, 9,2, 17,1, 11,0, 7,3, 3,2, 13,2, 1,2, 28,31, 31,33, 22,32, 18,32, 20,32, 32,33, 15,33, 14,33, 0,19, 19,2, -1,-1 };*/ /*long int join_order[] = { 43,42, 42,41, 44,41, 41,36, 35,36, 37,36, 36,29, 38,29, 34,29, 39,29, 33,29, 40,29, 32,29, 14,29, 30,29, 31,29, 6,18, 18,4, 23,4, 21,4, 19,4, 27,4, 20,4, 22,4, 26,4, 25,4, 24,4, 17,4, 0,13, 13,2, 1,2, 11,2, 8,2, 5,2, 3,2, 10,2, 9,2, 7,2, 2,28, 28,15, 12,15, 29,16, 4,15, -1,-1 };*/ no_of_nodes = igraph_vcount(graph); no_of_edges = igraph_ecount(graph); if (igraph_is_directed(graph)) { IGRAPH_ERROR("fast greedy community detection works for undirected graphs only", IGRAPH_UNIMPLEMENTED); } total_joins=no_of_nodes-1; if (weights != 0) { if (igraph_vector_size(weights) < igraph_ecount(graph)) IGRAPH_ERROR("fast greedy community detection: weight vector too short", IGRAPH_EINVAL); if (igraph_vector_any_smaller(weights, 0)) IGRAPH_ERROR("weights must be positive", IGRAPH_EINVAL); weight_sum = igraph_vector_sum(weights); } else weight_sum = no_of_edges; IGRAPH_CHECK(igraph_is_simple(graph, &simple)); if (!simple) { IGRAPH_ERROR("fast-greedy community finding works only on simple graphs", IGRAPH_EINVAL); } if (merges != 0) { IGRAPH_CHECK(igraph_matrix_resize(merges, total_joins, 2)); igraph_matrix_null(merges); } if (modularity != 0) { IGRAPH_CHECK(igraph_vector_resize(modularity, total_joins+1)); } /* Create degree vector */ IGRAPH_VECTOR_INIT_FINALLY(&a, no_of_nodes); if (weights) { debug("Calculating weighted degrees\n"); for (i=0; i < no_of_edges; i++) { VECTOR(a)[(long int)IGRAPH_FROM(graph, i)] += VECTOR(*weights)[i]; VECTOR(a)[(long int)IGRAPH_TO(graph, i)] += VECTOR(*weights)[i]; } } else { debug("Calculating degrees\n"); IGRAPH_CHECK(igraph_degree(graph, &a, igraph_vss_all(), IGRAPH_ALL, 0)); } /* Create list of communities */ debug("Creating community list\n"); communities.n = no_of_nodes; communities.no_of_communities = no_of_nodes; communities.e = (igraph_i_fastgreedy_community*)calloc(no_of_nodes, sizeof(igraph_i_fastgreedy_community)); if (communities.e == 0) { IGRAPH_ERROR("can't run fast greedy community detection", IGRAPH_ENOMEM); } IGRAPH_FINALLY(free, communities.e); communities.heap = (igraph_i_fastgreedy_community**)calloc(no_of_nodes, sizeof(igraph_i_fastgreedy_community*)); if (communities.heap == 0) { IGRAPH_ERROR("can't run fast greedy community detection", IGRAPH_ENOMEM); } IGRAPH_FINALLY(free, communities.heap); communities.heapindex = (igraph_integer_t*)calloc(no_of_nodes, sizeof(igraph_integer_t)); if (communities.heapindex == 0) { IGRAPH_ERROR("can't run fast greedy community detection", IGRAPH_ENOMEM); } IGRAPH_FINALLY_CLEAN(2); IGRAPH_FINALLY(igraph_i_fastgreedy_community_list_destroy, &communities); for (i=0; i<no_of_nodes; i++) { igraph_vector_ptr_init(&communities.e[i].neis, 0); communities.e[i].id = i; communities.e[i].size = 1; } /* Create list of community pairs from edges */ debug("Allocating dq vector\n"); dq = (igraph_real_t*)calloc(no_of_edges, sizeof(igraph_real_t)); if (dq == 0) { IGRAPH_ERROR("can't run fast greedy community detection", IGRAPH_ENOMEM); } IGRAPH_FINALLY(free, dq); debug("Creating community pair list\n"); IGRAPH_CHECK(igraph_eit_create(graph, igraph_ess_all(0), &edgeit)); IGRAPH_FINALLY(igraph_eit_destroy, &edgeit); pairs = (igraph_i_fastgreedy_commpair*)calloc(2*no_of_edges, sizeof(igraph_i_fastgreedy_commpair)); if (pairs == 0) { IGRAPH_ERROR("can't run fast greedy community detection", IGRAPH_ENOMEM); } IGRAPH_FINALLY(free, pairs); i=j=0; while (!IGRAPH_EIT_END(edgeit)) { long int eidx = IGRAPH_EIT_GET(edgeit); igraph_edge(graph, eidx, &ffrom, &fto); /* Create the pairs themselves */ from = (long int)ffrom; to = (long int)fto; if (from == to) { IGRAPH_ERROR("loop edge detected, simplify the graph before starting community detection", IGRAPH_EINVAL); } if (from>to) { dummy=from; from=to; to=dummy; } if (weights) { dq[j]=2*(VECTOR(*weights)[eidx]/(weight_sum*2.0) - VECTOR(a)[from]*VECTOR(a)[to]/(4.0*weight_sum*weight_sum)); } else { dq[j]=2*(1.0/(no_of_edges*2.0) - VECTOR(a)[from]*VECTOR(a)[to]/(4.0*no_of_edges*no_of_edges)); } pairs[i].first = from; pairs[i].second = to; pairs[i].dq = &dq[j]; pairs[i].opposite = &pairs[i+1]; pairs[i+1].first = to; pairs[i+1].second = from; pairs[i+1].dq = pairs[i].dq; pairs[i+1].opposite = &pairs[i]; /* Link the pair to the communities */ igraph_vector_ptr_push_back(&communities.e[from].neis, &pairs[i]); igraph_vector_ptr_push_back(&communities.e[to].neis, &pairs[i+1]); /* Update maximums */ if (communities.e[from].maxdq==0 || *communities.e[from].maxdq->dq < *pairs[i].dq) communities.e[from].maxdq = &pairs[i]; if (communities.e[to].maxdq==0 || *communities.e[to].maxdq->dq < *pairs[i+1].dq) communities.e[to].maxdq = &pairs[i+1]; /* Iterate */ i+=2; j++; IGRAPH_EIT_NEXT(edgeit); } igraph_eit_destroy(&edgeit); IGRAPH_FINALLY_CLEAN(1); /* Sorting community neighbor lists by community IDs */ debug("Sorting community neighbor lists\n"); for (i=0, j=0; i<no_of_nodes; i++) { igraph_vector_ptr_sort(&communities.e[i].neis, igraph_i_fastgreedy_commpair_cmp); /* Isolated vertices won't be stored in the heap (to avoid maxdq == 0) */ if (VECTOR(a)[i] > 0) { communities.heap[j] = &communities.e[i]; communities.heapindex[i] = j; j++; } else { communities.heapindex[i] = -1; } } communities.no_of_communities = j; /* Calculate proper vector a (see paper) and initial modularity */ q=0; igraph_vector_scale(&a, 1.0/(2.0 * (weights ? weight_sum : no_of_edges))); for (i=0; i<no_of_nodes; i++) q -= VECTOR(a)[i]*VECTOR(a)[i]; maxq=q; /* Initializing community heap */ debug("Initializing community heap\n"); igraph_i_fastgreedy_community_list_build_heap(&communities); debug("Initial modularity: %.4f\n", q); /* Let's rock ;) */ no_of_joins=0; while (no_of_joins<total_joins) { IGRAPH_ALLOW_INTERRUPTION(); IGRAPH_PROGRESS("fast greedy community detection", no_of_joins*100.0/total_joins, 0); /* Store the modularity */ if (modularity) VECTOR(*modularity)[no_of_joins] = q; /* Some debug info if needed */ /* igraph_i_fastgreedy_community_list_check_heap(&communities); */ #ifdef DEBUG debug("===========================================\n"); for (i=0; i<communities.n; i++) { if (communities.e[i].maxdq == 0) { debug("Community #%ld: PASSIVE\n", i); continue; } debug("Community #%ld\n ", i); for (j=0; j<igraph_vector_ptr_size(&communities.e[i].neis); j++) { p1=(igraph_i_fastgreedy_commpair*)VECTOR(communities.e[i].neis)[j]; debug(" (%ld,%ld,%.4f)", p1->first, p1->second, *p1->dq); } p1=communities.e[i].maxdq; debug("\n Maxdq: (%ld,%ld,%.4f)\n", p1->first, p1->second, *p1->dq); } debug("Global maxdq is: (%ld,%ld,%.4f)\n", communities.heap[0]->maxdq->first, communities.heap[0]->maxdq->second, *communities.heap[0]->maxdq->dq); for (i=0; i<communities.no_of_communities; i++) debug("(%ld,%ld,%.4f) ", communities.heap[i]->maxdq->first, communities.heap[i]->maxdq->second, *communities.heap[0]->maxdq->dq); debug("\n"); #endif if (communities.heap[0] == 0) break; /* no more communities */ if (communities.heap[0]->maxdq == 0) break; /* there are only isolated comms */ to=communities.heap[0]->maxdq->second; from=communities.heap[0]->maxdq->first; debug("Q[%ld] = %.7f\tdQ = %.7f\t |H| = %ld\n", no_of_joins, q, *communities.heap[0]->maxdq->dq, no_of_nodes-no_of_joins-1); /* DEBUG */ /* from=join_order[no_of_joins*2]; to=join_order[no_of_joins*2+1]; if (to == -1) break; for (i=0; i<igraph_vector_ptr_size(&communities.e[to].neis); i++) { p1=(igraph_i_fastgreedy_commpair*)VECTOR(communities.e[to].neis)[i]; if (p1->second == from) communities.maxdq = p1; } */ n = igraph_vector_ptr_size(&communities.e[to].neis); m = igraph_vector_ptr_size(&communities.e[from].neis); /*if (n>m) { dummy=n; n=m; m=dummy; dummy=to; to=from; from=dummy; }*/ debug(" joining: %ld <- %ld\n", to, from); q += *communities.heap[0]->maxdq->dq; /* Merge the second community into the first */ i = j = 0; while (i<n && j<m) { p1 = (igraph_i_fastgreedy_commpair*)VECTOR(communities.e[to].neis)[i]; p2 = (igraph_i_fastgreedy_commpair*)VECTOR(communities.e[from].neis)[j]; debug("Pairs: %ld-%ld and %ld-%ld\n", p1->first, p1->second, p2->first, p2->second); if (p1->second < p2->second) { /* Considering p1 from now on */ debug(" Considering: %ld-%ld\n", p1->first, p1->second); if (p1->second == from) { debug(" WILL REMOVE: %ld-%ld\n", to, from); } else { /* chain, case 1 */ debug(" CHAIN(1): %ld-%ld %ld, now=%.7f, adding=%.7f, newdq(%ld,%ld)=%.7f\n", to, p1->second, from, *p1->dq, -2*VECTOR(a)[from]*VECTOR(a)[p1->second], p1->first, p1->second, *p1->dq-2*VECTOR(a)[from]*VECTOR(a)[p1->second]); igraph_i_fastgreedy_community_update_dq(&communities, p1, *p1->dq - 2*VECTOR(a)[from]*VECTOR(a)[p1->second]); } i++; } else if (p1->second == p2->second) { /* p1->first, p1->second and p2->first form a triangle */ debug(" Considering: %ld-%ld and %ld-%ld\n", p1->first, p1->second, p2->first, p2->second); /* Update dq value */ debug(" TRIANGLE: %ld-%ld-%ld, now=%.7f, adding=%.7f, newdq(%ld,%ld)=%.7f\n", to, p1->second, from, *p1->dq, *p2->dq, p1->first, p1->second, *p1->dq+*p2->dq); igraph_i_fastgreedy_community_update_dq(&communities, p1, *p1->dq + *p2->dq); igraph_i_fastgreedy_community_remove_nei(&communities, p1->second, from); i++; j++; } else { debug(" Considering: %ld-%ld\n", p2->first, p2->second); if (p2->second == to) { debug(" WILL REMOVE: %ld-%ld\n", p2->second, p2->first); } else { /* chain, case 2 */ debug(" CHAIN(2): %ld %ld-%ld, newdq(%ld,%ld)=%.7f\n", to, p2->second, from, to, p2->second, *p2->dq-2*VECTOR(a)[to]*VECTOR(a)[p2->second]); p2->opposite->second=to; /* need to re-sort community nei list `p2->second` */ /* TODO: quicksort is O(n*logn), although we could do a deletion and * insertion which can be done in O(logn) if deletion is O(1) */ debug(" Re-sorting community %ld\n", p2->second); igraph_vector_ptr_sort(&communities.e[p2->second].neis, igraph_i_fastgreedy_commpair_cmp); /* link from.neis[j] to the current place in to.neis if * from.neis[j] != to */ p2->first=to; IGRAPH_CHECK(igraph_vector_ptr_insert(&communities.e[to].neis,i,p2)); n++; i++; if (*p2->dq > *communities.e[to].maxdq->dq) { communities.e[to].maxdq = p2; k=igraph_i_fastgreedy_community_list_find_in_heap(&communities, to); igraph_i_fastgreedy_community_list_sift_up(&communities, k); } igraph_i_fastgreedy_community_update_dq(&communities, p2, *p2->dq - 2*VECTOR(a)[to]*VECTOR(a)[p2->second]); } j++; } } while (i<n) { p1 = (igraph_i_fastgreedy_commpair*)VECTOR(communities.e[to].neis)[i]; if (p1->second == from) { debug(" WILL REMOVE: %ld-%ld\n", p1->first, from); } else { /* chain, case 1 */ debug(" CHAIN(1): %ld-%ld %ld, now=%.7f, adding=%.7f, newdq(%ld,%ld)=%.7f\n", to, p1->second, from, *p1->dq, -2*VECTOR(a)[from]*VECTOR(a)[p1->second], p1->first, p1->second, *p1->dq-2*VECTOR(a)[from]*VECTOR(a)[p1->second]); igraph_i_fastgreedy_community_update_dq(&communities, p1, *p1->dq - 2*VECTOR(a)[from]*VECTOR(a)[p1->second]); } i++; } while (j<m) { p2 = (igraph_i_fastgreedy_commpair*)VECTOR(communities.e[from].neis)[j]; if (to == p2->second) { j++; continue; } /* chain, case 2 */ debug(" CHAIN(2): %ld %ld-%ld, newdq(%ld,%ld)=%.7f\n", to, p2->second, from, p1->first, p2->second, *p2->dq-2*VECTOR(a)[to]*VECTOR(a)[p2->second]); p2->opposite->second=to; /* need to re-sort community nei list `p2->second` */ /* TODO: quicksort is O(n*logn), although we could do a deletion and * insertion which can be done in O(logn) if deletion is O(1) */ debug(" Re-sorting community %ld\n", p2->second); igraph_vector_ptr_sort(&communities.e[p2->second].neis, igraph_i_fastgreedy_commpair_cmp); /* link from.neis[j] to the current place in to.neis if * from.neis[j] != to */ p2->first=to; IGRAPH_CHECK(igraph_vector_ptr_push_back(&communities.e[to].neis,p2)); if (*p2->dq > *communities.e[to].maxdq->dq) { communities.e[to].maxdq = p2; k=igraph_i_fastgreedy_community_list_find_in_heap(&communities, to); igraph_i_fastgreedy_community_list_sift_up(&communities, k); } igraph_i_fastgreedy_community_update_dq(&communities, p2, *p2->dq-2*VECTOR(a)[to]*VECTOR(a)[p2->second]); j++; } /* Now, remove community `from` from the neighbors of community `to` */ if (communities.no_of_communities > 2) { debug(" REMOVING: %ld-%ld\n", to, from); igraph_i_fastgreedy_community_remove_nei(&communities, to, from); i=igraph_i_fastgreedy_community_list_find_in_heap(&communities, from); igraph_i_fastgreedy_community_list_remove(&communities, i); } communities.e[from].maxdq=0; /* Update community sizes */ communities.e[to].size += communities.e[from].size; communities.e[from].size = 0; /* record what has been merged */ /* igraph_vector_ptr_clear is not enough here as it won't free * the memory consumed by communities.e[from].neis. Thanks * to Tom Gregorovic for pointing that out. */ igraph_vector_ptr_destroy(&communities.e[from].neis); if (merges) { MATRIX(*merges, no_of_joins, 0) = communities.e[to].id; MATRIX(*merges, no_of_joins, 1) = communities.e[from].id; communities.e[to].id = no_of_nodes+no_of_joins; } /* Update vector a */ VECTOR(a)[to] += VECTOR(a)[from]; VECTOR(a)[from] = 0.0; no_of_joins++; } /* TODO: continue merging when some isolated communities remained. Always * joining the communities with the least number of nodes results in the * smallest decrease in modularity every step. Now we're simply deleting * the excess rows from the merge matrix */ if (no_of_joins < total_joins) { long int *ivec; ivec=igraph_Calloc(igraph_matrix_nrow(merges), long int); if (ivec == 0) IGRAPH_ERROR("can't run fast greedy community detection", IGRAPH_ENOMEM); IGRAPH_FINALLY(free, ivec); for (i=0; i<no_of_joins; i++) ivec[i] = i+1; igraph_matrix_permdelete_rows(merges, ivec, total_joins-no_of_joins); free(ivec); IGRAPH_FINALLY_CLEAN(1); }
int igraph_get_adjacency(const igraph_t *graph, igraph_matrix_t *res, igraph_get_adjacency_t type) { igraph_eit_t edgeit; long int no_of_nodes=igraph_vcount(graph); igraph_bool_t directed=igraph_is_directed(graph); int retval=0; long int from, to; igraph_integer_t ffrom, fto; IGRAPH_CHECK(igraph_matrix_resize(res, no_of_nodes, no_of_nodes)); igraph_matrix_null(res); IGRAPH_CHECK(igraph_eit_create(graph, igraph_ess_all(0), &edgeit)); IGRAPH_FINALLY(igraph_eit_destroy, &edgeit); if (directed) { while (!IGRAPH_EIT_END(edgeit)) { igraph_edge(graph, IGRAPH_EIT_GET(edgeit), &ffrom, &fto); from=ffrom; to=fto; MATRIX(*res, from, to) += 1; IGRAPH_EIT_NEXT(edgeit); } } else if (type==IGRAPH_GET_ADJACENCY_UPPER) { while (!IGRAPH_EIT_END(edgeit)) { igraph_edge(graph, IGRAPH_EIT_GET(edgeit), &ffrom, &fto); from=ffrom; to=fto; if (to < from) { MATRIX(*res, to, from) += 1; } else { MATRIX(*res, from, to) += 1; } IGRAPH_EIT_NEXT(edgeit); } } else if (type==IGRAPH_GET_ADJACENCY_LOWER) { while (!IGRAPH_EIT_END(edgeit)) { igraph_edge(graph, IGRAPH_EIT_GET(edgeit), &ffrom, &fto); from=ffrom; to=fto; if (to < from) { MATRIX(*res, from, to) += 1; } else { MATRIX(*res, to, from) += 1; } IGRAPH_EIT_NEXT(edgeit); } } else if (type==IGRAPH_GET_ADJACENCY_BOTH) { while (!IGRAPH_EIT_END(edgeit)) { igraph_edge(graph, IGRAPH_EIT_GET(edgeit), &ffrom, &fto); from=ffrom; to=fto; MATRIX(*res, from, to) += 1; if (from != to) { MATRIX(*res, to, from) += 1; } IGRAPH_EIT_NEXT(edgeit); } } else { IGRAPH_ERROR("Invalid type argument", IGRAPH_EINVAL); } igraph_eit_destroy(&edgeit); IGRAPH_FINALLY_CLEAN(1); return retval; }
int print_attributes(const igraph_t *g) { igraph_vector_t gtypes, vtypes, etypes; igraph_strvector_t gnames, vnames, enames; long int i; igraph_vector_t vec; igraph_strvector_t svec; long int j; 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); /* Graph attributes */ for (i=0; i<igraph_strvector_size(&gnames); i++) { printf("%s=", STR(gnames, i)); if (VECTOR(gtypes)[i]==IGRAPH_ATTRIBUTE_NUMERIC) { igraph_real_printf(GAN(g, STR(gnames,i))); putchar(' '); } else { printf("\"%s\" ", GAS(g, STR(gnames,i))); } } printf("\n"); for (i=0; i<igraph_vcount(g); i++) { long int j; printf("Vertex %li: ", i); for (j=0; j<igraph_strvector_size(&vnames); j++) { printf("%s=", STR(vnames, j)); if (VECTOR(vtypes)[j]==IGRAPH_ATTRIBUTE_NUMERIC) { igraph_real_printf(VAN(g, STR(vnames,j), i)); putchar(' '); } else { printf("\"%s\" ", VAS(g, STR(vnames,j), i)); } } printf("\n"); } for (i=0; i<igraph_ecount(g); i++) { long int j; printf("Edge %li (%i-%i): ", i, (int)IGRAPH_FROM(g,i), (int)IGRAPH_TO(g,i)); for (j=0; j<igraph_strvector_size(&enames); j++) { printf("%s=", STR(enames, j)); if (VECTOR(etypes)[j]==IGRAPH_ATTRIBUTE_NUMERIC) { igraph_real_printf(EAN(g, STR(enames, j), i)); putchar(' '); } else { printf("\"%s\" ", EAS(g, STR(enames, j), i)); } } printf("\n"); } /* Check vector-based query functions */ igraph_vector_init(&vec, 0); igraph_strvector_init(&svec, 0); for (j=0; j<igraph_strvector_size(&vnames); j++) { if (VECTOR(vtypes)[j]==IGRAPH_ATTRIBUTE_NUMERIC) { igraph_cattribute_VANV(g, STR(vnames, j), igraph_vss_all(), &vec); for (i=0; i<igraph_vcount(g); i++) { igraph_real_t num=VAN(g, STR(vnames, j), i); if (num != VECTOR(vec)[i] && (!isnan(num) || !isnan(VECTOR(vec)[i]))) { exit(51); } } } else { igraph_cattribute_VASV(g, STR(vnames, j), igraph_vss_all(), &svec); for (i=0; i<igraph_vcount(g); i++) { const char *str=VAS(g, STR(vnames, j), i); if (strcmp(str,STR(svec, i))) { exit(52); } } } } for (j=0; j<igraph_strvector_size(&enames); j++) { if (VECTOR(etypes)[j]==IGRAPH_ATTRIBUTE_NUMERIC) { igraph_cattribute_EANV(g, STR(enames, j), igraph_ess_all(IGRAPH_EDGEORDER_ID), &vec); for (i=0; i<igraph_ecount(g); i++) { igraph_real_t num=EAN(g, STR(enames, j), i); if (num != VECTOR(vec)[i] && (!isnan(num) || !isnan(VECTOR(vec)[i]))) { exit(53); } } } else { igraph_cattribute_EASV(g, STR(enames, j), igraph_ess_all(IGRAPH_EDGEORDER_ID), &svec); for (i=0; i<igraph_ecount(g); i++) { const char *str=EAS(g, STR(enames, j), i); if (strcmp(str,STR(svec, i))) { exit(54); } } } } igraph_strvector_destroy(&svec); igraph_vector_destroy(&vec); igraph_strvector_destroy(&enames); igraph_strvector_destroy(&vnames); igraph_strvector_destroy(&gnames); igraph_vector_destroy(&etypes); igraph_vector_destroy(&vtypes); igraph_vector_destroy(>ypes); return 0; }
int main() { igraph_t g; igraph_vector_t tdist; igraph_matrix_t pmat; igraph_bool_t conn; igraph_vector_bool_t bs; int i, ret; /* Symmetric preference game */ igraph_vector_bool_init(&bs, 0); igraph_vector_init_real(&tdist, 3, 1.0, 1.0, 1.0); igraph_matrix_init(&pmat, 3, 3); for (i=0; i<3; i++) MATRIX(pmat, i, i) = 0.2; /* undirected, no loops */ IGRAPH_CHECK(igraph_preference_game(&g, 1000, 3, &tdist, /*fixed_sizes=*/ 0, &pmat, 0, 0, 0)); if (igraph_vcount(&g) != 1000) return 18; if (igraph_is_directed(&g)) return 2; igraph_is_connected(&g, &conn, IGRAPH_STRONG); if (conn) return 3; igraph_is_loop(&g, &bs, igraph_ess_all(IGRAPH_EDGEORDER_ID)); if (igraph_vector_bool_sum(&bs)) return 4; igraph_is_multiple(&g, &bs, igraph_ess_all(IGRAPH_EDGEORDER_ID)); if (igraph_vector_bool_sum(&bs)) return 5; igraph_destroy(&g); for (i=0; i<2; i++) MATRIX(pmat, i, i+1) = 0.1; /* directed, no loops */ IGRAPH_CHECK(igraph_preference_game(&g, 1000, 3, &tdist, /*fixed_sizes=*/0, &pmat, 0, 1, 0)); if (igraph_vcount(&g) != 1000) return 17; if (!igraph_is_directed(&g)) return 6; igraph_is_loop(&g, &bs, igraph_ess_all(IGRAPH_EDGEORDER_ID)); if (igraph_vector_bool_sum(&bs)) return 7; igraph_is_multiple(&g, &bs, igraph_ess_all(IGRAPH_EDGEORDER_ID)); if (igraph_vector_bool_sum(&bs)) return 8; igraph_destroy(&g); /* undirected, loops */ for (i=0; i<3; i++) MATRIX(pmat, i, i) = 1.0; IGRAPH_CHECK(igraph_preference_game(&g, 100, 3, &tdist, /*fixed_sizes=*/ 0, &pmat, 0, 0, 1)); if (igraph_vcount(&g) != 100) return 16; if (igraph_ecount(&g) < 1395) return 20; if (igraph_is_directed(&g)) return 9; igraph_is_loop(&g, &bs, igraph_ess_all(IGRAPH_EDGEORDER_ID)); if (igraph_vector_bool_sum(&bs) == 0) return 10; igraph_is_multiple(&g, &bs, igraph_ess_all(IGRAPH_EDGEORDER_ID)); if (igraph_vector_bool_sum(&bs)) return 11; igraph_destroy(&g); /* directed, loops */ IGRAPH_CHECK(igraph_preference_game(&g, 100, 3, &tdist, /*fixed_sizes=*/ 0, &pmat, 0, 1, 1)); if (igraph_vcount(&g) != 100) return 15; if (igraph_ecount(&g) < 2700) return 19; if (!igraph_is_directed(&g)) return 12; igraph_is_loop(&g, &bs, igraph_ess_all(IGRAPH_EDGEORDER_ID)); if (igraph_vector_bool_sum(&bs) == 0) return 13; igraph_is_multiple(&g, &bs, igraph_ess_all(IGRAPH_EDGEORDER_ID)); if (igraph_vector_bool_sum(&bs)) return 14; igraph_destroy(&g); /* Asymmetric preference game */ /* directed, no loops */ igraph_matrix_resize(&pmat, 2, 2); MATRIX(pmat, 0, 0) = 1; MATRIX(pmat, 0, 1) = 1; MATRIX(pmat, 1, 0) = 1; MATRIX(pmat, 1, 1) = 1; IGRAPH_CHECK(igraph_asymmetric_preference_game(&g, 100, 2, 0, &pmat, 0, 0, 0)); if (igraph_vcount(&g) != 100) return 21; if (igraph_ecount(&g) != 9900) return 22; if (!igraph_is_directed(&g)) return 23; igraph_is_loop(&g, &bs, igraph_ess_all(IGRAPH_EDGEORDER_ID)); if (igraph_vector_bool_sum(&bs)) return 24; igraph_is_multiple(&g, &bs, igraph_ess_all(IGRAPH_EDGEORDER_ID)); if (igraph_vector_bool_sum(&bs)) return 25; igraph_destroy(&g); /* directed, loops */ igraph_matrix_resize(&pmat, 2, 2); MATRIX(pmat, 0, 0) = 1; MATRIX(pmat, 0, 1) = 1; MATRIX(pmat, 1, 0) = 1; MATRIX(pmat, 1, 1) = 1; IGRAPH_CHECK(igraph_asymmetric_preference_game(&g, 100, 2, 0, &pmat, 0, 0, 1)); if (igraph_vcount(&g) != 100) return 26; if (igraph_ecount(&g) != 10000) return 27; if (!igraph_is_directed(&g)) return 28; igraph_is_loop(&g, &bs, igraph_ess_all(IGRAPH_EDGEORDER_ID)); if (igraph_vector_bool_sum(&bs) != 100) return 29; igraph_is_multiple(&g, &bs, igraph_ess_all(IGRAPH_EDGEORDER_ID)); if (igraph_vector_bool_sum(&bs)) return 30; igraph_destroy(&g); igraph_vector_destroy(&tdist); igraph_matrix_destroy(&pmat); igraph_vector_bool_destroy(&bs); assert(IGRAPH_FINALLY_STACK_EMPTY); return 0; }