int igraph_matrix_complex_realimag(const igraph_matrix_complex_t *v, igraph_matrix_t *real, igraph_matrix_t *imag) { long int nrow=igraph_matrix_complex_nrow(v); long int ncol=igraph_matrix_complex_ncol(v); IGRAPH_CHECK(igraph_matrix_resize(real, nrow, ncol)); IGRAPH_CHECK(igraph_matrix_resize(imag, nrow, ncol)); IGRAPH_CHECK(igraph_vector_complex_realimag(&v->data, &real->data, &imag->data)); return 0; }
/* call-seq: * IGraphMatrix.new([[x,y,...],...]) -> IGraphMatrix * * Creates a new IGraphMatrix object. The argument should be an Array of * Arrays which each contain the data for a row of the matrix. */ VALUE cIGraph_matrix_initialize(int argc, VALUE *argv, VALUE self){ igraph_matrix_t *m; VALUE rows; int nrows; int ncols; int i; int j; rb_scan_args(argc,argv,"0*", &rows); Data_Get_Struct(self, igraph_matrix_t, m); nrows = RARRAY_LEN(rows); ncols = RARRAY_LEN(RARRAY_PTR(rows)[0]); igraph_matrix_resize(m, nrows, ncols); //Loop through rows for (i=0; i<nrows; i++) { for (j=0; j<ncols; j++){ MATRIX(*m,i,j) = NUM2DBL(RARRAY_PTR(RARRAY_PTR(rows)[i])[j]); } } return self; }
int igraph_sample_dirichlet(igraph_integer_t n, const igraph_vector_t *alpha, igraph_matrix_t *res) { igraph_integer_t len=igraph_vector_size(alpha); igraph_integer_t i; igraph_vector_t vec; if (n < 0) { IGRAPH_ERROR("Number of samples should be non-negative", IGRAPH_EINVAL); } if (len < 2) { IGRAPH_ERROR("Dirichlet parameter vector too short, must " "have at least two entries", IGRAPH_EINVAL); } if (igraph_vector_min(alpha) <= 0) { IGRAPH_ERROR("Dirichlet concentration parameters must be positive", IGRAPH_EINVAL); } IGRAPH_CHECK(igraph_matrix_resize(res, len, n)); RNG_BEGIN(); for (i = 0; i < n; i++) { igraph_vector_view(&vec, &MATRIX(*res, 0, i), len); igraph_rng_get_dirichlet(igraph_rng_default(), alpha, &vec); } RNG_END(); return 0; }
/** * \ingroup structural * \function igraph_similarity_jaccard * \brief Jaccard similarity coefficient for the given vertices. * * </para><para> * The Jaccard similarity coefficient of two vertices is the number of common * neighbors divided by the number of vertices that are neighbors of at * least one of the two vertices being considered. This function calculates * the pairwise Jaccard similarities for some (or all) of the vertices. * * \param graph The graph object to analyze * \param res Pointer to a matrix, the result of the calculation will * be stored here. The number of its rows and columns is the same * as the number of vertex ids in \p vids. * \param vids The vertex ids of the vertices for which the * calculation will be done. * \param mode The type of neighbors to be used for the calculation in * directed graphs. Possible values: * \clist * \cli IGRAPH_OUT * the outgoing edges will be considered for each node. * \cli IGRAPH_IN * the incoming edges will be considered for each node. * \cli IGRAPH_ALL * the directed graph is considered as an undirected one for the * computation. * \endclist * \param loops Whether to include the vertices themselves in the neighbor * sets. * \return Error code: * \clist * \cli IGRAPH_ENOMEM * not enough memory for temporary data. * \cli IGRAPH_EINVVID * invalid vertex id passed. * \cli IGRAPH_EINVMODE * invalid mode argument. * \endclist * * Time complexity: O(|V|^2 d), * |V| is the number of vertices in the vertex iterator given, d is the * (maximum) degree of the vertices in the graph. * * \sa \ref igraph_similarity_dice(), a measure very similar to the Jaccard * coefficient * * \example examples/simple/igraph_similarity.c */ int igraph_similarity_jaccard(const igraph_t *graph, igraph_matrix_t *res, const igraph_vs_t vids, igraph_neimode_t mode, igraph_bool_t loops) { igraph_lazy_adjlist_t al; igraph_vit_t vit, vit2; long int i, j, k; long int len_union, len_intersection; igraph_vector_t *v1, *v2; IGRAPH_CHECK(igraph_vit_create(graph, vids, &vit)); IGRAPH_FINALLY(igraph_vit_destroy, &vit); IGRAPH_CHECK(igraph_vit_create(graph, vids, &vit2)); IGRAPH_FINALLY(igraph_vit_destroy, &vit2); IGRAPH_CHECK(igraph_lazy_adjlist_init(graph, &al, mode, IGRAPH_SIMPLIFY)); IGRAPH_FINALLY(igraph_lazy_adjlist_destroy, &al); IGRAPH_CHECK(igraph_matrix_resize(res, IGRAPH_VIT_SIZE(vit), IGRAPH_VIT_SIZE(vit))); if (loops) { for (IGRAPH_VIT_RESET(vit); !IGRAPH_VIT_END(vit); IGRAPH_VIT_NEXT(vit)) { i=IGRAPH_VIT_GET(vit); v1=igraph_lazy_adjlist_get(&al, (igraph_integer_t) i); if (!igraph_vector_binsearch(v1, i, &k)) igraph_vector_insert(v1, k, i); } } for (IGRAPH_VIT_RESET(vit), i=0; !IGRAPH_VIT_END(vit); IGRAPH_VIT_NEXT(vit), i++) { MATRIX(*res, i, i) = 1.0; for (IGRAPH_VIT_RESET(vit2), j=0; !IGRAPH_VIT_END(vit2); IGRAPH_VIT_NEXT(vit2), j++) { if (j <= i) continue; v1=igraph_lazy_adjlist_get(&al, IGRAPH_VIT_GET(vit)); v2=igraph_lazy_adjlist_get(&al, IGRAPH_VIT_GET(vit2)); igraph_i_neisets_intersect(v1, v2, &len_union, &len_intersection); if (len_union > 0) MATRIX(*res, i, j) = ((igraph_real_t)len_intersection)/len_union; else MATRIX(*res, i, j) = 0.0; MATRIX(*res, j, i) = MATRIX(*res, i, j); } } igraph_lazy_adjlist_destroy(&al); igraph_vit_destroy(&vit); igraph_vit_destroy(&vit2); IGRAPH_FINALLY_CLEAN(3); return 0; }
int main() { igraph_matrix_t m; igraph_matrix_init(&m, 10, 10); if (igraph_matrix_capacity(&m) != 100) { return 1; } igraph_matrix_add_cols(&m, 5); igraph_matrix_resize(&m, 5, 5); igraph_matrix_resize_min(&m); if (igraph_matrix_capacity(&m) != igraph_matrix_size(&m)) { return 2; } igraph_matrix_destroy(&m); return 0; }
int igraph_sample_sphere_surface(igraph_integer_t dim, igraph_integer_t n, igraph_real_t radius, igraph_bool_t positive, igraph_matrix_t *res) { igraph_integer_t i, j; if (dim < 2) { IGRAPH_ERROR("Sphere must be at least two dimensional to sample from " "surface", IGRAPH_EINVAL); } if (n < 0) { IGRAPH_ERROR("Number of samples must be non-negative", IGRAPH_EINVAL); } if (radius <= 0) { IGRAPH_ERROR("Sphere radius must be positive", IGRAPH_EINVAL); } IGRAPH_CHECK(igraph_matrix_resize(res, dim, n)); RNG_BEGIN(); for (i = 0; i < n; i++) { igraph_real_t *col=&MATRIX(*res, 0, i); igraph_real_t sum=0.0; for (j = 0; j < dim; j++) { col[j] = RNG_NORMAL(0, 1); sum += col[j] * col[j]; } sum = sqrt(sum); for (j = 0; j < dim; j++) { col[j] = radius * col[j] / sum; } if (positive) { for (j = 0; j < dim; j++) { col[j] = fabs(col[j]); } } } RNG_END(); return 0; }
int igraph_layout_kamada_kawai(const igraph_t *graph, igraph_matrix_t *res, igraph_bool_t use_seed, igraph_integer_t maxiter, igraph_real_t epsilon, igraph_real_t kkconst, const igraph_vector_t *weights, const igraph_vector_t *minx, const igraph_vector_t *maxx, const igraph_vector_t *miny, const igraph_vector_t *maxy) { igraph_integer_t no_nodes=igraph_vcount(graph); igraph_integer_t no_edges=igraph_ecount(graph); igraph_real_t L, L0=sqrt(no_nodes); igraph_matrix_t dij, lij, kij; igraph_real_t max_dij; igraph_vector_t D1, D2; igraph_integer_t i, j, m; if (maxiter < 0) { IGRAPH_ERROR("Number of iterations must be non-negatice in " "Kamada-Kawai layout", IGRAPH_EINVAL); } if (kkconst <= 0) { IGRAPH_ERROR("`K' constant must be positive in Kamada-Kawai layout", IGRAPH_EINVAL); } if (use_seed && (igraph_matrix_nrow(res) != no_nodes || igraph_matrix_ncol(res) != 2)) { IGRAPH_ERROR("Invalid start position matrix size in " "Kamada-Kawai layout", IGRAPH_EINVAL); } if (weights && igraph_vector_size(weights) != no_edges) { IGRAPH_ERROR("Invalid weight vector length", IGRAPH_EINVAL); } if (minx && igraph_vector_size(minx) != no_nodes) { IGRAPH_ERROR("Invalid minx vector length", IGRAPH_EINVAL); } if (maxx && igraph_vector_size(maxx) != no_nodes) { IGRAPH_ERROR("Invalid maxx vector length", IGRAPH_EINVAL); } if (minx && maxx && !igraph_vector_all_le(minx, maxx)) { IGRAPH_ERROR("minx must not be greater than maxx", IGRAPH_EINVAL); } if (miny && igraph_vector_size(miny) != no_nodes) { IGRAPH_ERROR("Invalid miny vector length", IGRAPH_EINVAL); } if (maxy && igraph_vector_size(maxy) != no_nodes) { IGRAPH_ERROR("Invalid maxy vector length", IGRAPH_EINVAL); } if (miny && maxy && !igraph_vector_all_le(miny, maxy)) { IGRAPH_ERROR("miny must not be greater than maxy", IGRAPH_EINVAL); } if (!use_seed) { if (minx || maxx || miny || maxy) { const igraph_real_t width=sqrt(no_nodes), height=width; IGRAPH_CHECK(igraph_matrix_resize(res, no_nodes, 2)); RNG_BEGIN(); for (i=0; i<no_nodes; i++) { igraph_real_t x1=minx ? VECTOR(*minx)[i] : -width/2; igraph_real_t x2=maxx ? VECTOR(*maxx)[i] : width/2; igraph_real_t y1=miny ? VECTOR(*miny)[i] : -height/2; igraph_real_t y2=maxy ? VECTOR(*maxy)[i] : height/2; if (!igraph_finite(x1)) { x1 = -width/2; } if (!igraph_finite(x2)) { x2 = width/2; } if (!igraph_finite(y1)) { y1 = -height/2; } if (!igraph_finite(y2)) { y2 = height/2; } MATRIX(*res, i, 0) = RNG_UNIF(x1, x2); MATRIX(*res, i, 1) = RNG_UNIF(y1, y2); } RNG_END(); } else { igraph_layout_circle(graph, res, /* order= */ igraph_vss_all()); } } if (no_nodes <= 1) { return 0; } IGRAPH_MATRIX_INIT_FINALLY(&dij, no_nodes, no_nodes); IGRAPH_MATRIX_INIT_FINALLY(&kij, no_nodes, no_nodes); IGRAPH_MATRIX_INIT_FINALLY(&lij, no_nodes, no_nodes); IGRAPH_CHECK(igraph_shortest_paths_dijkstra(graph, &dij, igraph_vss_all(), igraph_vss_all(), weights, IGRAPH_ALL)); max_dij = 0.0; for (i=0; i<no_nodes; i++) { for (j=i+1; j<no_nodes; j++) { if (!igraph_finite(MATRIX(dij, i, j))) { continue; } if (MATRIX(dij, i, j) > max_dij) { max_dij = MATRIX(dij, i, j); } } } for (i=0; i<no_nodes; i++) { for (j=0; j<no_nodes; j++) { if (MATRIX(dij, i, j) > max_dij) { MATRIX(dij, i, j) = max_dij; } } } L = L0 / max_dij; for (i=0; i<no_nodes; i++) { for (j=0; j<no_nodes; j++) { igraph_real_t tmp=MATRIX(dij, i, j) * MATRIX(dij, i, j); if (i==j) { continue; } MATRIX(kij, i, j) = kkconst / tmp; MATRIX(lij, i, j) = L * MATRIX(dij, i, j); } } /* Initialize delta */ IGRAPH_VECTOR_INIT_FINALLY(&D1, no_nodes); IGRAPH_VECTOR_INIT_FINALLY(&D2, no_nodes); for (m=0; m<no_nodes; m++) { igraph_real_t myD1=0.0, myD2=0.0; for (i=0; i<no_nodes; i++) { if (i==m) { continue; } igraph_real_t dx=MATRIX(*res, m, 0) - MATRIX(*res, i, 0); igraph_real_t dy=MATRIX(*res, m, 1) - MATRIX(*res, i, 1); igraph_real_t mi_dist=sqrt(dx * dx + dy * dy); myD1 += MATRIX(kij, m, i) * (dx - MATRIX(lij, m, i) * dx / mi_dist); myD2 += MATRIX(kij, m, i) * (dy - MATRIX(lij, m, i) * dy / mi_dist); } VECTOR(D1)[m] = myD1; VECTOR(D2)[m] = myD2; } for (j=0; j<maxiter; j++) { igraph_real_t myD1=0.0, myD2=0.0, A=0.0, B=0.0, C=0.0; igraph_real_t max_delta, delta_x, delta_y; igraph_real_t old_x, old_y, new_x, new_y; /* Select maximal delta */ m=0; max_delta=-1; for (i=0; i<no_nodes; i++) { igraph_real_t delta=(VECTOR(D1)[i] * VECTOR(D1)[i] + VECTOR(D2)[i] * VECTOR(D2)[i]); if (delta > max_delta) { m=i; max_delta=delta; } } if (max_delta < epsilon) { break; } old_x=MATRIX(*res, m, 0); old_y=MATRIX(*res, m, 1); /* Calculate D1 and D2, A, B, C */ for (i=0; i<no_nodes; i++) { if (i==m) { continue; } igraph_real_t dx=old_x - MATRIX(*res, i, 0); igraph_real_t dy=old_y - MATRIX(*res, i, 1); igraph_real_t dist=sqrt(dx * dx + dy * dy); igraph_real_t den=dist * (dx * dx + dy * dy); A += MATRIX(kij, m, i) * (1 - MATRIX(lij, m, i) * dy * dy / den); B += MATRIX(kij, m, i) * MATRIX(lij, m, i) * dx * dy / den; C += MATRIX(kij, m, i) * (1 - MATRIX(lij, m, i) * dx * dx / den); } myD1 = VECTOR(D1)[m]; myD2 = VECTOR(D2)[m]; /* Need to solve some linear equations */ delta_y = (B * myD1 - myD2 * A) / (C * A - B * B); delta_x = - (myD1 + B * delta_y) / A; new_x = old_x + delta_x; new_y = old_y + delta_y; /* Limits, if given */ if (minx && new_x < VECTOR(*minx)[m]) { new_x = VECTOR(*minx)[m]; } if (maxx && new_x > VECTOR(*maxx)[m]) { new_x = VECTOR(*maxx)[m]; } if (miny && new_y < VECTOR(*miny)[m]) { new_y = VECTOR(*miny)[m]; } if (maxy && new_y > VECTOR(*maxy)[m]) { new_y = VECTOR(*maxy)[m]; } /* Update delta, only with/for the affected node */ VECTOR(D1)[m] = VECTOR(D2)[m] = 0.0; for (i=0; i<no_nodes; i++) { if (i==m) { continue; } igraph_real_t old_dx=old_x - MATRIX(*res, i, 0); igraph_real_t old_dy=old_y - MATRIX(*res, i, 1); igraph_real_t old_mi_dist=sqrt(old_dx * old_dx + old_dy * old_dy); igraph_real_t new_dx=new_x - MATRIX(*res, i, 0); igraph_real_t new_dy=new_y - MATRIX(*res, i, 1); igraph_real_t new_mi_dist=sqrt(new_dx * new_dx + new_dy * new_dy); VECTOR(D1)[i] -= MATRIX(kij, m, i) * (-old_dx + MATRIX(lij, m, i) * old_dx / old_mi_dist); VECTOR(D2)[i] -= MATRIX(kij, m, i) * (-old_dy + MATRIX(lij, m, i) * old_dy / old_mi_dist); VECTOR(D1)[i] += MATRIX(kij, m, i) * (-new_dx + MATRIX(lij, m, i) * new_dx / new_mi_dist); VECTOR(D2)[i] += MATRIX(kij, m, i) * (-new_dy + MATRIX(lij, m, i) * new_dy / new_mi_dist); VECTOR(D1)[m] += MATRIX(kij, m, i) * (new_dx - MATRIX(lij, m, i) * new_dx / new_mi_dist); VECTOR(D2)[m] += MATRIX(kij, m, i) * (new_dy - MATRIX(lij, m, i) * new_dy / new_mi_dist); } /* Update coordinates*/ MATRIX(*res, m, 0) = new_x; MATRIX(*res, m, 1) = new_y; } igraph_vector_destroy(&D2); igraph_vector_destroy(&D1); igraph_matrix_destroy(&lij); igraph_matrix_destroy(&kij); igraph_matrix_destroy(&dij); IGRAPH_FINALLY_CLEAN(5); return 0; }
int igraph_cocitation_real(const igraph_t *graph, igraph_matrix_t *res, igraph_vs_t vids, igraph_neimode_t mode, igraph_vector_t *weights) { long int no_of_nodes=igraph_vcount(graph); long int no_of_vids; long int from, i, j, k, l, u, v; igraph_vector_t neis=IGRAPH_VECTOR_NULL; igraph_vector_t vid_reverse_index; igraph_vit_t vit; IGRAPH_CHECK(igraph_vit_create(graph, vids, &vit)); IGRAPH_FINALLY(igraph_vit_destroy, &vit); no_of_vids = IGRAPH_VIT_SIZE(vit); /* Create a mapping from vertex IDs to the row of the matrix where * the result for this vertex will appear */ IGRAPH_VECTOR_INIT_FINALLY(&vid_reverse_index, no_of_nodes); igraph_vector_fill(&vid_reverse_index, -1); for (IGRAPH_VIT_RESET(vit), i = 0; !IGRAPH_VIT_END(vit); IGRAPH_VIT_NEXT(vit), i++) { v = IGRAPH_VIT_GET(vit); if (v < 0 || v >= no_of_nodes) IGRAPH_ERROR("invalid vertex ID in vertex selector", IGRAPH_EINVAL); VECTOR(vid_reverse_index)[v] = i; } IGRAPH_VECTOR_INIT_FINALLY(&neis, 0); IGRAPH_CHECK(igraph_matrix_resize(res, no_of_vids, no_of_nodes)); igraph_matrix_null(res); /* The result */ for (from=0; from<no_of_nodes; from++) { igraph_real_t weight = 1; IGRAPH_ALLOW_INTERRUPTION(); IGRAPH_CHECK(igraph_neighbors(graph, &neis, (igraph_integer_t) from, mode)); if (weights) weight = VECTOR(*weights)[from]; for (i=0; i < igraph_vector_size(&neis)-1; i++) { u = (long int) VECTOR(neis)[i]; k = (long int) VECTOR(vid_reverse_index)[u]; for (j=i+1; j<igraph_vector_size(&neis); j++) { v = (long int) VECTOR(neis)[j]; l = (long int) VECTOR(vid_reverse_index)[v]; if (k != -1) MATRIX(*res, k, v) += weight; if (l != -1) MATRIX(*res, l, u) += weight; } } } /* Clean up */ igraph_vector_destroy(&neis); igraph_vector_destroy(&vid_reverse_index); igraph_vit_destroy(&vit); IGRAPH_FINALLY_CLEAN(3); return 0; }
int igraph_layout_i_fr(const igraph_t *graph, igraph_matrix_t *res, igraph_bool_t use_seed, igraph_integer_t niter, igraph_real_t start_temp, const igraph_vector_t *weight, const igraph_vector_t *minx, const igraph_vector_t *maxx, const igraph_vector_t *miny, const igraph_vector_t *maxy) { igraph_integer_t no_nodes=igraph_vcount(graph); igraph_integer_t no_edges=igraph_ecount(graph); igraph_integer_t i; igraph_vector_float_t dispx, dispy; igraph_real_t temp=start_temp; igraph_real_t difftemp=start_temp / niter; float width=sqrtf(no_nodes), height=width; igraph_bool_t conn=1; float C; igraph_is_connected(graph, &conn, IGRAPH_WEAK); if (!conn) { C = no_nodes * sqrtf(no_nodes); } RNG_BEGIN(); if (!use_seed) { IGRAPH_CHECK(igraph_matrix_resize(res, no_nodes, 2)); for (i=0; i<no_nodes; i++) { igraph_real_t x1=minx ? VECTOR(*minx)[i] : -width/2; igraph_real_t x2=maxx ? VECTOR(*maxx)[i] : width/2; igraph_real_t y1=miny ? VECTOR(*miny)[i] : -height/2; igraph_real_t y2=maxy ? VECTOR(*maxy)[i] : height/2; if (!igraph_finite(x1)) { x1 = -sqrt(no_nodes)/2; } if (!igraph_finite(x2)) { x2 = sqrt(no_nodes)/2; } if (!igraph_finite(y1)) { y1 = -sqrt(no_nodes)/2; } if (!igraph_finite(y2)) { y2 = sqrt(no_nodes)/2; } MATRIX(*res, i, 0) = RNG_UNIF(x1, x2); MATRIX(*res, i, 1) = RNG_UNIF(y1, y2); } } IGRAPH_CHECK(igraph_vector_float_init(&dispx, no_nodes)); IGRAPH_FINALLY(igraph_vector_float_destroy, &dispx); IGRAPH_CHECK(igraph_vector_float_init(&dispy, no_nodes)); IGRAPH_FINALLY(igraph_vector_float_destroy, &dispy); for (i=0; i<niter; i++) { igraph_integer_t v, u, e; /* calculate repulsive forces, we have a special version for unconnected graphs */ igraph_vector_float_null(&dispx); igraph_vector_float_null(&dispy); if (conn) { for (v=0; v<no_nodes; v++) { for (u=v+1; u<no_nodes; u++) { float dx=MATRIX(*res, v, 0) - MATRIX(*res, u, 0); float dy=MATRIX(*res, v, 1) - MATRIX(*res, u, 1); float dlen=dx * dx + dy * dy; if (dlen == 0) { dx = RNG_UNIF01() * 1e-9; dy = RNG_UNIF01() * 1e-9; dlen = dx * dx + dy * dy; } VECTOR(dispx)[v] += dx/dlen; VECTOR(dispy)[v] += dy/dlen; VECTOR(dispx)[u] -= dx/dlen; VECTOR(dispy)[u] -= dy/dlen; } } } else { for (v=0; v<no_nodes; v++) { for (u=v+1; u<no_nodes; u++) { float dx=MATRIX(*res, v, 0) - MATRIX(*res, u, 0); float dy=MATRIX(*res, v, 1) - MATRIX(*res, u, 1); float dlen, rdlen; dlen=dx * dx + dy * dy; if (dlen == 0) { dx = RNG_UNIF(0, 1e-6); dy = RNG_UNIF(0, 1e-6); dlen = dx * dx + dy * dy; } rdlen=sqrt(dlen); VECTOR(dispx)[v] += dx * (C-dlen * rdlen) / (dlen*C); VECTOR(dispy)[v] += dy * (C-dlen * rdlen) / (dlen*C); VECTOR(dispx)[u] -= dx * (C-dlen * rdlen) / (dlen*C); VECTOR(dispy)[u] -= dy * (C-dlen * rdlen) / (dlen*C); } } } /* calculate attractive forces */ for (e=0; e<no_edges; e++) { /* each edges is an ordered pair of vertices v and u */ igraph_integer_t v=IGRAPH_FROM(graph, e); igraph_integer_t u=IGRAPH_TO(graph, e); igraph_real_t dx=MATRIX(*res, v, 0) - MATRIX(*res, u, 0); igraph_real_t dy=MATRIX(*res, v, 1) - MATRIX(*res, u, 1); igraph_real_t w=weight ? VECTOR(*weight)[e] : 1.0; igraph_real_t dlen=sqrt(dx * dx + dy * dy) * w; VECTOR(dispx)[v] -= (dx * dlen); VECTOR(dispy)[v] -= (dy * dlen); VECTOR(dispx)[u] += (dx * dlen); VECTOR(dispy)[u] += (dy * dlen); } /* limit max displacement to temperature t and prevent from displacement outside frame */ for (v=0; v<no_nodes; v++) { igraph_real_t dx=VECTOR(dispx)[v] + RNG_UNIF01() * 1e-9; igraph_real_t dy=VECTOR(dispy)[v] + RNG_UNIF01() * 1e-9; igraph_real_t displen=sqrt(dx * dx + dy * dy); igraph_real_t mx=fabs(dx) < temp ? dx : temp; igraph_real_t my=fabs(dy) < temp ? dy : temp; if (displen > 0) { MATRIX(*res, v, 0) += (dx / displen) * mx; MATRIX(*res, v, 1) += (dy / displen) * my; } if (minx && MATRIX(*res, v, 0) < VECTOR(*minx)[v]) { MATRIX(*res, v, 0) = VECTOR(*minx)[v]; } if (maxx && MATRIX(*res, v, 0) > VECTOR(*maxx)[v]) { MATRIX(*res, v, 0) = VECTOR(*maxx)[v]; } if (miny && MATRIX(*res, v, 1) < VECTOR(*miny)[v]) { MATRIX(*res, v, 1) = VECTOR(*miny)[v]; } if (maxy && MATRIX(*res, v, 1) > VECTOR(*maxy)[v]) { MATRIX(*res, v, 1) = VECTOR(*maxy)[v]; } } temp -= difftemp; } RNG_END(); igraph_vector_float_destroy(&dispx); igraph_vector_float_destroy(&dispy); IGRAPH_FINALLY_CLEAN(2); return 0; }
int igraph_lapack_dgeevx(igraph_lapack_dgeevx_balance_t balance, const igraph_matrix_t *A, igraph_vector_t *valuesreal, igraph_vector_t *valuesimag, igraph_matrix_t *vectorsleft, igraph_matrix_t *vectorsright, int *ilo, int *ihi, igraph_vector_t *scale, igraph_real_t *abnrm, igraph_vector_t *rconde, igraph_vector_t *rcondv, int *info) { char balanc; char jobvl= vectorsleft ? 'V' : 'N'; char jobvr= vectorsright ? 'V' : 'N'; char sense; int n=(int) igraph_matrix_nrow(A); int lda=n, ldvl=n, ldvr=n, lwork=-1; igraph_vector_t work; igraph_vector_int_t iwork; igraph_matrix_t Acopy; int error=*info; igraph_vector_t *myreal=valuesreal, *myimag=valuesimag, vreal, vimag; igraph_vector_t *myscale=scale, vscale; if (igraph_matrix_ncol(A) != n) { IGRAPH_ERROR("Cannot calculate eigenvalues (dgeevx)", IGRAPH_NONSQUARE); } switch (balance) { case IGRAPH_LAPACK_DGEEVX_BALANCE_NONE: balanc='N'; break; case IGRAPH_LAPACK_DGEEVX_BALANCE_PERM: balanc='P'; break; case IGRAPH_LAPACK_DGEEVX_BALANCE_SCALE: balanc='S'; break; case IGRAPH_LAPACK_DGEEVX_BALANCE_BOTH: balanc='B'; break; default: IGRAPH_ERROR("Invalid 'balance' argument", IGRAPH_EINVAL); break; } if (!rconde && !rcondv) { sense='N'; } else if (rconde && !rcondv) { sense='E'; } else if (!rconde && rcondv) { sense='V'; } else { sense='B'; } IGRAPH_CHECK(igraph_matrix_copy(&Acopy, A)); IGRAPH_FINALLY(igraph_matrix_destroy, &Acopy); IGRAPH_VECTOR_INIT_FINALLY(&work, 1); IGRAPH_CHECK(igraph_vector_int_init(&iwork, n)); IGRAPH_FINALLY(igraph_vector_int_destroy, &iwork); if (!valuesreal) { IGRAPH_VECTOR_INIT_FINALLY(&vreal, n); myreal=&vreal; } else { IGRAPH_CHECK(igraph_vector_resize(myreal, n)); } if (!valuesimag) { IGRAPH_VECTOR_INIT_FINALLY(&vimag, n); myimag=&vimag; } else { IGRAPH_CHECK(igraph_vector_resize(myimag, n)); } if (!scale) { IGRAPH_VECTOR_INIT_FINALLY(&vscale, n); myscale=&vscale; } else { IGRAPH_CHECK(igraph_vector_resize(scale, n)); } if (vectorsleft) { IGRAPH_CHECK(igraph_matrix_resize(vectorsleft, n, n)); } if (vectorsright) { IGRAPH_CHECK(igraph_matrix_resize(vectorsright, n, n)); } igraphdgeevx_(&balanc, &jobvl, &jobvr, &sense, &n, &MATRIX(Acopy,0,0), &lda, VECTOR(*myreal), VECTOR(*myimag), vectorsleft ? &MATRIX(*vectorsleft ,0,0) : 0, &ldvl, vectorsright ? &MATRIX(*vectorsright,0,0) : 0, &ldvr, ilo, ihi, VECTOR(*myscale), abnrm, rconde ? VECTOR(*rconde) : 0, rcondv ? VECTOR(*rcondv) : 0, VECTOR(work), &lwork, VECTOR(iwork), info); lwork=(int) VECTOR(work)[0]; IGRAPH_CHECK(igraph_vector_resize(&work, lwork)); igraphdgeevx_(&balanc, &jobvl, &jobvr, &sense, &n, &MATRIX(Acopy,0,0), &lda, VECTOR(*myreal), VECTOR(*myimag), vectorsleft ? &MATRIX(*vectorsleft ,0,0) : 0, &ldvl, vectorsright ? &MATRIX(*vectorsright,0,0) : 0, &ldvr, ilo, ihi, VECTOR(*myscale), abnrm, rconde ? VECTOR(*rconde) : 0, rcondv ? VECTOR(*rcondv) : 0, VECTOR(work), &lwork, VECTOR(iwork), info); if (*info < 0) { IGRAPH_ERROR("Cannot calculate eigenvalues (dgeev)", IGRAPH_ELAPACK); } else if (*info > 0) { if (error) { IGRAPH_ERROR("Cannot calculate eigenvalues (dgeev)", IGRAPH_ELAPACK); } else { IGRAPH_WARNING("Cannot calculate eigenvalues (dgeev)"); } } if (!scale) { igraph_vector_destroy(&vscale); IGRAPH_FINALLY_CLEAN(1); } if (!valuesimag) { igraph_vector_destroy(&vimag); IGRAPH_FINALLY_CLEAN(1); } if (!valuesreal) { igraph_vector_destroy(&vreal); IGRAPH_FINALLY_CLEAN(1); } igraph_vector_int_destroy(&iwork); igraph_vector_destroy(&work); igraph_matrix_destroy(&Acopy); IGRAPH_FINALLY_CLEAN(3); return 0; }
int igraph_lapack_dsyevr(const igraph_matrix_t *A, igraph_lapack_dsyev_which_t which, igraph_real_t vl, igraph_real_t vu, int vestimate, int il, int iu, igraph_real_t abstol, igraph_vector_t *values, igraph_matrix_t *vectors, igraph_vector_int_t *support) { igraph_matrix_t Acopy; char jobz = vectors ? 'V' : 'N', range, uplo='U'; int n=(int) igraph_matrix_nrow(A), lda=n, ldz=n; int m, info; igraph_vector_t *myvalues=values, vvalues; igraph_vector_int_t *mysupport=support, vsupport; igraph_vector_t work; igraph_vector_int_t iwork; int lwork=-1, liwork=-1; if (n != igraph_matrix_ncol(A)) { IGRAPH_ERROR("Cannot find eigenvalues/vectors", IGRAPH_NONSQUARE); } if (which==IGRAPH_LAPACK_DSYEV_INTERVAL && (vestimate < 1 || vestimate > n)) { IGRAPH_ERROR("Estimated (upper bound) number of eigenvalues must be " "between 1 and n", IGRAPH_EINVAL); } if (which==IGRAPH_LAPACK_DSYEV_SELECT && iu-il < 0) { IGRAPH_ERROR("Invalid 'il' and/or 'iu' values", IGRAPH_EINVAL); } IGRAPH_CHECK(igraph_matrix_copy(&Acopy, A)); IGRAPH_FINALLY(igraph_matrix_destroy, &Acopy); IGRAPH_VECTOR_INIT_FINALLY(&work, 1); IGRAPH_CHECK(igraph_vector_int_init(&iwork, 1)); IGRAPH_FINALLY(igraph_vector_int_destroy, &iwork); if (!values) { IGRAPH_VECTOR_INIT_FINALLY(&vvalues, 0); myvalues=&vvalues; } if (!support) { IGRAPH_CHECK(igraph_vector_int_init(&vsupport, 0)); IGRAPH_FINALLY(igraph_vector_int_destroy, &vsupport); mysupport=&vsupport; } switch (which) { case IGRAPH_LAPACK_DSYEV_ALL: range = 'A'; IGRAPH_CHECK(igraph_vector_resize(myvalues, n)); IGRAPH_CHECK(igraph_vector_int_resize(mysupport, 2*n)); if (vectors) { IGRAPH_CHECK(igraph_matrix_resize(vectors, n, n)); } break; case IGRAPH_LAPACK_DSYEV_INTERVAL: range = 'V'; IGRAPH_CHECK(igraph_vector_resize(myvalues, vestimate)); IGRAPH_CHECK(igraph_vector_int_resize(mysupport, 2*vestimate)); if (vectors) { IGRAPH_CHECK(igraph_matrix_resize(vectors,n, vestimate)); } break; case IGRAPH_LAPACK_DSYEV_SELECT: range = 'I'; IGRAPH_CHECK(igraph_vector_resize(myvalues, iu-il+1)); IGRAPH_CHECK(igraph_vector_int_resize(mysupport, 2*(iu-il+1))); if (vectors) { IGRAPH_CHECK(igraph_matrix_resize(vectors, n, iu-il+1)); } break; } igraphdsyevr_(&jobz, &range, &uplo, &n, &MATRIX(Acopy,0,0), &lda, &vl, &vu, &il, &iu, &abstol, &m, VECTOR(*myvalues), vectors ? &MATRIX(*vectors,0,0) : 0, &ldz, VECTOR(*mysupport), VECTOR(work), &lwork, VECTOR(iwork), &liwork, &info); lwork=(int) VECTOR(work)[0]; liwork=VECTOR(iwork)[0]; IGRAPH_CHECK(igraph_vector_resize(&work, lwork)); IGRAPH_CHECK(igraph_vector_int_resize(&iwork, liwork)); igraphdsyevr_(&jobz, &range, &uplo, &n, &MATRIX(Acopy,0,0), &lda, &vl, &vu, &il, &iu, &abstol, &m, VECTOR(*myvalues), vectors ? &MATRIX(*vectors,0,0) : 0, &ldz, VECTOR(*mysupport), VECTOR(work), &lwork, VECTOR(iwork), &liwork, &info); if (values) { IGRAPH_CHECK(igraph_vector_resize(values, m)); } if (vectors) { IGRAPH_CHECK(igraph_matrix_resize(vectors, n, m)); } if (support) { IGRAPH_CHECK(igraph_vector_int_resize(support, m)); } if (!support) { igraph_vector_int_destroy(&vsupport); IGRAPH_FINALLY_CLEAN(1); } if (!values) { igraph_vector_destroy(&vvalues); IGRAPH_FINALLY_CLEAN(1); } igraph_vector_int_destroy(&iwork); igraph_vector_destroy(&work); igraph_matrix_destroy(&Acopy); IGRAPH_FINALLY_CLEAN(3); return 0; }
int igraph_i_eigen_matrix_symmetric_lapack_lm(const igraph_matrix_t *A, const igraph_eigen_which_t *which, igraph_vector_t *values, igraph_matrix_t *vectors) { igraph_matrix_t vec1, vec2; igraph_vector_t val1, val2; int n=(int) igraph_matrix_nrow(A); int p1=0, p2=which->howmany-1, pr=0; IGRAPH_VECTOR_INIT_FINALLY(&val1, 0); IGRAPH_VECTOR_INIT_FINALLY(&val2, 0); if (vectors) { IGRAPH_CHECK(igraph_matrix_init(&vec1, 0, 0)); IGRAPH_FINALLY(igraph_matrix_destroy, &vec1); IGRAPH_CHECK(igraph_matrix_init(&vec2, 0, 0)); IGRAPH_FINALLY(igraph_matrix_destroy, &vec1); } IGRAPH_CHECK(igraph_lapack_dsyevr(A, IGRAPH_LAPACK_DSYEV_SELECT, /*vl=*/ 0, /*vu=*/ 0, /*vestimate=*/ 0, /*il=*/ 1, /*iu=*/ which->howmany, /*abstol=*/ 1e-14, &val1, vectors ? &vec1 : 0, /*support=*/ 0)); IGRAPH_CHECK(igraph_lapack_dsyevr(A, IGRAPH_LAPACK_DSYEV_SELECT, /*vl=*/ 0, /*vu=*/ 0, /*vestimate=*/ 0, /*il=*/ n-which->howmany+1, /*iu=*/ n, /*abstol=*/ 1e-14, &val2, vectors ? &vec2 : 0, /*support=*/ 0)); if (values) { IGRAPH_CHECK(igraph_vector_resize(values, which->howmany)); } if (vectors) { IGRAPH_CHECK(igraph_matrix_resize(vectors, n, which->howmany)); } while (pr < which->howmany) { if (p2 < 0 || fabs(VECTOR(val1)[p1]) > fabs(VECTOR(val2)[p2])) { if (values) { VECTOR(*values)[pr]=VECTOR(val1)[p1]; } if (vectors) { memcpy(&MATRIX(*vectors,0,pr), &MATRIX(vec1,0,p1), sizeof(igraph_real_t) * (size_t) n); } p1++; pr++; } else { if (values) { VECTOR(*values)[pr]=VECTOR(val2)[p2]; } if (vectors) { memcpy(&MATRIX(*vectors,0,pr), &MATRIX(vec2,0,p2), sizeof(igraph_real_t) * (size_t) n); } p2--; pr++; } } if (vectors) { igraph_matrix_destroy(&vec2); igraph_matrix_destroy(&vec1); IGRAPH_FINALLY_CLEAN(2); } igraph_vector_destroy(&val2); igraph_vector_destroy(&val1); IGRAPH_FINALLY_CLEAN(2); return 0; }
int igraph_i_eigen_matrix_symmetric_lapack_sm(const igraph_matrix_t *A, const igraph_eigen_which_t *which, igraph_vector_t *values, igraph_matrix_t *vectors) { igraph_vector_t val; igraph_matrix_t vec; int i, w=0, n=(int) igraph_matrix_nrow(A); igraph_real_t small; int p1, p2, pr=0; IGRAPH_VECTOR_INIT_FINALLY(&val, 0); if (vectors) { IGRAPH_MATRIX_INIT_FINALLY(&vec, 0, 0); } IGRAPH_CHECK(igraph_lapack_dsyevr(A, IGRAPH_LAPACK_DSYEV_ALL, /*vl=*/ 0, /*vu=*/ 0, /*vestimate=*/ 0, /*il=*/ 0, /*iu=*/ 0, /*abstol=*/ 1e-14, &val, vectors ? &vec : 0, /*support=*/ 0)); /* Look for smallest value */ small=fabs(VECTOR(val)[0]); for (i=1; i<n; i++) { igraph_real_t v=fabs(VECTOR(val)[i]); if (v < small) { small=v; w=i; } } p1=w-1; p2=w; if (values) { IGRAPH_CHECK(igraph_vector_resize(values, which->howmany)); } if (vectors) { IGRAPH_CHECK(igraph_matrix_resize(vectors, n, which->howmany)); } while (pr < which->howmany) { if (p2 == n-1 || fabs(VECTOR(val)[p1]) < fabs(VECTOR(val)[p2])) { if (values) { VECTOR(*values)[pr]=VECTOR(val)[p1]; } if (vectors) { memcpy(&MATRIX(*vectors,0,pr), &MATRIX(vec,0,p1), sizeof(igraph_real_t) * (size_t) n); } p1--; pr++; } else { if (values) { VECTOR(*values)[pr]=VECTOR(val)[p2]; } if (vectors) { memcpy(&MATRIX(*vectors,0,pr), &MATRIX(vec,0,p2), sizeof(igraph_real_t) * (size_t) n); } p2++; pr++; } } if (vectors) { igraph_matrix_destroy(&vec); IGRAPH_FINALLY_CLEAN(1); } igraph_vector_destroy(&val); IGRAPH_FINALLY_CLEAN(1); return 0; }
/** * \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 main() { igraph_matrix_t m, m2; igraph_vector_t v; long int i, j, i2, j2; igraph_real_t r1, r2; igraph_matrix_init(&m, 4, 3); byrow(&m); /* igraph_matrix_e */ printf("igraph_matrix_e\n"); apply(m, printf("%i ", (int)igraph_matrix_e(&m, i, j)), printf("\n")); /* igraph_matrix_e_ptr */ printf("igraph_matrix_e_ptr\n"); apply(m, printf("%i ", (int)igraph_matrix_e_ptr(&m, i, j)[0]), printf("\n")); /* igraph_matrix_set */ printf("igraph_matrix_set\n"); apply(m, igraph_matrix_set(&m, i, j, i), (void) 0 ); print_matrix(&m); apply(m, igraph_matrix_set(&m, i, j, j), (void) 0 ); print_matrix(&m); /* igraph_matrix_fill */ printf("igraph_matrix_fill\n"); igraph_matrix_fill(&m, 42); print_matrix(&m); igraph_matrix_fill(&m, -42.1); print_matrix(&m); /* igraph_matrix_update */ printf("igraph_matrix_update\n"); igraph_matrix_init(&m2, 0, 0); byrow(&m); igraph_matrix_update(&m2, &m); print_matrix(&m2); /* igraph_matrix_rbind */ printf("igraph_matrix_rbind\n"); igraph_matrix_rbind(&m2, &m); print_matrix(&m2); printf("\n"); igraph_matrix_resize(&m, 0, igraph_matrix_ncol(&m2)); igraph_matrix_rbind(&m2, &m); print_matrix(&m2); printf("\n"); igraph_matrix_rbind(&m, &m2); print_matrix(&m); /* igraph_matrix_cbind */ printf("igraph_matrix_cbind\n"); igraph_matrix_resize(&m, 4, 3); igraph_matrix_resize(&m2, 4, 2); byrow(&m); byrow(&m2); igraph_matrix_cbind(&m, &m2); print_matrix(&m); /* igraph_matrix_swap */ printf("igraph_matrix_swap\n"); igraph_matrix_update(&m, &m2); igraph_matrix_null(&m); igraph_matrix_swap(&m, &m2); print_matrix(&m); print_matrix(&m2); /* igraph_matrix_get_row */ /* igraph_matrix_set_row */ printf("igraph_matrix_get_row\n"); printf("igraph_matrix_set_row\n"); igraph_vector_init(&v, 0); for (i=0; i<igraph_matrix_nrow(&m); i++) { igraph_matrix_get_row(&m, &v, i); igraph_matrix_set_row(&m2, &v, i); } print_matrix(&m2); /* igraph_matrix_set_col */ printf("igraph_matrix_set_col\n"); igraph_matrix_null(&m2); for (i=0; i<igraph_matrix_ncol(&m); i++) { igraph_matrix_get_col(&m, &v, i); igraph_matrix_set_col(&m2, &v, i); } print_matrix(&m2); /* igraph_matrix_swap_rows */ printf("igraph_matrix_swap_rows\n"); igraph_matrix_swap_rows(&m2, 0, 0); igraph_matrix_swap_rows(&m2, 0, 2); print_matrix(&m2); /* igraph_matrix_swap_cols */ printf("igraph_matrix_swap_cols\n"); igraph_matrix_swap_cols(&m2, 0, 0); igraph_matrix_swap_cols(&m2, 0, 1); print_matrix(&m2); /* igraph_matrix_add_constant */ printf("igraph_matrix_add_constant\n"); igraph_matrix_add_constant(&m2, 0); print_matrix(&m2); igraph_matrix_add_constant(&m2, -1); print_matrix(&m2); /* igraph_matrix_add */ printf("igraph_matrix_add\n"); byrow(&m2); byrow(&m); igraph_matrix_add(&m2, &m); print_matrix(&m2); /* igraph_matrix_sub */ printf("igraph_matrix_sub\n"); igraph_matrix_sub(&m2, &m); print_matrix(&m2); /* igraph_matrix_mul_elements */ printf("igraph_matrix_mul_elements\n"); igraph_matrix_mul_elements(&m2, &m); print_matrix(&m2); /* igraph_matrix_div_elements */ printf("igraph_matrix_div_elements\n"); igraph_matrix_fill(&m, 2); igraph_matrix_div_elements(&m2, &m); print_matrix(&m2); /* igraph_matrix_min */ printf("igraph_matrix_min\n"); if (igraph_matrix_min(&m2) != 0) { return 1; } if (igraph_matrix_min(&m) != 2) { return 1; } /* igraph_matrix_which_min */ printf("igraph_matrix_which_min\n"); igraph_matrix_which_min(&m2, &i, &j); if (i != 0 || j != 0) { return 2; } MATRIX(m2,0,1) = -1; igraph_matrix_which_min(&m2, &i, &j); if (i != 0 || j != 1) { return 2; } MATRIX(m2,3,1) = -2; igraph_matrix_which_min(&m2, &i, &j); if (i != 3 || j != 1) { return 2; } /* igraph_matrix_which_max */ printf("igraph_matrix_which_max\n"); MATRIX(m2,3,0) = 100; igraph_matrix_which_max(&m2, &i, &j); if (i != 3 || j != 0) { return 3; } /* igraph_matrix_minmax */ printf("igraph_matrix_minmax\n"); igraph_matrix_minmax(&m2, &r1, &r2); printf("%g %g\n", r1, r2); /* igraph_matrix_which_minmax */ printf("igraph_matrix_which_minmax\n"); igraph_matrix_which_minmax(&m2, &i, &j, &i2, &j2); if (i != 3 || j != 1 || i2 != 3 || j2 != 0) { return 4; } /* igraph_matrix_isnull */ printf("igraph_matrix_isnull\n"); if (igraph_matrix_isnull(&m2)) { return 5; } igraph_matrix_null(&m); if (!igraph_matrix_isnull(&m)) { return 5; } igraph_matrix_resize(&m2, 5, 0); if (!igraph_matrix_isnull(&m2)) { return 5; } /* igraph_matrix_empty */ printf("igraph_matrix_empty\n"); if (!igraph_matrix_empty(&m2)) { return 6; } igraph_matrix_resize(&m2, 5, 5); if (igraph_matrix_empty(&m2)) { return 6; } /* igraph_matrix_is_symmetric */ printf("igraph_matrix_is_symmetric\n"); byrow(&m2); if (igraph_matrix_is_symmetric(&m2)) { return 7; } igraph_matrix_update(&m, &m2); igraph_matrix_transpose(&m); igraph_matrix_add(&m, &m2); if (!igraph_matrix_is_symmetric(&m)) { return 7; } /* igraph_matrix_prod */ printf("igraph_matrix_prod\n"); igraph_matrix_resize(&m, 3,2); byrow(&m); igraph_matrix_add_constant(&m, 1); print_matrix(&m); printf("product: %g\n", igraph_matrix_prod(&m)); /* igraph_matrix_rowsum */ printf("igraph_matrix_rowsum\n"); igraph_matrix_rowsum(&m, &v); print_vector(&v); /* igraph_matrix_colsum */ printf("igraph_matrix_colsum\n"); igraph_matrix_colsum(&m, &v); print_vector(&v); /* igraph_matrix_contains */ printf("igraph_matrix_contains\n"); if (igraph_matrix_contains(&m, 0)) { return 8; } if (igraph_matrix_contains(&m, 6.0001)) { return 8; } if (igraph_matrix_contains(&m, 7)) { return 8; } if (!igraph_matrix_contains(&m, 1)) { return 8; } if (!igraph_matrix_contains(&m, 6)) { return 8; } /* igraph_matrix_search */ printf("igraph_matrix_search\n"); if (!igraph_matrix_search(&m, 0, 6.0, &i2, &i, &j)) { return 9; } if (i2 != 5 || i != 2 || j != 1) { return 9; } /* igraph_matrix_remove_row */ printf("igraph_matrix_remove_row\n"); igraph_matrix_remove_row(&m, 1); print_matrix(&m); igraph_matrix_resize(&m,5,4); byrow(&m); igraph_matrix_remove_row(&m, 4); print_matrix(&m); igraph_matrix_remove_row(&m, 0); print_matrix(&m); /* igraph_matrix_select_cols */ printf("igraph_matrix_select_cols\n"); igraph_matrix_resize(&m, 6, 5); apply(m, igraph_matrix_set(&m, i, j, j), (void) 0 ); igraph_vector_resize(&v, 3); VECTOR(v)[0]=0; VECTOR(v)[1]=4; VECTOR(v)[2]=2; igraph_matrix_select_cols(&m, &m2, &v); print_matrix(&m2); igraph_vector_resize(&v, 1); igraph_matrix_select_cols(&m, &m2, &v); print_matrix(&m2); igraph_vector_clear(&v); igraph_matrix_select_cols(&m, &m2, &v); if (!igraph_matrix_empty(&m2)) { return 9; } igraph_vector_destroy(&v); igraph_matrix_destroy(&m2); igraph_matrix_destroy(&m); if (IGRAPH_FINALLY_STACK_SIZE() != 0) return 10; return 0; }
int igraph_get_incidence(const igraph_t *graph, const igraph_vector_bool_t *types, igraph_matrix_t *res, igraph_vector_t *row_ids, igraph_vector_t *col_ids) { long int no_of_nodes=igraph_vcount(graph); long int no_of_edges=igraph_ecount(graph); long int n1=0, n2=0, i; igraph_vector_t perm; long int p1, p2; if (igraph_vector_bool_size(types) != no_of_nodes) { IGRAPH_ERROR("Invalid vertex type vector for bipartite graph", IGRAPH_EINVAL); } for (i=0; i<no_of_nodes; i++) { n1 += VECTOR(*types)[i] == 0 ? 1 : 0; } n2 = no_of_nodes-n1; IGRAPH_VECTOR_INIT_FINALLY(&perm, no_of_nodes); for (i=0, p1=0, p2=n1; i<no_of_nodes; i++) { VECTOR(perm)[i] = VECTOR(*types)[i] ? p2++ : p1++; } IGRAPH_CHECK(igraph_matrix_resize(res, n1, n2)); igraph_matrix_null(res); for (i=0; i<no_of_edges; i++) { long int from=IGRAPH_FROM(graph, i); long int to=IGRAPH_TO(graph, i); long int from2=(long int) VECTOR(perm)[from]; long int to2=(long int) VECTOR(perm)[to]; if (! VECTOR(*types)[from]) { MATRIX(*res, from2, to2-n1) += 1; } else { MATRIX(*res, to2, from2-n1) += 1; } } if (row_ids) { IGRAPH_CHECK(igraph_vector_resize(row_ids, n1)); } if (col_ids) { IGRAPH_CHECK(igraph_vector_resize(col_ids, n2)); } if (row_ids || col_ids) { for (i=0; i<no_of_nodes; i++) { if (! VECTOR(*types)[i]) { if (row_ids) { long int i2=(long int) VECTOR(perm)[i]; VECTOR(*row_ids)[i2] = i; } } else { if (col_ids) { long int i2=(long int) VECTOR(perm)[i]; VECTOR(*col_ids)[i2-n1] = i; } } } } igraph_vector_destroy(&perm); IGRAPH_FINALLY_CLEAN(1); return 0; }
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 igraph_layout_fruchterman_reingold_3d(const igraph_t *graph, igraph_matrix_t *res, igraph_bool_t use_seed, igraph_integer_t niter, igraph_real_t start_temp, const igraph_vector_t *weight, const igraph_vector_t *minx, const igraph_vector_t *maxx, const igraph_vector_t *miny, const igraph_vector_t *maxy, const igraph_vector_t *minz, const igraph_vector_t *maxz) { igraph_integer_t no_nodes=igraph_vcount(graph); igraph_integer_t no_edges=igraph_ecount(graph); igraph_integer_t i; igraph_vector_float_t dispx, dispy, dispz; igraph_real_t temp=start_temp; igraph_real_t difftemp=start_temp / niter; float width=sqrtf(no_nodes), height=width, depth=width; igraph_bool_t conn=1; float C; if (niter < 0) { IGRAPH_ERROR("Number of iterations must be non-negative in " "Fruchterman-Reingold layout", IGRAPH_EINVAL); } if (use_seed && (igraph_matrix_nrow(res) != no_nodes || igraph_matrix_ncol(res) != 3)) { IGRAPH_ERROR("Invalid start position matrix size in " "Fruchterman-Reingold layout", IGRAPH_EINVAL); } if (weight && igraph_vector_size(weight) != igraph_ecount(graph)) { IGRAPH_ERROR("Invalid weight vector length", IGRAPH_EINVAL); } if (minx && igraph_vector_size(minx) != no_nodes) { IGRAPH_ERROR("Invalid minx vector length", IGRAPH_EINVAL); } if (maxx && igraph_vector_size(maxx) != no_nodes) { IGRAPH_ERROR("Invalid maxx vector length", IGRAPH_EINVAL); } if (minx && maxx && !igraph_vector_all_le(minx, maxx)) { IGRAPH_ERROR("minx must not be greater than maxx", IGRAPH_EINVAL); } if (miny && igraph_vector_size(miny) != no_nodes) { IGRAPH_ERROR("Invalid miny vector length", IGRAPH_EINVAL); } if (maxy && igraph_vector_size(maxy) != no_nodes) { IGRAPH_ERROR("Invalid maxy vector length", IGRAPH_EINVAL); } if (miny && maxy && !igraph_vector_all_le(miny, maxy)) { IGRAPH_ERROR("miny must not be greater than maxy", IGRAPH_EINVAL); } if (minz && igraph_vector_size(minz) != no_nodes) { IGRAPH_ERROR("Invalid minz vector length", IGRAPH_EINVAL); } if (maxz && igraph_vector_size(maxz) != no_nodes) { IGRAPH_ERROR("Invalid maxz vector length", IGRAPH_EINVAL); } if (minz && maxz && !igraph_vector_all_le(minz, maxz)) { IGRAPH_ERROR("minz must not be greater than maxz", IGRAPH_EINVAL); } igraph_is_connected(graph, &conn, IGRAPH_WEAK); if (!conn) { C = no_nodes * sqrtf(no_nodes); } RNG_BEGIN(); if (!use_seed) { IGRAPH_CHECK(igraph_matrix_resize(res, no_nodes, 3)); for (i=0; i<no_nodes; i++) { igraph_real_t x1=minx ? VECTOR(*minx)[i] : -width/2; igraph_real_t x2=maxx ? VECTOR(*maxx)[i] : width/2; igraph_real_t y1=miny ? VECTOR(*miny)[i] : -height/2; igraph_real_t y2=maxy ? VECTOR(*maxy)[i] : height/2; igraph_real_t z1=minz ? VECTOR(*minz)[i] : -depth/2; igraph_real_t z2=maxz ? VECTOR(*maxz)[i] : depth/2; MATRIX(*res, i, 0) = RNG_UNIF(x1, x2); MATRIX(*res, i, 1) = RNG_UNIF(y1, y2); MATRIX(*res, i, 2) = RNG_UNIF(z1, z2); } } IGRAPH_CHECK(igraph_vector_float_init(&dispx, no_nodes)); IGRAPH_FINALLY(igraph_vector_float_destroy, &dispx); IGRAPH_CHECK(igraph_vector_float_init(&dispy, no_nodes)); IGRAPH_FINALLY(igraph_vector_float_destroy, &dispy); IGRAPH_CHECK(igraph_vector_float_init(&dispz, no_nodes)); IGRAPH_FINALLY(igraph_vector_float_destroy, &dispz); for (i=0; i<niter; i++) { igraph_integer_t v, u, e; /* calculate repulsive forces, we have a special version for unconnected graphs */ igraph_vector_float_null(&dispx); igraph_vector_float_null(&dispy); igraph_vector_float_null(&dispz); if (conn) { for (v=0; v<no_nodes; v++) { for (u=v+1; u<no_nodes; u++) { float dx=MATRIX(*res, v, 0) - MATRIX(*res, u, 0); float dy=MATRIX(*res, v, 1) - MATRIX(*res, u, 1); float dz=MATRIX(*res, v, 2) - MATRIX(*res, u, 2); float dlen=dx * dx + dy * dy + dz * dz; if (dlen == 0) { dx = RNG_UNIF01() * 1e-9; dy = RNG_UNIF01() * 1e-9; dz = RNG_UNIF01() * 1e-9; dlen = dx * dx + dy * dy + dz * dz; } VECTOR(dispx)[v] += dx/dlen; VECTOR(dispy)[v] += dy/dlen; VECTOR(dispz)[v] += dz/dlen; VECTOR(dispx)[u] -= dx/dlen; VECTOR(dispy)[u] -= dy/dlen; VECTOR(dispz)[u] -= dz/dlen; } } } else { for (v=0; v<no_nodes; v++) { for (u=v+1; u<no_nodes; u++) { float dx=MATRIX(*res, v, 0) - MATRIX(*res, u, 0); float dy=MATRIX(*res, v, 1) - MATRIX(*res, u, 1); float dz=MATRIX(*res, v, 2) - MATRIX(*res, u, 2); float dlen, rdlen; dlen=dx * dx + dy * dy + dz * dz; if (dlen == 0) { dx = RNG_UNIF01() * 1e-9; dy = RNG_UNIF01() * 1e-9; dz = RNG_UNIF01() * 1e-9; dlen = dx * dx + dy * dy + dz * dz; } rdlen=sqrt(dlen); VECTOR(dispx)[v] += dx * (C-dlen * rdlen) / (dlen*C); VECTOR(dispy)[v] += dy * (C-dlen * rdlen) / (dlen*C); VECTOR(dispy)[v] += dz * (C-dlen * rdlen) / (dlen*C); VECTOR(dispx)[u] -= dx * (C-dlen * rdlen) / (dlen*C); VECTOR(dispy)[u] -= dy * (C-dlen * rdlen) / (dlen*C); VECTOR(dispz)[u] -= dz * (C-dlen * rdlen) / (dlen*C); } } } /* calculate attractive forces */ for (e=0; e<no_edges; e++) { /* each edges is an ordered pair of vertices v and u */ igraph_integer_t v=IGRAPH_FROM(graph, e); igraph_integer_t u=IGRAPH_TO(graph, e); igraph_real_t dx=MATRIX(*res, v, 0) - MATRIX(*res, u, 0); igraph_real_t dy=MATRIX(*res, v, 1) - MATRIX(*res, u, 1); igraph_real_t dz=MATRIX(*res, v, 2) - MATRIX(*res, u, 2); igraph_real_t w=weight ? VECTOR(*weight)[e] : 1.0; igraph_real_t dlen=sqrt(dx * dx + dy * dy + dz * dz) * w; VECTOR(dispx)[v] -= (dx * dlen); VECTOR(dispy)[v] -= (dy * dlen); VECTOR(dispz)[v] -= (dz * dlen); VECTOR(dispx)[u] += (dx * dlen); VECTOR(dispy)[u] += (dy * dlen); VECTOR(dispz)[u] += (dz * dlen); } /* limit max displacement to temperature t and prevent from displacement outside frame */ for (v=0; v<no_nodes; v++) { igraph_real_t dx=VECTOR(dispx)[v] + RNG_UNIF01() * 1e-9; igraph_real_t dy=VECTOR(dispy)[v] + RNG_UNIF01() * 1e-9; igraph_real_t dz=VECTOR(dispz)[v] + RNG_UNIF01() * 1e-9; igraph_real_t displen=sqrt(dx * dx + dy * dy + dz * dz); igraph_real_t mx=fabs(dx) < temp ? dx : temp; igraph_real_t my=fabs(dy) < temp ? dy : temp; igraph_real_t mz=fabs(dz) < temp ? dz : temp; if (displen > 0) { MATRIX(*res, v, 0) += (dx / displen) * mx; MATRIX(*res, v, 1) += (dy / displen) * my; MATRIX(*res, v, 2) += (dz / displen) * mz; } if (minx && MATRIX(*res, v, 0) < VECTOR(*minx)[v]) { MATRIX(*res, v, 0) = VECTOR(*minx)[v]; } if (maxx && MATRIX(*res, v, 0) > VECTOR(*maxx)[v]) { MATRIX(*res, v, 0) = VECTOR(*maxx)[v]; } if (miny && MATRIX(*res, v, 1) < VECTOR(*miny)[v]) { MATRIX(*res, v, 1) = VECTOR(*miny)[v]; } if (maxy && MATRIX(*res, v, 1) > VECTOR(*maxy)[v]) { MATRIX(*res, v, 1) = VECTOR(*maxy)[v]; } if (minz && MATRIX(*res, v, 2) < VECTOR(*minz)[v]) { MATRIX(*res, v, 2) = VECTOR(*minz)[v]; } if (maxz && MATRIX(*res, v, 2) > VECTOR(*maxz)[v]) { MATRIX(*res, v, 2) = VECTOR(*maxz)[v]; } } temp -= difftemp; } RNG_END(); igraph_vector_float_destroy(&dispx); igraph_vector_float_destroy(&dispy); igraph_vector_float_destroy(&dispz); IGRAPH_FINALLY_CLEAN(3); return 0; }
int igraph_layout_gem(const igraph_t *graph, igraph_matrix_t *res, igraph_bool_t use_seed, igraph_integer_t maxiter, igraph_real_t temp_max, igraph_real_t temp_min, igraph_real_t temp_init) { igraph_integer_t no_nodes = igraph_vcount(graph); igraph_vector_int_t perm; igraph_vector_float_t impulse_x, impulse_y, temp, skew_gauge; igraph_integer_t i; float temp_global; igraph_integer_t perm_pointer = 0; float barycenter_x = 0.0, barycenter_y = 0.0; igraph_vector_t phi; igraph_vector_t neis; const float elen_des2 = 128 * 128; const float gamma = 1/16.0; const float alpha_o = M_PI; const float alpha_r = M_PI / 3.0; const float sigma_o = 1.0 / 3.0; const float sigma_r = 1.0 / 2.0 / no_nodes; if (maxiter < 0) { IGRAPH_ERROR("Number of iterations must be non-negative in GEM layout", IGRAPH_EINVAL); } if (use_seed && (igraph_matrix_nrow(res) != no_nodes || igraph_matrix_ncol(res) != 2)) { IGRAPH_ERROR("Invalid start position matrix size in GEM layout", IGRAPH_EINVAL); } if (temp_max <= 0) { IGRAPH_ERROR("Maximum temperature should be positive in GEM layout", IGRAPH_EINVAL); } if (temp_min <= 0) { IGRAPH_ERROR("Minimum temperature should be positive in GEM layout", IGRAPH_EINVAL); } if (temp_init <= 0) { IGRAPH_ERROR("Initial temperature should be positive in GEM layout", IGRAPH_EINVAL); } if (temp_max < temp_init || temp_init < temp_min) { IGRAPH_ERROR("Minimum <= Initial <= Maximum temperature is required " "in GEM layout", IGRAPH_EINVAL); } if (no_nodes == 0) { return 0; } IGRAPH_CHECK(igraph_vector_float_init(&impulse_x, no_nodes)); IGRAPH_FINALLY(igraph_vector_float_destroy, &impulse_x); IGRAPH_CHECK(igraph_vector_float_init(&impulse_y, no_nodes)); IGRAPH_FINALLY(igraph_vector_float_destroy, &impulse_y); IGRAPH_CHECK(igraph_vector_float_init(&temp, no_nodes)); IGRAPH_FINALLY(igraph_vector_float_destroy, &temp); IGRAPH_CHECK(igraph_vector_float_init(&skew_gauge, no_nodes)); IGRAPH_FINALLY(igraph_vector_float_destroy, &skew_gauge); IGRAPH_CHECK(igraph_vector_int_init_seq(&perm, 0, no_nodes-1)); IGRAPH_FINALLY(igraph_vector_int_destroy, &perm); IGRAPH_VECTOR_INIT_FINALLY(&phi, no_nodes); IGRAPH_VECTOR_INIT_FINALLY(&neis, 10); RNG_BEGIN(); /* Initialization */ igraph_degree(graph, &phi, igraph_vss_all(), IGRAPH_ALL, IGRAPH_LOOPS); if (!use_seed) { const igraph_real_t width_half=no_nodes*100, height_half=width_half; IGRAPH_CHECK(igraph_matrix_resize(res, no_nodes, 2)); for (i=0; i<no_nodes; i++) { MATRIX(*res, i, 0) = RNG_UNIF(-width_half, width_half); MATRIX(*res, i, 1) = RNG_UNIF(-height_half, height_half); barycenter_x += MATRIX(*res, i, 0); barycenter_y += MATRIX(*res, i, 1); VECTOR(phi)[i] *= (VECTOR(phi)[i] / 2.0 + 1.0); } } else { for (i=0; i<no_nodes; i++) { barycenter_x += MATRIX(*res, i, 0); barycenter_y += MATRIX(*res, i, 1); VECTOR(phi)[i] *= (VECTOR(phi)[i] / 2.0 + 1.0); } } igraph_vector_float_fill(&temp, temp_init); temp_global = temp_init * no_nodes; while (temp_global > temp_min * no_nodes && maxiter > 0) { /* choose a vertex v to update */ igraph_integer_t u, v, nlen, j; float px, py, pvx, pvy; if (!perm_pointer) { igraph_vector_int_shuffle(&perm); perm_pointer=no_nodes-1; } v=VECTOR(perm)[perm_pointer--]; /* compute v's impulse */ px = (barycenter_x/no_nodes - MATRIX(*res, v, 0)) * gamma * VECTOR(phi)[v]; py = (barycenter_y/no_nodes - MATRIX(*res, v, 1)) * gamma * VECTOR(phi)[v]; px += RNG_UNIF(-32.0, 32.0); py += RNG_UNIF(-32.0, 32.0); for (u = 0; u < no_nodes; u++) { float dx, dy, dist2; if (u == v) { continue; } dx=MATRIX(*res, v, 0) - MATRIX(*res, u, 0); dy=MATRIX(*res, v, 1) - MATRIX(*res, u, 1); dist2=dx * dx + dy * dy; if (dist2 != 0) { px += dx * elen_des2 / dist2; py += dy * elen_des2 / dist2; } } IGRAPH_CHECK(igraph_neighbors(graph, &neis, v, IGRAPH_ALL)); nlen=igraph_vector_size(&neis); for (j = 0; j < nlen; j++) { igraph_integer_t u=VECTOR(neis)[j]; float dx=MATRIX(*res, v, 0) - MATRIX(*res, u, 0); float dy=MATRIX(*res, v, 1) - MATRIX(*res, u, 1); float dist2= dx * dx + dy * dy; px -= dx * dist2 / (elen_des2 * VECTOR(phi)[v]); py -= dy * dist2 / (elen_des2 * VECTOR(phi)[v]); } /* update v's position and temperature */ if (px != 0 || py != 0) { float plen = sqrtf(px * px + py * py); px *= VECTOR(temp)[v] / plen; py *= VECTOR(temp)[v] / plen; MATRIX(*res, v, 0) += px; MATRIX(*res, v, 1) += py; barycenter_x += px; barycenter_y += py; } pvx=VECTOR(impulse_x)[v]; pvy=VECTOR(impulse_y)[v]; if (pvx != 0 || pvy != 0) { float beta = atan2f(pvy - py, pvx - px); float sin_beta = sinf(beta); float sign_sin_beta = (sin_beta > 0) ? 1 : ((sin_beta < 0) ? -1 : 0); float cos_beta = cosf(beta); float abs_cos_beta = fabsf(cos_beta); float old_temp=VECTOR(temp)[v]; if (sin(beta) >= sin(M_PI_2 + alpha_r / 2.0)) { VECTOR(skew_gauge)[v] += sigma_r * sign_sin_beta; } if (abs_cos_beta >= cosf(alpha_o / 2.0)) { VECTOR(temp)[v] *= sigma_o * cos_beta; } VECTOR(temp)[v] *= (1 - fabsf(VECTOR(skew_gauge)[v])); if (VECTOR(temp)[v] > temp_max) { VECTOR(temp)[v] = temp_max; } VECTOR(impulse_x)[v] = px; VECTOR(impulse_y)[v] = py; temp_global += VECTOR(temp)[v] - old_temp; } maxiter--; } /* while temp && iter */ RNG_END(); igraph_vector_destroy(&neis); igraph_vector_destroy(&phi); igraph_vector_int_destroy(&perm); igraph_vector_float_destroy(&skew_gauge); igraph_vector_float_destroy(&temp); igraph_vector_float_destroy(&impulse_y); igraph_vector_float_destroy(&impulse_x); IGRAPH_FINALLY_CLEAN(7); return 0; }
int igraph_revolver_mes_d_d(const igraph_t *graph, igraph_lazy_inclist_t *inclist, igraph_matrix_t *kernel, igraph_matrix_t *sd, igraph_matrix_t *norm, igraph_matrix_t *cites, const igraph_matrix_t *debug, igraph_vector_ptr_t *debugres, const igraph_vector_t *st, const igraph_vector_t *vtime, const igraph_vector_t *vtimeidx, const igraph_vector_t *etime, const igraph_vector_t *etimeidx, igraph_integer_t pno_of_events, igraph_integer_t pmaxdegree) { long int no_of_nodes=igraph_vcount(graph); long int no_of_edges=igraph_ecount(graph); long int no_of_events=pno_of_events; long int maxdegree=pmaxdegree; igraph_vector_long_t degree; igraph_vector_char_t added; /* is this edge already in the network? */ igraph_matrix_t v_normfact, *normfact, v_notnull, *notnull; igraph_matrix_t ch; igraph_vector_long_t ntk; /* # of type x vertices */ igraph_matrix_t ntkk; /* # of connections between type x1, x2 vert. */ igraph_vector_t *adjedges; long int timestep, i; long int nptr=0, eptr=0; long int nptr_save, eptr_save, eptr_new; IGRAPH_CHECK(igraph_vector_long_init(°ree, no_of_nodes)); IGRAPH_FINALLY(&igraph_vector_long_destroy, °ree); IGRAPH_CHECK(igraph_vector_char_init(&added, no_of_edges)); IGRAPH_FINALLY(igraph_vector_char_destroy, &added); IGRAPH_CHECK(igraph_vector_long_init(&ntk, maxdegree+1)); IGRAPH_FINALLY(igraph_vector_long_destroy, &ntk); IGRAPH_MATRIX_INIT_FINALLY(&ntkk, maxdegree+1, maxdegree+1); IGRAPH_MATRIX_INIT_FINALLY(&ch, maxdegree+1, maxdegree+1); if (norm) { normfact=norm; IGRAPH_CHECK(igraph_matrix_resize(normfact, maxdegree+1, maxdegree+1)); igraph_matrix_null(normfact); } else { normfact=&v_normfact; IGRAPH_MATRIX_INIT_FINALLY(normfact, maxdegree+1, maxdegree+1); } if (cites) { notnull=cites; IGRAPH_CHECK(igraph_matrix_resize(notnull, maxdegree+1, maxdegree+1)); igraph_matrix_null(notnull); } else { notnull=&v_notnull; IGRAPH_MATRIX_INIT_FINALLY(notnull, maxdegree+1, maxdegree+1); } IGRAPH_CHECK(igraph_matrix_resize(kernel, maxdegree+1, maxdegree+1)); igraph_matrix_null(kernel); if (sd) { IGRAPH_CHECK(igraph_matrix_resize(sd, maxdegree+1, maxdegree+1)); igraph_matrix_null(sd); } for (timestep=0; timestep<no_of_events; timestep++) { IGRAPH_ALLOW_INTERRUPTION(); /* Add the vertices in the first */ nptr_save=nptr; while (nptr < no_of_nodes && VECTOR(*vtime)[(long int)VECTOR(*vtimeidx)[nptr]]==timestep) { nptr++; } VECTOR(ntk)[0] += (nptr-nptr_save); /* Update ch accordingly, could be done later as well */ if (VECTOR(ntk)[0] == nptr-nptr_save && nptr!=nptr_save) { if (nptr-nptr_save >= 2) { MATRIX(ch, 0, 0) = eptr; } for (i=1; i<maxdegree+1; i++) { if (NTKK(0,i) == (nptr-nptr_save)*VECTOR(ntk)[i]) { MATRIX(ch, 0, i) = MATRIX(ch, i, 0) = eptr; } } } /* Estimate Akk */ eptr_save=eptr; while (eptr < no_of_edges && VECTOR(*etime)[(long int)VECTOR(*etimeidx)[eptr] ] == timestep) { long int edge=(long int) VECTOR(*etimeidx)[eptr]; long int from=IGRAPH_FROM(graph, edge), to=IGRAPH_TO(graph, edge); long int xidx=VECTOR(degree)[from]; long int yidx=VECTOR(degree)[to]; double xk, oldakk; MATRIX(*notnull, xidx, yidx) += 1; MATRIX(*notnull, yidx, xidx) = MATRIX(*notnull, xidx, yidx); xk=VECTOR(*st)[timestep]/NTKK(xidx, yidx); oldakk=MATRIX(*kernel, xidx, yidx); MATRIX(*kernel, xidx, yidx) += (xk-oldakk)/MATRIX(*notnull, xidx, yidx); MATRIX(*kernel, yidx, xidx) = MATRIX(*kernel, xidx, yidx); if (sd) { MATRIX(*sd, xidx, yidx) += (xk-oldakk)*(xk-MATRIX(*kernel, xidx, yidx)); MATRIX(*sd, yidx, xidx) = MATRIX(*sd, xidx, yidx); } /* TODO: debug */ eptr++; } /* Update ntkk, ntk, ch, normfact, add the edges */ eptr_new=eptr; eptr=eptr_save; while (eptr < no_of_edges && VECTOR(*etime)[(long int) VECTOR(*etimeidx)[eptr] ] == timestep) { long int edge=(long int) VECTOR(*etimeidx)[eptr]; long int from=IGRAPH_FROM(graph, edge); long int to=IGRAPH_TO(graph, edge); long int xidx=VECTOR(degree)[from]; long int yidx=VECTOR(degree)[to]; long int n; adjedges=igraph_lazy_inclist_get(inclist, (igraph_integer_t) from); n=igraph_vector_size(adjedges); for (i=0; i<n; i++) { long int edge=(long int) VECTOR(*adjedges)[i]; if (VECTOR(added)[edge]) { long int otherv=IGRAPH_OTHER(graph, edge, from); /* other than from */ long int deg=VECTOR(degree)[otherv]; MATRIX(ntkk, xidx, deg) -= 1; MATRIX(ntkk, deg, xidx) = MATRIX(ntkk, xidx, deg); if (NTKK(xidx, deg)==1) { MATRIX(ch, deg, xidx) = eptr_new; MATRIX(ch, xidx, deg) = MATRIX(ch, deg, xidx); } MATRIX(ntkk, xidx+1, deg) += 1; MATRIX(ntkk, deg, xidx+1) = MATRIX(ntkk, xidx+1, deg); if (NTKK(xidx+1, deg)==0) { MATRIX(*normfact, xidx+1, deg) += eptr_new-MATRIX(ch, xidx+1, deg); MATRIX(*normfact, deg, xidx+1) = MATRIX(*normfact, xidx+1, deg); } } } adjedges=igraph_lazy_inclist_get(inclist, (igraph_integer_t) to); n=igraph_vector_size(adjedges); for (i=0; i<n; i++) { long int edge=(long int) VECTOR(*adjedges)[i]; if (VECTOR(added)[edge]) { long int otherv=IGRAPH_OTHER(graph, edge, to); /* other than to */ long int deg=VECTOR(degree)[otherv]; MATRIX(ntkk, yidx, deg) -= 1; MATRIX(ntkk, deg, yidx) = MATRIX(ntkk, yidx, deg); if (NTKK(yidx, deg)==1) { MATRIX(ch, deg, yidx) = eptr_new; MATRIX(ch, yidx, deg) = MATRIX(ch, deg, yidx); } MATRIX(ntkk, yidx+1, deg) += 1; MATRIX(ntkk, deg, yidx+1) = MATRIX(ntkk, yidx+1, deg); if (NTKK(yidx+1, deg)==0) { MATRIX(*normfact, yidx+1, deg) += eptr_new-MATRIX(ch, yidx+1, deg); MATRIX(*normfact, deg, yidx+1) = MATRIX(*normfact, yidx+1, deg); } } } VECTOR(added)[edge]=1; MATRIX(ntkk, xidx+1, yidx+1) += 1; MATRIX(ntkk, yidx+1, xidx+1) = MATRIX(ntkk, xidx+1, yidx+1); if (NTKK(xidx+1, yidx+1)==0) { MATRIX(*normfact, xidx+1, yidx+1) = eptr_new-MATRIX(ch, xidx+1, yidx+1); MATRIX(*normfact, yidx+1, xidx+1) = MATRIX(*normfact, xidx+1, yidx+1); } for (i=0; i<maxdegree+1; i++) { long int before, after; before=(long int) NTKK(xidx,i); VECTOR(ntk)[xidx] -= 1; after=(long int) NTKK(xidx,i); VECTOR(ntk)[xidx] += 1; if (before > 0 && after==0) { MATRIX(*normfact, xidx, i) += eptr_new-MATRIX(ch, xidx, i); MATRIX(*normfact, i, xidx) = MATRIX(*normfact, xidx, i); } } VECTOR(ntk)[xidx]--; for (i=0; i<maxdegree+1; i++) { long int before, after; before=(long int) NTKK(yidx, i); VECTOR(ntk)[yidx] -= 1; after=(long int) NTKK(yidx, i); VECTOR(ntk)[yidx] += 1; if (before > 0 && after==0) { MATRIX(*normfact, yidx, i) += eptr_new-MATRIX(ch, yidx, i); MATRIX(*normfact, i, yidx) = MATRIX(*normfact, yidx, i); } } VECTOR(ntk)[yidx]--; for (i=0; i<maxdegree+1; i++) { long int before, after; before=(long int) NTKK(xidx+1, i); VECTOR(ntk)[xidx+1] += 1; after=(long int) NTKK(xidx+1, i); VECTOR(ntk)[xidx+1] -= 1; if (before==0 && after > 0) { MATRIX(ch, xidx+1, i) = eptr_new; MATRIX(ch, i, xidx+1) = MATRIX(ch, xidx+1, i); } } VECTOR(ntk)[xidx+1]++; for (i=0; i<maxdegree+1; i++) { long int before, after; before=(long int) NTKK(yidx+1, i); VECTOR(ntk)[yidx+1] += 1; after=(long int) NTKK(yidx+1, i); VECTOR(ntk)[yidx+1] -= 1; if (before == 0 && after == 0) { MATRIX(ch, yidx+1, i) = eptr_new; MATRIX(ch, i, yidx+1) = MATRIX(ch, yidx+1, i); } } VECTOR(ntk)[yidx+1]++; VECTOR(degree)[from]++; VECTOR(degree)[to]++; eptr++; } } for (i=0; i<maxdegree+1; i++) { igraph_real_t oldakk; long int j; for (j=0; j<=i; j++) { if (NTKK(i, j) != 0) { MATRIX(*normfact, i, j) += (eptr-MATRIX(ch, i, j)); MATRIX(*normfact, j, i) = MATRIX(*normfact, i, j); } if (MATRIX(*normfact, i, j)==0) { MATRIX(*kernel, i, j)=MATRIX(*kernel, j, i)=0; MATRIX(*normfact, i, j)=MATRIX(*normfact, j, i)=1; } oldakk=MATRIX(*kernel, i, j); MATRIX(*kernel, i, j) *= MATRIX(*notnull, i, j)/MATRIX(*normfact, i, j); MATRIX(*kernel, j, i) = MATRIX(*kernel, i, j); if (sd) { MATRIX(*sd, i, j) += oldakk * oldakk * MATRIX(*notnull, i, j) * (1-MATRIX(*notnull, i, j)/MATRIX(*normfact, i, j)); MATRIX(*sd, i, j) = sqrt(MATRIX(*sd, i, j)/(MATRIX(*normfact, i, j)-1)); MATRIX(*sd, j, i) = MATRIX(*sd, i, j); } } } if (!cites) { igraph_matrix_destroy(notnull); IGRAPH_FINALLY_CLEAN(1); } if (!norm) { igraph_matrix_destroy(normfact); IGRAPH_FINALLY_CLEAN(1); } igraph_matrix_destroy(&ch); igraph_matrix_destroy(&ntkk); igraph_vector_long_destroy(&ntk); igraph_vector_char_destroy(&added); igraph_vector_long_destroy(°ree); IGRAPH_FINALLY_CLEAN(5); return 0; }
/** * \ingroup nongraph * \function igraph_convex_hull * \brief Determines the convex hull of a given set of points in the 2D plane * * </para><para> * The convex hull is determined by the Graham scan algorithm. * See the following reference for details: * * </para><para> * Thomas H. Cormen, Charles E. Leiserson, Ronald L. Rivest, and Clifford * Stein. Introduction to Algorithms, Second Edition. MIT Press and * McGraw-Hill, 2001. ISBN 0262032937. Pages 949-955 of section 33.3: * Finding the convex hull. * * \param data vector containing the coordinates. The length of the * vector must be even, since it contains X-Y coordinate pairs. * \param resverts the vector containing the result, e.g. the vector of * vertex indices used as the corners of the convex hull. Supply * \c NULL here if you are only interested in the coordinates of * the convex hull corners. * \param rescoords the matrix containing the coordinates of the selected * corner vertices. Supply \c NULL here if you are only interested in * the vertex indices. * \return Error code: * \c IGRAPH_ENOMEM: not enough memory * * Time complexity: O(n log(n)) where n is the number of vertices */ int igraph_convex_hull(const igraph_matrix_t *data, igraph_vector_t *resverts, igraph_matrix_t *rescoords) { igraph_integer_t no_of_nodes; long int i, pivot_idx=0, last_idx, before_last_idx, next_idx, j; igraph_real_t* angles; igraph_vector_t stack; igraph_indheap_t order; igraph_real_t px, py, cp; no_of_nodes=igraph_matrix_nrow(data); if (igraph_matrix_ncol(data) != 2) { IGRAPH_ERROR("matrix must have 2 columns", IGRAPH_EINVAL); } if (no_of_nodes == 0) { if (resverts != 0) { IGRAPH_CHECK(igraph_vector_resize(resverts, 0)); } if (rescoords != 0) { IGRAPH_CHECK(igraph_matrix_resize(rescoords, 0, 2)); } /**************************** this is an exit here *********/ return 0; } angles=igraph_Calloc(no_of_nodes, igraph_real_t); if (!angles) IGRAPH_ERROR("not enough memory for angle array", IGRAPH_ENOMEM); IGRAPH_FINALLY(free, angles); IGRAPH_VECTOR_INIT_FINALLY(&stack, 0); /* Search for the pivot vertex */ for (i=1; i<no_of_nodes; i++) { if (MATRIX(*data, i, 1)<MATRIX(*data, pivot_idx, 1)) pivot_idx=i; else if (MATRIX(*data, i, 1) == MATRIX(*data, pivot_idx, 1) && MATRIX(*data, i, 0) < MATRIX(*data, pivot_idx, 0)) pivot_idx=i; } px=MATRIX(*data, pivot_idx, 0); py=MATRIX(*data, pivot_idx, 1); /* Create angle array */ for (i=0; i<no_of_nodes; i++) { if (i == pivot_idx) { /* We can't calculate the angle of the pivot point with itself, * so we use 10 here. This way, after sorting the angle vector, * the pivot point will always be the first one, since the range * of atan2 is -3.14..3.14 */ angles[i] = 10; } else { angles[i] = atan2(MATRIX(*data, i, 1)-py, MATRIX(*data, i, 0)-px); } } IGRAPH_CHECK(igraph_indheap_init_array(&order, angles, no_of_nodes)); IGRAPH_FINALLY(igraph_indheap_destroy, &order); igraph_Free(angles); IGRAPH_FINALLY_CLEAN(1); if (no_of_nodes == 1) { IGRAPH_CHECK(igraph_vector_push_back(&stack, 0)); igraph_indheap_delete_max(&order); } else { /* Do the trick */ IGRAPH_CHECK(igraph_vector_push_back(&stack, igraph_indheap_max_index(&order)-1)); igraph_indheap_delete_max(&order); IGRAPH_CHECK(igraph_vector_push_back(&stack, igraph_indheap_max_index(&order)-1)); igraph_indheap_delete_max(&order); j=2; while (!igraph_indheap_empty(&order)) { /* Determine whether we are at a left or right turn */ last_idx=VECTOR(stack)[j-1]; before_last_idx=VECTOR(stack)[j-2]; next_idx=(long)igraph_indheap_max_index(&order)-1; igraph_indheap_delete_max(&order); cp=(MATRIX(*data, last_idx, 0)-MATRIX(*data, before_last_idx, 0))* (MATRIX(*data, next_idx, 1)-MATRIX(*data, before_last_idx, 1))- (MATRIX(*data, next_idx, 0)-MATRIX(*data, before_last_idx, 0))* (MATRIX(*data, last_idx, 1)-MATRIX(*data, before_last_idx, 1)); /* printf("B L N cp: %d, %d, %d, %f [", before_last_idx, last_idx, next_idx, (float)cp); for (k=0; k<j; k++) printf("%ld ", (long)VECTOR(stack)[k]); printf("]\n"); */ if (cp == 0) { /* The last three points are collinear. Replace the last one in * the stack to the newest one */ VECTOR(stack)[j-1]=next_idx; } else if (cp < 0) { /* We are turning into the right direction */ IGRAPH_CHECK(igraph_vector_push_back(&stack, next_idx)); j++; } else { /* No, skip back until we're okay */ while (cp >= 0 && j > 2) { igraph_vector_pop_back(&stack); j--; last_idx=VECTOR(stack)[j-1]; before_last_idx=VECTOR(stack)[j-2]; cp=(MATRIX(*data, last_idx, 0)-MATRIX(*data, before_last_idx, 0))* (MATRIX(*data, next_idx, 1)-MATRIX(*data, before_last_idx, 1))- (MATRIX(*data, next_idx, 0)-MATRIX(*data, before_last_idx, 0))* (MATRIX(*data, last_idx, 1)-MATRIX(*data, before_last_idx, 1)); } IGRAPH_CHECK(igraph_vector_push_back(&stack, next_idx)); j++; } } } /* Create result vector */ if (resverts != 0) { igraph_vector_clear(resverts); IGRAPH_CHECK(igraph_vector_append(resverts, &stack)); } if (rescoords != 0) { igraph_matrix_select_rows(data, rescoords, &stack); } /* Free everything */ igraph_vector_destroy(&stack); igraph_indheap_destroy(&order); IGRAPH_FINALLY_CLEAN(2); return 0; }
int igraph_revolver_mes_p_p(const igraph_t *graph, igraph_lazy_inclist_t *inclist, igraph_matrix_t *kernel, igraph_matrix_t *sd, igraph_matrix_t *norm, igraph_matrix_t *cites, const igraph_matrix_t *debug, igraph_vector_ptr_t *debugres, const igraph_vector_t *st, const igraph_vector_t *vtime, const igraph_vector_t *vtimeidx, const igraph_vector_t *etime, const igraph_vector_t *etimeidx, igraph_integer_t pno_of_events, const igraph_vector_t *authors, const igraph_vector_t *eventsizes, igraph_integer_t pmaxpapers) { long int no_of_nodes=igraph_vcount(graph); long int no_of_edges=igraph_ecount(graph); long int no_of_events=pno_of_events; long int maxpapers=pmaxpapers; igraph_vector_long_t papers; igraph_vector_char_t added; igraph_matrix_t v_normfact, *normfact, v_notnull, *notnull; igraph_matrix_t ch; igraph_vector_long_t ntk; igraph_matrix_t ntkk; igraph_vector_t *adjedges; long int timestep, i; long int nptr=0, eptr=0, aptr=0; long int nptr_save, eptr_save, eptr_new; IGRAPH_CHECK(igraph_vector_long_init(&papers, no_of_nodes)); IGRAPH_FINALLY(&igraph_vector_long_destroy, &papers); IGRAPH_CHECK(igraph_vector_char_init(&added, no_of_edges)); IGRAPH_FINALLY(igraph_vector_char_destroy, &added); IGRAPH_CHECK(igraph_vector_long_init(&ntk, maxpapers+1)); IGRAPH_FINALLY(igraph_vector_long_destroy, &ntk); IGRAPH_MATRIX_INIT_FINALLY(&ntkk, maxpapers+1, maxpapers+1); IGRAPH_MATRIX_INIT_FINALLY(&ch, maxpapers+1, maxpapers+1); if (norm) { normfact=norm; IGRAPH_CHECK(igraph_matrix_resize(normfact, maxpapers+1, maxpapers+1)); igraph_matrix_null(normfact); } else { normfact=&v_normfact; IGRAPH_MATRIX_INIT_FINALLY(normfact, maxpapers+1, maxpapers+1); } if (cites) { notnull=cites; IGRAPH_CHECK(igraph_matrix_resize(notnull, maxpapers+1, maxpapers+1)); igraph_matrix_null(notnull); } else { notnull=&v_notnull; IGRAPH_MATRIX_INIT_FINALLY(notnull, maxpapers+1, maxpapers+1); } IGRAPH_CHECK(igraph_matrix_resize(kernel, maxpapers+1, maxpapers+1)); igraph_matrix_null(kernel); if (sd) { IGRAPH_CHECK(igraph_matrix_resize(sd, maxpapers+1, maxpapers+1)); igraph_matrix_null(sd); } for (timestep=0; timestep<no_of_events; timestep++) { IGRAPH_ALLOW_INTERRUPTION(); nptr_save=nptr; while (nptr < no_of_nodes && VECTOR(*vtime)[(long int)VECTOR(*vtimeidx)[nptr]]==timestep) { nptr++; } /* If it is a new author then she has no papers yet */ VECTOR(ntk)[0] += (nptr-nptr_save); /* Update ch accordingly, could be done later as well */ if (VECTOR(ntk)[0] == nptr-nptr_save && nptr!=nptr_save) { if (nptr-nptr_save >= 2) { MATRIX(ch, 0, 0) = eptr; } for (i=1; i<maxpapers+1; i++) { if (NTKK(0,i) == (nptr-nptr_save)*VECTOR(ntk)[i]) { MATRIX(ch, 0, i) = MATRIX(ch, i, 0) = eptr; } } } /* print_ntkk(&ntkk, &ntk); */ /* Estimate Akk */ eptr_save=eptr; while (eptr < no_of_edges && VECTOR(*etime)[(long int)VECTOR(*etimeidx)[eptr] ] == timestep) { long int edge=(long int) VECTOR(*etimeidx)[eptr]; long int from=IGRAPH_FROM(graph, edge), to=IGRAPH_TO(graph, edge); long int xidx=VECTOR(papers)[from]; long int yidx=VECTOR(papers)[to]; double xk, oldakk; MATRIX(*notnull, xidx, yidx) += 1; MATRIX(*notnull, yidx, xidx) = MATRIX(*notnull, xidx, yidx); xk=VECTOR(*st)[timestep]/NTKK(xidx, yidx); oldakk=MATRIX(*kernel, xidx, yidx); MATRIX(*kernel, xidx, yidx) += (xk-oldakk)/MATRIX(*notnull, xidx, yidx); MATRIX(*kernel, yidx, xidx) = MATRIX(*kernel, xidx, yidx); if (sd) { MATRIX(*sd, xidx, yidx) += (xk-oldakk)*(xk-MATRIX(*kernel, xidx, yidx)); MATRIX(*sd, yidx, xidx) = MATRIX(*sd, xidx, yidx); } /* TODO: debug */ eptr++; } /* update ntkk, the new papers change the type of their authors */ eptr_new=eptr; for (i=aptr; i<aptr+VECTOR(*eventsizes)[timestep]; i++) { long int aut=(long int) VECTOR(*authors)[i]; long int pap=VECTOR(papers)[aut]; long int j, n; adjedges=igraph_lazy_inclist_get(inclist, (igraph_integer_t) aut); n=igraph_vector_size(adjedges); for (j=0; j<n; j++) { long int edge=(long int) VECTOR(*adjedges)[j]; if (VECTOR(added)[edge]) { long int otherv=IGRAPH_OTHER(graph, edge, aut); long int otherpap=VECTOR(papers)[otherv]; MATRIX(ntkk, pap, otherpap) -= 1; MATRIX(ntkk, otherpap, pap) = MATRIX(ntkk, pap, otherpap); if (NTKK(pap, otherpap)==1) { MATRIX(ch, pap, otherpap) = eptr_new; MATRIX(ch, otherpap, pap) = MATRIX(ch, pap, otherpap); } MATRIX(ntkk, pap+1, otherpap) += 1; MATRIX(ntkk, otherpap, pap+1) = MATRIX(ntkk, pap+1, otherpap); if (NTKK(pap+1, otherpap)==0) { MATRIX(*normfact, pap+1, otherpap) += eptr_new-MATRIX(ch, pap+1, otherpap); MATRIX(*normfact, otherpap, pap+1) = MATRIX(*normfact, pap+1, otherpap); } } } /* update ntk too */ for (j=0; j<maxpapers+1; j++) { long int before, after; before=(long int) NTKK(pap, j); VECTOR(ntk)[pap]-=1; after=(long int) NTKK(pap, j); VECTOR(ntk)[pap]+=1; if (before > 0 && after==0) { MATRIX(*normfact, pap, j) += eptr_new-MATRIX(ch, pap, j); MATRIX(*normfact, j, pap) = MATRIX(*normfact, pap, j); } } VECTOR(ntk)[pap]-=1; for (j=0; j<maxpapers+1; j++) { long int before, after; before=(long int) NTKK(pap+1, j); VECTOR(ntk)[pap+1] += 1; after=(long int) NTKK(pap+1, j); VECTOR(ntk)[pap+1] -= 1; if (before == 0 && after > 0) { MATRIX(ch, pap+1, j) = eptr_new; MATRIX(ch, j, pap+1) = MATRIX(ch, pap+1, j); } } VECTOR(ntk)[pap+1]+=1; VECTOR(papers)[aut] += 1; } aptr += VECTOR(*eventsizes)[timestep]; /* For every new edge, we lose one connection possibility, also add the edges*/ eptr=eptr_save; while (eptr < no_of_edges && VECTOR(*etime)[(long int) VECTOR(*etimeidx)[eptr] ] == timestep) { long int edge=(long int) VECTOR(*etimeidx)[eptr]; long int from=IGRAPH_FROM(graph, edge), to=IGRAPH_TO(graph, edge); long int xidx=VECTOR(papers)[from]; long int yidx=VECTOR(papers)[to]; MATRIX(ntkk, xidx, yidx) += 1; MATRIX(ntkk, yidx, xidx) = MATRIX(ntkk, xidx, yidx); if (NTKK(xidx, yidx)==0) { MATRIX(*normfact, xidx, yidx) += eptr_new-MATRIX(ch, xidx, yidx); MATRIX(*normfact, yidx, xidx) = MATRIX(*normfact, xidx, yidx); } VECTOR(added)[edge]=1; eptr++; } } for (i=0; i<maxpapers+1; i++) { igraph_real_t oldakk; long int j; for (j=0; j<=i; j++) { if (NTKK(i, j) != 0) { MATRIX(*normfact, i, j) += (eptr-MATRIX(ch, i, j)); MATRIX(*normfact, j, i) = MATRIX(*normfact, i, j); } if (MATRIX(*normfact, i, j)==0) { MATRIX(*kernel, i, j)=MATRIX(*kernel, j, i)=0; MATRIX(*normfact, i, j)=MATRIX(*normfact, j, i)=1; } oldakk=MATRIX(*kernel, i, j); MATRIX(*kernel, i, j) *= MATRIX(*notnull, i, j)/MATRIX(*normfact, i, j); MATRIX(*kernel, j, i) = MATRIX(*kernel, i, j); if (sd) { MATRIX(*sd, i, j) += oldakk * oldakk * MATRIX(*notnull, i, j) * (1-MATRIX(*notnull, i, j)/MATRIX(*normfact, i, j)); MATRIX(*sd, i, j) = sqrt(MATRIX(*sd, i, j)/(MATRIX(*normfact, i, j)-1)); MATRIX(*sd, j, i) = MATRIX(*sd, i, j); } } } if (!cites) { igraph_matrix_destroy(notnull); IGRAPH_FINALLY_CLEAN(1); } if (!norm) { igraph_matrix_destroy(normfact); IGRAPH_FINALLY_CLEAN(1); } igraph_matrix_destroy(&ch); igraph_matrix_destroy(&ntkk); igraph_vector_long_destroy(&ntk); igraph_vector_char_destroy(&added); igraph_vector_long_destroy(&papers); IGRAPH_FINALLY_CLEAN(5); return 0; }
int igraph_i_eigen_matrix_symmetric_arpack_be(const igraph_matrix_t *A, const igraph_sparsemat_t *sA, igraph_arpack_function_t *fun, int n, void *extra, const igraph_eigen_which_t *which, igraph_arpack_options_t *options, igraph_arpack_storage_t *storage, igraph_vector_t *values, igraph_matrix_t *vectors) { igraph_vector_t tmpvalues, tmpvalues2; igraph_matrix_t tmpvectors, tmpvectors2; igraph_i_eigen_matrix_sym_arpack_data_t myextra = { A, sA }; int low=(int) floor(which->howmany/2.0), high=(int) ceil(which->howmany/2.0); int l1, l2, w; if (low + high >= n) { IGRAPH_ERROR("Requested too many eigenvalues/vectors", IGRAPH_EINVAL); } if (!fun) { fun=igraph_i_eigen_matrix_sym_arpack_cb; extra=(void*) &myextra; } IGRAPH_VECTOR_INIT_FINALLY(&tmpvalues, high); IGRAPH_MATRIX_INIT_FINALLY(&tmpvectors, n, high); IGRAPH_VECTOR_INIT_FINALLY(&tmpvalues2, low); IGRAPH_MATRIX_INIT_FINALLY(&tmpvectors2, n, low); options->n=n; options->nev=high; options->ncv= 2*options->nev < n ? 2*options->nev : n; options->which[0]='L'; options->which[1]='A'; IGRAPH_CHECK(igraph_arpack_rssolve(fun, extra, options, storage, &tmpvalues, &tmpvectors)); options->nev=low; options->ncv= 2*options->nev < n ? 2*options->nev : n; options->which[0]='S'; options->which[1]='A'; IGRAPH_CHECK(igraph_arpack_rssolve(fun, extra, options, storage, &tmpvalues2, &tmpvectors2)); IGRAPH_CHECK(igraph_vector_resize(values, low+high)); IGRAPH_CHECK(igraph_matrix_resize(vectors, n, low+high)); l1=0; l2=0; w=0; while (w < which->howmany) { VECTOR(*values)[w] = VECTOR(tmpvalues)[l1]; memcpy(&MATRIX(*vectors, 0, w), &MATRIX(tmpvectors, 0, l1), (size_t) n * sizeof(igraph_real_t)); w++; l1++; if (w < which->howmany) { VECTOR(*values)[w] = VECTOR(tmpvalues2)[l2]; memcpy(&MATRIX(*vectors, 0, w), &MATRIX(tmpvectors2, 0, l2), (size_t) n * sizeof(igraph_real_t)); w++; l2++; } } igraph_matrix_destroy(&tmpvectors2); igraph_vector_destroy(&tmpvalues2); igraph_matrix_destroy(&tmpvectors); igraph_vector_destroy(&tmpvalues); IGRAPH_FINALLY_CLEAN(4); return 0; }
int igraph_layout_kamada_kawai_3d(const igraph_t *graph, igraph_matrix_t *res, igraph_bool_t use_seed, igraph_integer_t maxiter, igraph_real_t epsilon, igraph_real_t kkconst, const igraph_vector_t *weights, const igraph_vector_t *minx, const igraph_vector_t *maxx, const igraph_vector_t *miny, const igraph_vector_t *maxy, const igraph_vector_t *minz, const igraph_vector_t *maxz) { igraph_integer_t no_nodes=igraph_vcount(graph); igraph_integer_t no_edges=igraph_ecount(graph); igraph_real_t L, L0=sqrt(no_nodes); igraph_matrix_t dij, lij, kij; igraph_real_t max_dij; igraph_vector_t D1, D2, D3; igraph_integer_t i, j, m; if (maxiter < 0) { IGRAPH_ERROR("Number of iterations must be non-negatice in " "Kamada-Kawai layout", IGRAPH_EINVAL); } if (kkconst <= 0) { IGRAPH_ERROR("`K' constant must be positive in Kamada-Kawai layout", IGRAPH_EINVAL); } if (use_seed && (igraph_matrix_nrow(res) != no_nodes || igraph_matrix_ncol(res) != 3)) { IGRAPH_ERROR("Invalid start position matrix size in " "3d Kamada-Kawai layout", IGRAPH_EINVAL); } if (weights && igraph_vector_size(weights) != no_edges) { IGRAPH_ERROR("Invalid weight vector length", IGRAPH_EINVAL); } if (minx && igraph_vector_size(minx) != no_nodes) { IGRAPH_ERROR("Invalid minx vector length", IGRAPH_EINVAL); } if (maxx && igraph_vector_size(maxx) != no_nodes) { IGRAPH_ERROR("Invalid maxx vector length", IGRAPH_EINVAL); } if (minx && maxx && !igraph_vector_all_le(minx, maxx)) { IGRAPH_ERROR("minx must not be greater than maxx", IGRAPH_EINVAL); } if (miny && igraph_vector_size(miny) != no_nodes) { IGRAPH_ERROR("Invalid miny vector length", IGRAPH_EINVAL); } if (maxy && igraph_vector_size(maxy) != no_nodes) { IGRAPH_ERROR("Invalid maxy vector length", IGRAPH_EINVAL); } if (miny && maxy && !igraph_vector_all_le(miny, maxy)) { IGRAPH_ERROR("miny must not be greater than maxy", IGRAPH_EINVAL); } if (minz && igraph_vector_size(minz) != no_nodes) { IGRAPH_ERROR("Invalid minz vector length", IGRAPH_EINVAL); } if (maxz && igraph_vector_size(maxz) != no_nodes) { IGRAPH_ERROR("Invalid maxz vector length", IGRAPH_EINVAL); } if (minz && maxz && !igraph_vector_all_le(minz, maxz)) { IGRAPH_ERROR("minz must not be greater than maxz", IGRAPH_EINVAL); } if (!use_seed) { if (minx || maxx || miny || maxy || minz || maxz) { const igraph_real_t width=sqrt(no_nodes), height=width, depth=width; IGRAPH_CHECK(igraph_matrix_resize(res, no_nodes, 3)); RNG_BEGIN(); for (i=0; i<no_nodes; i++) { igraph_real_t x1=minx ? VECTOR(*minx)[i] : -width/2; igraph_real_t x2=maxx ? VECTOR(*maxx)[i] : width/2; igraph_real_t y1=miny ? VECTOR(*miny)[i] : -height/2; igraph_real_t y2=maxy ? VECTOR(*maxy)[i] : height/2; igraph_real_t z1=minz ? VECTOR(*minz)[i] : -depth/2; igraph_real_t z2=maxz ? VECTOR(*maxz)[i] : depth/2; if (!igraph_finite(x1)) { x1 = -width/2; } if (!igraph_finite(x2)) { x2 = width/2; } if (!igraph_finite(y1)) { y1 = -height/2; } if (!igraph_finite(y2)) { y2 = height/2; } if (!igraph_finite(z1)) { z1 = -depth/2; } if (!igraph_finite(z2)) { z2 = depth/2; } MATRIX(*res, i, 0) = RNG_UNIF(x1, x2); MATRIX(*res, i, 1) = RNG_UNIF(y1, y2); MATRIX(*res, i, 2) = RNG_UNIF(z1, z2); } RNG_END(); } else { igraph_layout_sphere(graph, res); } } if (no_nodes <= 1) { return 0; } IGRAPH_MATRIX_INIT_FINALLY(&dij, no_nodes, no_nodes); IGRAPH_MATRIX_INIT_FINALLY(&kij, no_nodes, no_nodes); IGRAPH_MATRIX_INIT_FINALLY(&lij, no_nodes, no_nodes); IGRAPH_CHECK(igraph_shortest_paths_dijkstra(graph, &dij, igraph_vss_all(), igraph_vss_all(), weights, IGRAPH_ALL)); max_dij = 0.0; for (i=0; i<no_nodes; i++) { for (j=i+1; j<no_nodes; j++) { if (!igraph_finite(MATRIX(dij, i, j))) { continue; } if (MATRIX(dij, i, j) > max_dij) { max_dij = MATRIX(dij, i, j); } } } for (i=0; i<no_nodes; i++) { for (j=0; j<no_nodes; j++) { if (MATRIX(dij, i, j) > max_dij) { MATRIX(dij, i, j) = max_dij; } } } L = L0 / max_dij; for (i=0; i<no_nodes; i++) { for (j=0; j<no_nodes; j++) { igraph_real_t tmp=MATRIX(dij, i, j) * MATRIX(dij, i, j); if (i==j) { continue; } MATRIX(kij, i, j) = kkconst / tmp; MATRIX(lij, i, j) = L * MATRIX(dij, i, j); } } /* Initialize delta */ IGRAPH_VECTOR_INIT_FINALLY(&D1, no_nodes); IGRAPH_VECTOR_INIT_FINALLY(&D2, no_nodes); IGRAPH_VECTOR_INIT_FINALLY(&D3, no_nodes); for (m=0; m<no_nodes; m++) { igraph_real_t myD1=0.0, myD2=0.0, myD3=0.0; for (i=0; i<no_nodes; i++) { if (i==m) { continue; } igraph_real_t dx=MATRIX(*res, m, 0) - MATRIX(*res, i, 0); igraph_real_t dy=MATRIX(*res, m, 1) - MATRIX(*res, i, 1); igraph_real_t dz=MATRIX(*res, m, 2) - MATRIX(*res, i, 2); igraph_real_t mi_dist=sqrt(dx * dx + dy * dy + dz * dz); myD1 += MATRIX(kij, m, i) * (dx - MATRIX(lij, m, i) * dx / mi_dist); myD2 += MATRIX(kij, m, i) * (dy - MATRIX(lij, m, i) * dy / mi_dist); myD3 += MATRIX(kij, m, i) * (dz - MATRIX(lij, m, i) * dz / mi_dist); } VECTOR(D1)[m] = myD1; VECTOR(D2)[m] = myD2; VECTOR(D3)[m] = myD3; } for (j=0; j<maxiter; j++) { igraph_real_t Ax=0.0, Ay=0.0, Az=0.0; igraph_real_t Axx=0.0, Axy=0.0, Axz=0.0, Ayy=0.0, Ayz=0.0, Azz=0.0; igraph_real_t max_delta, delta_x, delta_y, delta_z; igraph_real_t old_x, old_y, old_z, new_x, new_y, new_z; igraph_real_t detnum; /* Select maximal delta */ m=0; max_delta=-1; for (i=0; i<no_nodes; i++) { igraph_real_t delta=(VECTOR(D1)[i] * VECTOR(D1)[i] + VECTOR(D2)[i] * VECTOR(D2)[i] + VECTOR(D3)[i] * VECTOR(D3)[i]); if (delta > max_delta) { m=i; max_delta=delta; } } if (max_delta < epsilon) { break; } old_x=MATRIX(*res, m, 0); old_y=MATRIX(*res, m, 1); old_z=MATRIX(*res, m, 2); /* Calculate D1, D2 and D3, and other coefficients */ for (i=0; i<no_nodes; i++) { if (i==m) { continue; } igraph_real_t dx=old_x - MATRIX(*res, i, 0); igraph_real_t dy=old_y - MATRIX(*res, i, 1); igraph_real_t dz=old_z - MATRIX(*res, i, 2); igraph_real_t dist=sqrt(dx * dx + dy * dy + dz *dz); igraph_real_t den=dist * (dx * dx + dy * dy + dz * dz); igraph_real_t k_mi=MATRIX(kij, m, i); igraph_real_t l_mi=MATRIX(lij, m, i); Axx += k_mi * (1 - l_mi * (dy*dy + dz*dz) / den); Ayy += k_mi * (1 - l_mi * (dx*dx + dz*dz) / den); Azz += k_mi * (1 - l_mi * (dx*dx + dy*dy) / den); Axy += k_mi * l_mi * dx * dy / den; Axz += k_mi * l_mi * dx * dz / den; Ayz += k_mi * l_mi * dy * dz / den; } Ax = -VECTOR(D1)[m]; Ay = -VECTOR(D2)[m]; Az = -VECTOR(D3)[m]; /* Need to solve some linear equations, we just use Cramer's rule */ #define DET(a,b,c,d,e,f,g,h,i) ((a*e*i+b*f*g+c*d*h)-(c*e*g+b*d*i+a*f*h)) detnum = DET(Axx,Axy,Axz, Axy,Ayy,Ayz, Axz,Ayz,Azz); delta_x = DET(Ax ,Ay ,Az , Axy,Ayy,Ayz, Axz,Ayz,Azz) / detnum; delta_y = DET(Axx,Axy,Axz, Ax ,Ay ,Az , Axz,Ayz,Azz) / detnum; delta_z = DET(Axx,Axy,Axz, Axy,Ayy,Ayz, Ax ,Ay ,Az ) / detnum; new_x = old_x + delta_x; new_y = old_y + delta_y; new_z = old_z + delta_z; /* Limits, if given */ if (minx && new_x < VECTOR(*minx)[m]) { new_x = VECTOR(*minx)[m]; } if (maxx && new_x > VECTOR(*maxx)[m]) { new_x = VECTOR(*maxx)[m]; } if (miny && new_y < VECTOR(*miny)[m]) { new_y = VECTOR(*miny)[m]; } if (maxy && new_y > VECTOR(*maxy)[m]) { new_y = VECTOR(*maxy)[m]; } if (minz && new_z < VECTOR(*minz)[m]) { new_z = VECTOR(*minz)[m]; } if (maxz && new_z > VECTOR(*maxz)[m]) { new_z = VECTOR(*maxz)[m]; } /* Update delta, only with/for the affected node */ VECTOR(D1)[m] = VECTOR(D2)[m] = VECTOR(D3)[m] = 0.0; for (i=0; i<no_nodes; i++) { if (i==m) { continue; } igraph_real_t old_dx=old_x - MATRIX(*res, i, 0); igraph_real_t old_dy=old_y - MATRIX(*res, i, 1); igraph_real_t old_dz=old_z - MATRIX(*res, i, 2); igraph_real_t old_mi_dist=sqrt(old_dx * old_dx + old_dy * old_dy + old_dz * old_dz); igraph_real_t new_dx=new_x - MATRIX(*res, i, 0); igraph_real_t new_dy=new_y - MATRIX(*res, i, 1); igraph_real_t new_dz=new_z - MATRIX(*res, i, 2); igraph_real_t new_mi_dist=sqrt(new_dx * new_dx + new_dy * new_dy + new_dz * new_dz); VECTOR(D1)[i] -= MATRIX(kij, m, i) * (-old_dx + MATRIX(lij, m, i) * old_dx / old_mi_dist); VECTOR(D2)[i] -= MATRIX(kij, m, i) * (-old_dy + MATRIX(lij, m, i) * old_dy / old_mi_dist); VECTOR(D3)[i] -= MATRIX(kij, m, i) * (-old_dz + MATRIX(lij, m, i) * old_dz / old_mi_dist); VECTOR(D1)[i] += MATRIX(kij, m, i) * (-new_dx + MATRIX(lij, m, i) * new_dx / new_mi_dist); VECTOR(D2)[i] += MATRIX(kij, m, i) * (-new_dy + MATRIX(lij, m, i) * new_dy / new_mi_dist); VECTOR(D3)[i] += MATRIX(kij, m, i) * (-new_dz + MATRIX(lij, m, i) * new_dz / new_mi_dist); VECTOR(D1)[m] += MATRIX(kij, m, i) * (new_dx - MATRIX(lij, m, i) * new_dx / new_mi_dist); VECTOR(D2)[m] += MATRIX(kij, m, i) * (new_dy - MATRIX(lij, m, i) * new_dy / new_mi_dist); VECTOR(D3)[m] += MATRIX(kij, m, i) * (new_dz - MATRIX(lij, m, i) * new_dz / new_mi_dist); } /* Update coordinates*/ MATRIX(*res, m, 0) = new_x; MATRIX(*res, m, 1) = new_y; MATRIX(*res, m, 2) = new_z; } igraph_vector_destroy(&D3); igraph_vector_destroy(&D2); igraph_vector_destroy(&D1); igraph_matrix_destroy(&lij); igraph_matrix_destroy(&kij); igraph_matrix_destroy(&dij); IGRAPH_FINALLY_CLEAN(6); return 0; }
/* Resize operations */ void Matrix::resize(long int nrow, long int ncol) { SafeCall(igraph_matrix_resize(ptr(), nrow, ncol)); }
int igraph_community_multilevel(const igraph_t *graph, const igraph_vector_t *weights, igraph_vector_t *membership, igraph_matrix_t *memberships, igraph_vector_t *modularity) { igraph_t g; igraph_vector_t w, m, level_membership; igraph_real_t prev_q = -1, q = -1; int i, level = 1; long int vcount = igraph_vcount(graph); /* Make a copy of the original graph, we will do the merges on the copy */ IGRAPH_CHECK(igraph_copy(&g, graph)); IGRAPH_FINALLY(igraph_destroy, &g); if (weights) { IGRAPH_CHECK(igraph_vector_copy(&w, weights)); IGRAPH_FINALLY(igraph_vector_destroy, &w); } else { IGRAPH_VECTOR_INIT_FINALLY(&w, igraph_ecount(&g)); igraph_vector_fill(&w, 1); } IGRAPH_VECTOR_INIT_FINALLY(&m, vcount); IGRAPH_VECTOR_INIT_FINALLY(&level_membership, vcount); if (memberships || membership) { /* Put each vertex in its own community */ for (i = 0; i < vcount; i++) { VECTOR(level_membership)[i] = i; } } if (memberships) { /* Resize the membership matrix to have vcount columns and no rows */ IGRAPH_CHECK(igraph_matrix_resize(memberships, 0, vcount)); } if (modularity) { /* Clear the modularity vector */ igraph_vector_clear(modularity); } while (1) { /* Remember the previous modularity and vertex count, do a single step */ igraph_integer_t step_vcount = igraph_vcount(&g); prev_q = q; IGRAPH_CHECK(igraph_i_community_multilevel_step(&g, &w, &m, &q)); /* Were there any merges? If not, we have to stop the process */ if (igraph_vcount(&g) == step_vcount || q < prev_q) break; if (memberships || membership) { for (i = 0; i < vcount; i++) { /* Readjust the membership vector */ VECTOR(level_membership)[i] = VECTOR(m)[(long int) VECTOR(level_membership)[i]]; } } if (modularity) { /* If we have to return the modularity scores, add it to the modularity vector */ IGRAPH_CHECK(igraph_vector_push_back(modularity, q)); } if (memberships) { /* If we have to return the membership vectors at each level, store the new * membership vector */ IGRAPH_CHECK(igraph_matrix_add_rows(memberships, 1)); IGRAPH_CHECK(igraph_matrix_set_row(memberships, &level_membership, level - 1)); } /* debug("Level: %d Communities: %ld Modularity: %f\n", level, (long int) igraph_vcount(&g), (double) q); */ /* Increase the level counter */ level++; } /* It might happen that there are no merges, so every vertex is in its own community. We still might want the modularity score for that. */ if (modularity && igraph_vector_size(modularity) == 0) { igraph_vector_t tmp; igraph_real_t mod; int i; IGRAPH_VECTOR_INIT_FINALLY(&tmp, vcount); for (i=0; i<vcount; i++) { VECTOR(tmp)[i]=i; } IGRAPH_CHECK(igraph_modularity(graph, &tmp, &mod, weights)); igraph_vector_destroy(&tmp); IGRAPH_FINALLY_CLEAN(1); IGRAPH_CHECK(igraph_vector_resize(modularity, 1)); VECTOR(*modularity)[0]=mod; } /* If we need the final membership vector, copy it to the output */ if (membership) { IGRAPH_CHECK(igraph_vector_resize(membership, vcount)); for (i = 0; i < vcount; i++) { VECTOR(*membership)[i] = VECTOR(level_membership)[i]; } } /* Destroy the copy of the graph */ igraph_destroy(&g); /* Destroy the temporary vectors */ igraph_vector_destroy(&m); igraph_vector_destroy(&w); igraph_vector_destroy(&level_membership); IGRAPH_FINALLY_CLEAN(4); return 0; }
int igraph_lapack_dgeev(const igraph_matrix_t *A, igraph_vector_t *valuesreal, igraph_vector_t *valuesimag, igraph_matrix_t *vectorsleft, igraph_matrix_t *vectorsright, int *info) { char jobvl= vectorsleft ? 'V' : 'N'; char jobvr= vectorsright ? 'V' : 'N'; int n=(int) igraph_matrix_nrow(A); int lda=n, ldvl=n, ldvr=n, lwork=-1; igraph_vector_t work; igraph_vector_t *myreal=valuesreal, *myimag=valuesimag, vreal, vimag; igraph_matrix_t Acopy; int error=*info; if (igraph_matrix_ncol(A) != n) { IGRAPH_ERROR("Cannot calculate eigenvalues (dgeev)", IGRAPH_NONSQUARE); } IGRAPH_CHECK(igraph_matrix_copy(&Acopy, A)); IGRAPH_FINALLY(igraph_matrix_destroy, &Acopy); IGRAPH_VECTOR_INIT_FINALLY(&work, 1); if (!valuesreal) { IGRAPH_VECTOR_INIT_FINALLY(&vreal, n); myreal=&vreal; } else { IGRAPH_CHECK(igraph_vector_resize(myreal, n)); } if (!valuesimag) { IGRAPH_VECTOR_INIT_FINALLY(&vimag, n); myimag=&vimag; } else { IGRAPH_CHECK(igraph_vector_resize(myimag, n)); } if (vectorsleft) { IGRAPH_CHECK(igraph_matrix_resize(vectorsleft, n, n)); } if (vectorsright) { IGRAPH_CHECK(igraph_matrix_resize(vectorsright, n, n)); } igraphdgeev_(&jobvl, &jobvr, &n, &MATRIX(Acopy,0,0), &lda, VECTOR(*myreal), VECTOR(*myimag), vectorsleft ? &MATRIX(*vectorsleft ,0,0) : 0, &ldvl, vectorsright ? &MATRIX(*vectorsright,0,0) : 0, &ldvr, VECTOR(work), &lwork, info); lwork=(int) VECTOR(work)[0]; IGRAPH_CHECK(igraph_vector_resize(&work, lwork)); igraphdgeev_(&jobvl, &jobvr, &n, &MATRIX(Acopy,0,0), &lda, VECTOR(*myreal), VECTOR(*myimag), vectorsleft ? &MATRIX(*vectorsleft ,0,0) : 0, &ldvl, vectorsright ? &MATRIX(*vectorsright,0,0) : 0, &ldvr, VECTOR(work), &lwork, info); if (*info < 0) { IGRAPH_ERROR("Cannot calculate eigenvalues (dgeev)", IGRAPH_ELAPACK); } else if (*info > 0) { if (error) { IGRAPH_ERROR("Cannot calculate eigenvalues (dgeev)", IGRAPH_ELAPACK); } else { IGRAPH_WARNING("Cannot calculate eigenvalues (dgeev)"); } } if (!valuesimag) { igraph_vector_destroy(&vimag); IGRAPH_FINALLY_CLEAN(1); } if (!valuesreal) { igraph_vector_destroy(&vreal); IGRAPH_FINALLY_CLEAN(1); } igraph_vector_destroy(&work); igraph_matrix_destroy(&Acopy); IGRAPH_FINALLY_CLEAN(2); return 0; }
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; }
/** * \ingroup nongraph * \function igraph_convex_hull * \brief Determines the convex hull of a given set of points in the 2D plane * * </para><para> * The convex hull is determined by the Graham scan algorithm. * See the following reference for details: * * </para><para> * Thomas H. Cormen, Charles E. Leiserson, Ronald L. Rivest, and Clifford * Stein. Introduction to Algorithms, Second Edition. MIT Press and * McGraw-Hill, 2001. ISBN 0262032937. Pages 949-955 of section 33.3: * Finding the convex hull. * * \param data vector containing the coordinates. The length of the * vector must be even, since it contains X-Y coordinate pairs. * \param resverts the vector containing the result, e.g. the vector of * vertex indices used as the corners of the convex hull. Supply * \c NULL here if you are only interested in the coordinates of * the convex hull corners. * \param rescoords the matrix containing the coordinates of the selected * corner vertices. Supply \c NULL here if you are only interested in * the vertex indices. * \return Error code: * \c IGRAPH_ENOMEM: not enough memory * * Time complexity: O(n log(n)) where n is the number of vertices * * \example examples/simple/igraph_convex_hull.c */ int igraph_convex_hull(const igraph_matrix_t *data, igraph_vector_t *resverts, igraph_matrix_t *rescoords) { igraph_integer_t no_of_nodes; long int i, pivot_idx=0, last_idx, before_last_idx, next_idx, j; igraph_vector_t angles, stack, order; igraph_real_t px, py, cp; no_of_nodes=(igraph_integer_t) igraph_matrix_nrow(data); if (igraph_matrix_ncol(data) != 2) { IGRAPH_ERROR("matrix must have 2 columns", IGRAPH_EINVAL); } if (no_of_nodes == 0) { if (resverts != 0) { IGRAPH_CHECK(igraph_vector_resize(resverts, 0)); } if (rescoords != 0) { IGRAPH_CHECK(igraph_matrix_resize(rescoords, 0, 2)); } /**************************** this is an exit here *********/ return 0; } IGRAPH_VECTOR_INIT_FINALLY(&angles, no_of_nodes); IGRAPH_VECTOR_INIT_FINALLY(&stack, 0); /* Search for the pivot vertex */ for (i=1; i<no_of_nodes; i++) { if (MATRIX(*data, i, 1)<MATRIX(*data, pivot_idx, 1)) pivot_idx=i; else if (MATRIX(*data, i, 1) == MATRIX(*data, pivot_idx, 1) && MATRIX(*data, i, 0) < MATRIX(*data, pivot_idx, 0)) pivot_idx=i; } px=MATRIX(*data, pivot_idx, 0); py=MATRIX(*data, pivot_idx, 1); /* Create angle array */ for (i=0; i<no_of_nodes; i++) { if (i == pivot_idx) { /* We can't calculate the angle of the pivot point with itself, * so we use 10 here. This way, after sorting the angle vector, * the pivot point will always be the first one, since the range * of atan2 is -3.14..3.14 */ VECTOR(angles)[i] = 10; } else { VECTOR(angles)[i] = atan2(MATRIX(*data, i, 1)-py, MATRIX(*data, i, 0)-px); } } /* Sort points by angles */ IGRAPH_VECTOR_INIT_FINALLY(&order, no_of_nodes); IGRAPH_CHECK(igraph_vector_qsort_ind(&angles, &order, 0)); /* Check if two points have the same angle. If so, keep only the point that * is farthest from the pivot */ j = 0; last_idx = (long int) VECTOR(order)[0]; pivot_idx = (long int) VECTOR(order)[no_of_nodes - 1]; for (i=1; i < no_of_nodes; i++) { next_idx = (long int) VECTOR(order)[i]; if (VECTOR(angles)[last_idx] == VECTOR(angles)[next_idx]) { /* Keep the vertex that is farther from the pivot, drop the one that is * closer */ px = pow(MATRIX(*data, last_idx, 0) - MATRIX(*data, pivot_idx, 0), 2) + pow(MATRIX(*data, last_idx, 1) - MATRIX(*data, pivot_idx, 1), 2); py = pow(MATRIX(*data, next_idx, 0) - MATRIX(*data, pivot_idx, 0), 2) + pow(MATRIX(*data, next_idx, 1) - MATRIX(*data, pivot_idx, 1), 2); if (px > py) { VECTOR(order)[i] = -1; } else { VECTOR(order)[j] = -1; last_idx = next_idx; j = i; } } else { last_idx = next_idx; j = i; } } j=0; last_idx=-1; before_last_idx=-1; while (!igraph_vector_empty(&order)) { next_idx=(long int)VECTOR(order)[igraph_vector_size(&order) - 1]; if (next_idx < 0) { /* This vertex should be skipped; was excluded in an earlier step */ igraph_vector_pop_back(&order); continue; } /* Determine whether we are at a left or right turn */ if (j < 2) { /* Pretend that we are turning into the right direction if we have less * than two items in the stack */ cp=-1; } else { cp=(MATRIX(*data, last_idx, 0)-MATRIX(*data, before_last_idx, 0))* (MATRIX(*data, next_idx, 1)-MATRIX(*data, before_last_idx, 1))- (MATRIX(*data, next_idx, 0)-MATRIX(*data, before_last_idx, 0))* (MATRIX(*data, last_idx, 1)-MATRIX(*data, before_last_idx, 1)); } /* printf("B L N cp: %ld, %ld, %ld, %f [", before_last_idx, last_idx, next_idx, (float)cp); for (int k=0; k<j; k++) printf("%ld ", (long)VECTOR(stack)[k]); printf("]\n"); */ if (cp < 0) { /* We are turning into the right direction */ igraph_vector_pop_back(&order); IGRAPH_CHECK(igraph_vector_push_back(&stack, next_idx)); before_last_idx = last_idx; last_idx = next_idx; j++; } else { /* No, skip back and try again in the next iteration */ igraph_vector_pop_back(&stack); j--; last_idx = before_last_idx; before_last_idx = (j >= 2) ? (long int) VECTOR(stack)[j-2] : -1; } } /* Create result vector */ if (resverts != 0) { igraph_vector_clear(resverts); IGRAPH_CHECK(igraph_vector_append(resverts, &stack)); } if (rescoords != 0) { igraph_matrix_select_rows(data, rescoords, &stack); } /* Free everything */ igraph_vector_destroy(&order); igraph_vector_destroy(&stack); igraph_vector_destroy(&angles); IGRAPH_FINALLY_CLEAN(3); return 0; }
int igraph_layout_i_grid_fr(const igraph_t *graph, igraph_matrix_t *res, igraph_bool_t use_seed, igraph_integer_t niter, igraph_real_t start_temp, const igraph_vector_t *weight, const igraph_vector_t *minx, const igraph_vector_t *maxx, const igraph_vector_t *miny, const igraph_vector_t *maxy) { igraph_integer_t no_nodes=igraph_vcount(graph); igraph_integer_t no_edges=igraph_ecount(graph); float width=sqrtf(no_nodes), height=width; igraph_2dgrid_t grid; igraph_vector_float_t dispx, dispy; igraph_real_t temp=start_temp; igraph_real_t difftemp=start_temp / niter; igraph_2dgrid_iterator_t vidit; igraph_integer_t i; const float cellsize=2.0; RNG_BEGIN(); if (!use_seed) { IGRAPH_CHECK(igraph_matrix_resize(res, no_nodes, 2)); for (i=0; i<no_nodes; i++) { igraph_real_t x1=minx ? VECTOR(*minx)[i] : -width/2; igraph_real_t x2=maxx ? VECTOR(*maxx)[i] : width/2; igraph_real_t y1=miny ? VECTOR(*miny)[i] : -height/2; igraph_real_t y2=maxy ? VECTOR(*maxy)[i] : height/2; if (!igraph_finite(x1)) { x1 = -sqrt(no_nodes)/2; } if (!igraph_finite(x2)) { x2 = sqrt(no_nodes)/2; } if (!igraph_finite(y1)) { y1 = -sqrt(no_nodes)/2; } if (!igraph_finite(y2)) { y2 = sqrt(no_nodes)/2; } MATRIX(*res, i, 0) = RNG_UNIF(x1, x2); MATRIX(*res, i, 1) = RNG_UNIF(y1, y2); } } /* make grid */ IGRAPH_CHECK(igraph_2dgrid_init(&grid, res, -width/2, width/2, cellsize, -height/2, height/2, cellsize)); IGRAPH_FINALLY(igraph_2dgrid_destroy, &grid); /* place vertices on grid */ for (i=0; i<no_nodes; i++) { igraph_2dgrid_add2(&grid, i); } IGRAPH_CHECK(igraph_vector_float_init(&dispx, no_nodes)); IGRAPH_FINALLY(igraph_vector_float_destroy, &dispx); IGRAPH_CHECK(igraph_vector_float_init(&dispy, no_nodes)); IGRAPH_FINALLY(igraph_vector_float_destroy, &dispy); for (i=0; i<niter; i++) { igraph_integer_t v, u, e; igraph_vector_float_null(&dispx); igraph_vector_float_null(&dispy); /* repulsion */ igraph_2dgrid_reset(&grid, &vidit); while ( (v=igraph_2dgrid_next(&grid, &vidit)-1) != -1) { while ( (u=igraph_2dgrid_next_nei(&grid, &vidit)-1) != -1) { float dx=MATRIX(*res, v, 0)-MATRIX(*res, u, 0); float dy=MATRIX(*res, v, 1)-MATRIX(*res, u, 1); float dlen=dx * dx + dy * dy; if (dlen < cellsize * cellsize) { VECTOR(dispx)[v] += dx/dlen; VECTOR(dispy)[v] += dy/dlen; VECTOR(dispx)[u] -= dx/dlen; VECTOR(dispy)[u] -= dy/dlen; } } } /* attraction */ for (e=0; e<no_edges; e++) { igraph_integer_t v=IGRAPH_FROM(graph, e); igraph_integer_t u=IGRAPH_TO(graph, e); igraph_real_t dx=MATRIX(*res, v, 0) - MATRIX(*res, u, 0); igraph_real_t dy=MATRIX(*res, v, 1) - MATRIX(*res, u, 1); igraph_real_t w=weight ? VECTOR(*weight)[e] : 1.0; igraph_real_t dlen=sqrt(dx * dx + dy * dy) * w; VECTOR(dispx)[v] -= (dx * dlen); VECTOR(dispy)[v] -= (dy * dlen); VECTOR(dispx)[u] += (dx * dlen); VECTOR(dispy)[u] += (dy * dlen); } /* update */ for (v=0; v<no_nodes; v++) { igraph_real_t dx=VECTOR(dispx)[v] + RNG_UNIF01() * 1e-9; igraph_real_t dy=VECTOR(dispy)[v] + RNG_UNIF01() * 1e-9; igraph_real_t displen=sqrt(dx * dx + dy * dy); igraph_real_t mx=fabs(dx) < temp ? dx : temp; igraph_real_t my=fabs(dy) < temp ? dy : temp; if (displen > 0) { MATRIX(*res, v, 0) += (dx / displen) * mx; MATRIX(*res, v, 1) += (dy / displen) * my; } if (minx && MATRIX(*res, v, 0) < VECTOR(*minx)[v]) { MATRIX(*res, v, 0) = VECTOR(*minx)[v]; } if (maxx && MATRIX(*res, v, 0) > VECTOR(*maxx)[v]) { MATRIX(*res, v, 0) = VECTOR(*maxx)[v]; } if (miny && MATRIX(*res, v, 1) < VECTOR(*miny)[v]) { MATRIX(*res, v, 1) = VECTOR(*miny)[v]; } if (maxy && MATRIX(*res, v, 1) > VECTOR(*maxy)[v]) { MATRIX(*res, v, 1) = VECTOR(*maxy)[v]; } } temp -= difftemp; } igraph_vector_float_destroy(&dispx); igraph_vector_float_destroy(&dispy); igraph_2dgrid_destroy(&grid); IGRAPH_FINALLY_CLEAN(3); return 0; }